From 0fe96a7d4bc39f95d1e95054a6fdff92a2389f8a Mon Sep 17 00:00:00 2001 From: Timotej Ecimovic Date: Wed, 13 Jul 2022 13:57:58 -0400 Subject: [PATCH] Clean up server-mode for concurrent use (#598) * Share the ipc socket same way as single-instance shares sockets. * Some code cleanup. * Increase feature level to trigger IDE tests. * Make server load both zigbee and matter data. * Fix the hang of the generation in the client/server case. --- apack.json | 2 +- package.json | 2 +- src-electron/main-process/main.ts | 14 +++---- src-electron/main-process/startup.js | 60 ++++++++++++---------------- src-electron/server/ipc-server.ts | 7 +++- src-electron/ui/main-ui.ts | 21 +++++----- 6 files changed, 50 insertions(+), 56 deletions(-) diff --git a/apack.json b/apack.json index 639875be10..7f9a9747f6 100644 --- a/apack.json +++ b/apack.json @@ -4,7 +4,7 @@ "description": "Graphical configuration tool for application and libraries based on Zigbee Cluster Library.", "path": [".", "node_modules/.bin/", "ZAP.app/Contents/MacOS"], "requiredFeatureLevel": "apack.core:9", - "featureLevel": 75, + "featureLevel": 76, "uc.triggerExtension": "zap", "executable": { "zap:win32.x86_64": { diff --git a/package.json b/package.json index 6f2ef0cacd..1788fd7bb9 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "zaphelp": "node src-script/zap-start.js --help", "zap-dotdot": "node src-script/zap-start.js --logToStdout --zcl ./zcl-builtin/dotdot/library.xml", "zap-devserver": "node src-script/zap-start.js server --allowCors --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", - "server": "node src-script/zap-start.js server --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", + "server": "node src-script/zap-start.js server --logToStdout --zcl ./zcl-builtin/silabs/zcl.json --zcl ./zcl-builtin/matter/zcl.json --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", "stop": "node src-script/zap-start.js stop --reuseZapInstance", "status": "node src-script/zap-start.js status --reuseZapInstance", "self-check": "node src-script/zap-start.js selfCheck -g ./test/gen-template/zigbee/gen-templates.json", diff --git a/src-electron/main-process/main.ts b/src-electron/main-process/main.ts index a8da168ff1..22b0eb9bd7 100644 --- a/src-electron/main-process/main.ts +++ b/src-electron/main-process/main.ts @@ -27,20 +27,16 @@ env.versionsCheck() env.setProductionEnv() let argv = args.processCommandLineArguments(process.argv) - util.mainOrSecondaryInstance( argv.reuseZapInstance, () => { - startup.startUpMainInstance( - { - quitFunction: null, - uiEnableFunction: null, - }, - argv - ) + startup.startUpMainInstance(argv, { + quitFunction: () => process.exit(0), + uiEnableFunction: null, + }) }, () => { - startup.startUpSecondaryInstance(null, argv) + startup.startUpSecondaryInstance(argv, { quitFunction: null }) } ) diff --git a/src-electron/main-process/startup.js b/src-electron/main-process/startup.js index 92688b61aa..23d4123c87 100644 --- a/src-electron/main-process/startup.js +++ b/src-electron/main-process/startup.js @@ -323,35 +323,28 @@ async function startServer(argv, quitFunction) { } }) mainDatabase = db - - await zclLoader.loadZclMetafiles(db, argv.zclProperties) - return generatorEngine - .loadTemplates(db, argv.generationTemplate) - .then((ctx) => { - if (ctx.error) { - env.logWarning(ctx.error) + try { + await zclLoader.loadZclMetafiles(db, argv.zclProperties) + let ctx = await generatorEngine.loadTemplates(db, argv.generationTemplate) + if (ctx.error) { + env.logWarning(ctx.error) + } + await httpServer.initHttpServer( + ctx.db, + argv.httpPort, + argv.studioHttpPort, + { + zcl: argv.zclProperties, + template: argv.generationTemplate, + allowCors: argv.allowCors, } - return ctx - }) - .then((ctx) => { - return httpServer - .initHttpServer(ctx.db, argv.httpPort, argv.studioHttpPort, { - zcl: argv.zclProperties, - template: argv.generationTemplate, - allowCors: argv.allowCors, - }) - .then(() => { - ipcServer.initServer(ctx.db, argv.httpPort) - }) - .then(() => ctx) - }) - .then((ctx) => { - logRemoteData(httpServer.httpServerStartupMessage()) - }) - .catch((err) => { - env.logError(err) - throw err - }) + ) + await ipcServer.initServer(ctx.db, argv.httpPort) + logRemoteData(httpServer.httpServerStartupMessage()) + } catch (err) { + env.logError(err) + throw err + } } /** @@ -554,12 +547,12 @@ function logRemoteData(data) { * * @param {*} argv */ -function startUpSecondaryInstance(quitFunction, argv) { +function startUpSecondaryInstance(argv, callbacks) { console.log('🧐 Existing instance of zap will service this request.') ipcClient.initAndConnectClient().then(() => { ipcClient.on(ipcServer.eventType.overAndOut, (data) => { logRemoteData(data) - if (quitFunction != null) quitFunction() + if (callbacks.quitFunction != null) callbacks.quitFunction() else process.exit(0) }) @@ -598,7 +591,7 @@ function quit() { * @param {*} quitFunction * @param {*} argv */ -async function startUpMainInstance(callbacks, argv) { +async function startUpMainInstance(argv, callbacks) { let quitFunction = callbacks.quitFunction let uiFunction = callbacks.uiEnableFunction if (quitFunction != null) { @@ -671,7 +664,7 @@ async function startUpMainInstance(callbacks, argv) { }) } else { // If we run with node only, we force no UI as it won't work. - if (quitFunction == null) { + if (uiEnableFunction == null) { argv.noUi = true argv.showUrl = true argv.standalone = false @@ -681,11 +674,10 @@ async function startUpMainInstance(callbacks, argv) { let uiEnabled = !argv.noUi let zapFiles = argv.zapFiles let port = await startNormal(quitFunction, argv) - let showUrl = argv.showUrl if (uiEnabled && uiFunction != null) { uiFunction(port, zapFiles, argv.uiMode, argv.standalone) } else { - if (showUrl) { + if (argv.showUrl) { // NOTE: this is parsed/used by Studio as the default landing page. logRemoteData(httpServer.httpServerStartupMessage()) } diff --git a/src-electron/server/ipc-server.ts b/src-electron/server/ipc-server.ts index a65aa10a48..105ef149e1 100644 --- a/src-electron/server/ipc-server.ts +++ b/src-electron/server/ipc-server.ts @@ -20,6 +20,7 @@ import ipc from 'node-ipc' import * as env from '../util/env' import * as ipcTypes from '../../src-shared/types/ipc-types' const path = require('path') +const os = require('os') const util = require('../util/util.js') const watchdog = require('../main-process/watchdog') const httpServer = require('../server/http-server.js') @@ -47,7 +48,11 @@ const server: ipcTypes.Server = { * Returns the socket path for the IPC. */ function socketPath() { - return path.join(env.appDirectory(), 'main.ipc') + var defaultSocketPath = + process.platform == 'win32' + ? '\\\\.\\pipe\\' + 'zap-ipc' + '-sock' + : path.join(os.tmpdir(), 'zap-ipc' + '.sock') + return defaultSocketPath } function log(msg: string) { diff --git a/src-electron/ui/main-ui.ts b/src-electron/ui/main-ui.ts index 4d24bb10e1..3bd8f58410 100644 --- a/src-electron/ui/main-ui.ts +++ b/src-electron/ui/main-ui.ts @@ -15,11 +15,11 @@ * limitations under the License. */ -const { app } = require('electron') - // enable stack trace to be mapped back to the correct line number in TypeScript source files. require('source-map-support').install() +const { app } = require('electron') + import * as args from '../util/args' const env = require('../util/env') const windowJs = require('./window') @@ -31,7 +31,11 @@ env.versionsCheck() env.setProductionEnv() function hookSecondInstanceEvents(argv: args.Arguments) { - app.whenReady().then(() => startup.startUpSecondaryInstance(app.quit, argv)) + app + .whenReady() + .then(() => + startup.startUpSecondaryInstance(argv, { quitFunction: app.quit }) + ) } /** @@ -41,13 +45,10 @@ function hookMainInstanceEvents(argv: args.Arguments) { app .whenReady() .then(() => - startup.startUpMainInstance( - { - quitFunction: app.quit, - uiEnableFunction: uiUtil.enableUi, - }, - argv - ) + startup.startUpMainInstance(argv, { + quitFunction: app.quit, + uiEnableFunction: uiUtil.enableUi, + }) ) .catch((err) => { console.log(err)