<|start_filename|>public/preload.js<|end_filename|>
const electron = require('electron');
const {
  shell,
  ipcRenderer,
  remote: { nativeTheme },
} = electron;
const {
  hotelConfig,
  hotelPort,
  hotelHost,
  hotelUrl,
  hotelTld,
} = require('./hotel-config');

if (process.platform === 'darwin') {
  const setTheme = () => {
    const theme = nativeTheme.shouldUseDarkColors ? 'dark' : 'light';
    window.localStorage.osTheme = theme;
    if ('__setTheme' in window) {
      window.__setTheme();
    }
  };
  nativeTheme.addListener('updated', setTheme);

  setTheme();
}

window.shell = shell;
window.ipcRenderer = ipcRenderer;

// Attach electron shell, ipcRenderer, and hotelPort to window object
window.hotelConfig = hotelConfig;
window.hotelPort = hotelPort;
window.hotelHost = hotelHost;
window.hotelUrl = hotelUrl;
window.hotelTld = hotelTld;


<|start_filename|>public/electron.js<|end_filename|>
const electron = require('electron');
const { app, BrowserWindow, ipcMain, Tray, Menu } = electron;
const path = require('path');
const url = require('url');
const positioner = require('electron-traywindow-positioner');
var EventSource = require('eventsource');
const { hotelUrl } = require('./hotel-config');
const { autoUpdater } = require('electron-updater');

autoUpdater.checkForUpdatesAndNotify();

const assetsDirectory = path.join(__dirname, './assets');

const output = new EventSource(`${hotelUrl}/_/events/output`);
output.addEventListener('message', (event) => {
  logsWindow.webContents.send('output', JSON.parse(event.data));
  window.webContents.send('output', JSON.parse(event.data));
});

const events = new EventSource(`${hotelUrl}/_/events`);
events.addEventListener('message', (event) => {
  logsWindow.webContents.send('events', JSON.parse(event.data));
  window.webContents.send('events', JSON.parse(event.data));
});

let tray;
let window;
let logsWindow;
let closingApp = false;
// workaround for Windows, where blur event occurs when clicking on a tray icon
let blurredRecently = false;
let activeLogsWindowServer = null;

if (process.platform === 'darwin') {
  app.dock.hide();
} else {
  Menu.setApplicationMenu(null);
}

app.on('ready', () => {
  createTray();
  createWindow();
  createLogWindow();
});

app.on('window-all-closed', () => {
  app.quit();
});

const createTray = () => {
  if (process.platform === 'darwin') {
    tray = new Tray(path.join(assetsDirectory, 'hotelTemplate.png'));
  } else {
    tray = new Tray(path.join(assetsDirectory, 'hotelTemplate_white.png'));
  }
  tray.on('right-click', toggleWindow);
  tray.on('click', function (event) {
    toggleWindow();

    if (event.shiftKey) {
      if (window.isVisible()) {
        window.openDevTools({ mode: 'detach' });
      }
      if (logsWindow.isVisible()) {
        logsWindow.openDevTools({ mode: 'detach' });
      }
    }
  });
};

const startUrl =
  process.env.ELECTRON_START_URL ||
  url.format({
    pathname: path.join(__dirname, './index.html'),
    protocol: 'file:',
    slashes: true,
  });

const createWindow = () => {
  window = new BrowserWindow({
    width: 300,
    height: 450,
    show: false,
    frame: false,
    fullscreenable: false,
    resizable: true,
    transparent: true,
    webPreferences: {
      backgroundThrottling: false,
      enableRemoteModule: true,
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  window.on('page-title-updated', (evt) => {
    evt.preventDefault();
  });
  window.loadURL(startUrl);

  window.on('blur', () => {
    blurredRecently = true;
    setTimeout(() => (blurredRecently = false), 100);
    if (!window.webContents.isDevToolsOpened()) {
      window.hide();
    }
  });
  window.on('close', (e) => {
    closingApp = true;
    logsWindow.close();
  });
};

const createLogWindow = () => {
  logsWindow = new BrowserWindow({
    width: 800,
    height: 600,
    show: false,
    resizable: true,
    frame: true,
    webPreferences: {
      backgroundThrottling: false,
      enableRemoteModule: true,
      preload: path.join(__dirname, 'preload.js'),
    },
  });

  logsWindow.on('page-title-updated', (evt) => {
    evt.preventDefault();
  });
  logsWindow.loadURL(startUrl);
  logsWindow.on('close', (e) => {
    if (!closingApp) {
      e.preventDefault();
      if (process.platform === 'darwin') {
        app.dock.hide();
      }
      logsWindow.hide();
    }
  });
};

const toggleWindow = () => {
  if (window.isVisible() || blurredRecently) {
    window.hide();
  } else {
    showWindow();
  }
};

const showWindow = () => {
  positioner.position(window, tray.getBounds());
  window.show();
  window.focus();
};

ipcMain.on('showDock', (_event, serverId) => {
  if (serverId === activeLogsWindowServer && logsWindow.isVisible()) {
    logsWindow.hide();
    if (process.platform === 'darwin') {
      app.dock.hide();
    }
  } else {
    activeLogsWindowServer = serverId;
    logsWindow.setTitle(`Hotelier - Logs of ${serverId}`);
    logsWindow.webContents.executeJavaScript(
      `location.href = "#/logs/${serverId}"`
    );
    if (!logsWindow.isVisible()) {
      logsWindow.show();
      if (process.platform === 'darwin') {
        app.dock.show();
      }
    } else {
      logsWindow.focus();
    }
  }
});


<|start_filename|>public/hotel-config.js<|end_filename|>
const fs = require('fs');
const path = require('path');
const homedir = require('os').homedir();

// Read Hotel config and store port number
const hotelConfigPath = path.join(homedir, '.hotel', 'conf.json');
const hotelConfig = JSON.parse(fs.readFileSync(hotelConfigPath));
const hotelPort = hotelConfig.port || 2000;
const hotelTld = hotelConfig.tld || 'localhost';
const prefix = 'http://';
let hotelHost = hotelConfig.host || 'localhost';
if (hotelHost.substr(0, prefix.length) !== prefix) {
  hotelHost = prefix + hotelHost;
}
const hotelUrl = `${hotelHost}:${hotelPort}`;

module.exports = { hotelConfig, hotelPort, hotelHost, hotelUrl, hotelTld };


<|start_filename|>tslint.json<|end_filename|>
{
  "extends": [
      "tslint:latest", "tslint-react"
  ],
  "rules": {
      "whitespace": [true, "check-module"],
      "member-access": [true, "no-public"],
      "no-console": false,
      "interface-name": false,
      "object-literal-sort-keys": false,
      "no-object-literal-type-assertion": false,
      "no-empty-interface": false,
      "no-submodule-imports": false,
      "no-implicit-dependencies": false,
      "quotemark": [true, "single", "avoid-escape", "avoid-template", "jsx-double"],
      "arrow-parens": false,
      "max-line-length": [true, 140],
      "jsx-no-multiline-js": false,
      "jsx-no-lambda": false
  }
}
