'use strict'; var electron = require('electron'); var app = electron.app; // Module to control application life. var BrowserWindow = electron.BrowserWindow; var Menu = require('menu'); var Tray = require('tray'); var shell = require('shell'); var os = require('os'); var childProcess = require('child_process'); var path = require('path'); var fs = require('fs'); var Tail = require('always-tail'); var http = require('http'); var path = require('path'); var hfprocess = require('./modules/hf-process.js'); var Process = hfprocess.Process; var ACMonitorProcess = hfprocess.ACMonitorProcess; var ProcessStates = hfprocess.ProcessStates; var ProcessGroup = hfprocess.ProcessGroup; var ProcessGroupStates = hfprocess.ProcessGroupStates; function getApplicationDataDirectory() { var osType = os.type(); var rootDirectory; if (osType == 'Windows_NT') { rootDirectory = process.env.APPDATA; } else if (osType == 'Darwin') { rootDirecotry = process.env.HOME + 'Library/Application Support'; } else { rootDirectory = '/usr/local/share'; } return path.join(rootDirectory, '/High Fidelity/Console'); } const ipcMain = electron.ipcMain; const osType = os.type(); var isShuttingDown = false; function shutdown() { if (!isShuttingDown) { isShuttingDown = true; logWindow.close(); homeServer.stop(); var timeoutID = setTimeout(app.quit, 5000); homeServer.on('state-update', function(processGroup) { if (processGroup.state == ProcessGroupStates.STOPPED) { clearTimeout(timeoutID); app.quit(); } }); updateTrayMenu(null); } } var logPath = path.join(getApplicationDataDirectory(), '/logs'); console.log("Log directory:", logPath); const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME); const APP_ICON = path.join(__dirname, '../resources/console.png'); // print out uncaught exceptions in the console process.on('uncaughtException', function(err) { console.error(err); console.error(err.stack); }); var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { // Someone tried to run a second instance, focus the window (if there is one) return true; }); if (shouldQuit) { app.quit(); return; } // Check command line arguments to see how to find binaries var argv = require('yargs').argv; var pathFinder = require('./modules/path-finder.js'); var interfacePath = null; var dsPath = null; var acPath = null; var debug = argv.debug; if (argv.localDebugBuilds || argv.localReleaseBuilds) { interfacePath = pathFinder.discoveredPath("Interface", argv.localReleaseBuilds); dsPath = pathFinder.discoveredPath("domain-server", argv.localReleaseBuilds); acPath = pathFinder.discoveredPath("assignment-client", argv.localReleaseBuilds); } // if at this point any of the paths are null, we're missing something we wanted to find // TODO: show an error for the binaries that couldn't be found function openFileBrowser(path) { // Add quotes around path path = '"' + path + '"'; if (osType == "Windows_NT") { console.log('start "" ' + path); childProcess.exec('start "" ' + path); } else if (osType == "Darwin") { childProcess.exec('open ' + path); } else if (osType == "Linux") { childProcess.exec('xdg-open ' + path); } } app.on('window-all-closed', function() { }); function startInterface(url) { var argArray = []; // check if we have a url parameter to include if (url) { argArray = ["--url", url]; } // create a new Interface instance - Interface makes sure only one is running at a time var pInterface = new Process('interface', interfacePath, argArray); pInterface.start(); } var tray = null; global.homeServer = null; global.domainServer = null; global.acMonitor = null; const GO_HOME_INDEX = 0; const SERVER_LABEL_INDEX = 2; const RESTART_INDEX = 3; const STOP_INDEX = 4; const SETTINGS_INDEX = 5; function buildMenuArray(serverState) { var menuArray = [ { label: 'Go Home', click: function() { startInterface('hifi://localhost'); }, enabled: false }, { type: 'separator' }, { label: "Server - Stopped", enabled: false }, { label: "Start", click: function() { homeServer.restart(); } }, { label: "Stop", visible: false, click: function() { homeServer.stop(); } }, { label: "Settings", click: function() { shell.openExternal('http://localhost:40100/settings'); }, enabled: false }, { label: "View Logs", click: function() { openFileBrowser(logPath); } }, { type: 'separator' }, { label: 'Quit', accelerator: 'Command+Q', click: function() { app.quit(); } } function buildMenuArray(serverState) { var menuArray = null; if (isShuttingDown) { menuArray = [ { label: "Shutting down...", enabled: false } ]; } else { menuArray = [ { label: 'Go Home', click: function() { startInterface('hifi://localhost'); }, enabled: false }, { type: 'separator' }, { label: "Server - Stopped", enabled: false }, { label: "Start", click: function() { homeServer.restart(); } }, { label: "Stop", visible: false, click: function() { homeServer.stop(); } }, { label: "Settings", click: function() { shell.openExternal('http://localhost:40100/settings'); }, enabled: false }, { label: "View Logs", click: function() { logWindow.open(); } }, { label: "Open Log Directory", click: function() { openFileBrowser(logPath); } }, { type: 'separator' }, { label: 'Quit', accelerator: 'Command+Q', click: function() { shutdown(); } } ]; updateMenuArray(menuArray, serverState); } return menuArray; } function updateMenuArray(menuArray, serverState) { // update the tray menu state var running = serverState == ProcessGroupStates.STARTED; var serverLabelItem = menuArray[SERVER_LABEL_INDEX]; var restartItem = menuArray[RESTART_INDEX]; // Go Home is only enabled if running menuArray[GO_HOME_INDEX].enabled = running; // Stop is only visible if running menuArray[STOP_INDEX].visible = running; // Settings is only visible if running menuArray[SETTINGS_INDEX].enabled = running; if (serverState == ProcessGroupStates.STARTED) { serverLabelItem.label = "Server - Started"; restartItem.label = "Restart"; } else if (serverState == ProcessGroupStates.STOPPED) { serverLabelItem.label = "Server - Stopped"; restartItem.label = "Start"; } else if (serverState == ProcessGroupStates.STOPPING) { serverLabelItem.label = "Server - Stopping"; restartItem.label = "Restart"; restartItem.enabled = false; } } function updateTrayMenu(serverState) { if (tray) { var menuArray = buildMenuArray(serverState); tray.setContextMenu(Menu.buildFromTemplate(menuArray)); if (isShuttingDown) { tray.setToolTip('High Fidelity - Shutting Down'); } } } const httpStatusPort = 60332; // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { if (app.dock) { // hide the dock icon on OS X app.dock.hide() } // Create tray icon tray = new Tray(TRAY_ICON); tray.setToolTip('High Fidelity'); updateTrayMenu(ProcessGroupStates.STOPPED); if (interfacePath && dsPath && acPath) { domainServer = new Process('domain-server', dsPath, [], logPath); acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n4', '--log-directory', logPath, '--http-status-port', httpStatusPort], httpStatusPort, logPath); homeServer = new ProcessGroup('home', [domainServer, acMonitor]); logWindow = new LogWindow(acMonitor, domainServer); // make sure we stop child processes on app quit app.on('quit', function(){ homeServer.stop(); }); var processes = { home: homeServer }; // handle process updates homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); // start the home server homeServer.start(); } });