From 31726315c3936c375d0de14db4babde4a579be14 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Tue, 21 Nov 2023 18:51:38 +0800 Subject: [PATCH] Improvements (#124) * Improvements * Add inspect to dev:backend * Skip debug log at the beginning --- backend/log.ts | 4 ++ .../socket-handlers/docker-socket-handler.ts | 2 +- backend/stack.ts | 53 ++++++++------ backend/terminal.ts | 70 ++++++++++++------- package.json | 2 +- 5 files changed, 82 insertions(+), 49 deletions(-) diff --git a/backend/log.ts b/backend/log.ts index 37f2d4a..3cfac64 100644 --- a/backend/log.ts +++ b/backend/log.ts @@ -103,6 +103,10 @@ class Logger { * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized. */ log(module: string, msg: unknown, level: string) { + if (level === "DEBUG" && !isDev) { + return; + } + if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) { return; } diff --git a/backend/socket-handlers/docker-socket-handler.ts b/backend/socket-handlers/docker-socket-handler.ts index 252d85b..3683114 100644 --- a/backend/socket-handlers/docker-socket-handler.ts +++ b/backend/socket-handlers/docker-socket-handler.ts @@ -217,7 +217,7 @@ export class DockerSocketHandler extends SocketHandler { throw new ValidationError("Stack name must be a string"); } - const stack = Stack.getStack(server, stackName); + const stack = Stack.getStack(server, stackName, true); const serviceStatusList = Object.fromEntries(await stack.getServiceStatusList()); callback({ ok: true, diff --git a/backend/stack.ts b/backend/stack.ts index 5674428..e2873da 100644 --- a/backend/stack.ts +++ b/backend/stack.ts @@ -31,17 +31,19 @@ export class Stack { protected static managedStackList: Map = new Map(); - constructor(server : DockgeServer, name : string, composeYAML? : string) { + constructor(server : DockgeServer, name : string, composeYAML? : string, skipFSOperations = false) { this.name = name; this.server = server; this._composeYAML = composeYAML; - // Check if compose file name is different from compose.yaml - const supportedFileNames = [ "compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml" ]; - for (const filename of supportedFileNames) { - if (fs.existsSync(path.join(this.path, filename))) { - this._composeFileName = filename; - break; + if (!skipFSOperations) { + // Check if compose file name is different from compose.yaml + const supportedFileNames = [ "compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml" ]; + for (const filename of supportedFileNames) { + if (fs.existsSync(path.join(this.path, filename))) { + this._composeFileName = filename; + break; + } } } } @@ -281,23 +283,34 @@ export class Stack { } } - static getStack(server: DockgeServer, stackName: string) : Stack { + static getStack(server: DockgeServer, stackName: string, skipFSOperations = false) : Stack { let dir = path.join(server.stacksDir, stackName); - if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { - // Maybe it is a stack managed by docker compose directly - let stackList = this.getStackList(server); - let stack = stackList.get(stackName); + if (!skipFSOperations) { + if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { + // Maybe it is a stack managed by docker compose directly + let stackList = this.getStackList(server, true); + let stack = stackList.get(stackName); - if (stack) { - return stack; - } else { - // Really not found - throw new ValidationError("Stack not found"); + if (stack) { + return stack; + } else { + // Really not found + throw new ValidationError("Stack not found"); + } } + } else { + log.debug("getStack", "Skip FS operations"); + } + + let stack : Stack; + + if (!skipFSOperations) { + stack = new Stack(server, stackName); + } else { + stack = new Stack(server, stackName, undefined, true); } - let stack = new Stack(server, stackName); stack._status = UNKNOWN; stack._configFilePath = path.resolve(dir); return stack; @@ -386,11 +399,11 @@ export class Stack { async getServiceStatusList() { let statusList = new Map(); - let res = childProcess.execSync("docker compose ps --format json", { + let res = childProcess.spawnSync("docker", [ "compose", "ps", "--format", "json" ], { cwd: this.path, }); - let lines = res.toString().split("\n"); + let lines = res.stdout.toString().split("\n"); for (let line of lines) { try { diff --git a/backend/terminal.ts b/backend/terminal.ts index 66831b9..f1faf18 100644 --- a/backend/terminal.ts +++ b/backend/terminal.ts @@ -80,37 +80,53 @@ export class Terminal { return; } - this._ptyProcess = pty.spawn(this.file, this.args, { - name: this.name, - cwd: this.cwd, - cols: TERMINAL_COLS, - rows: this.rows, - }); + try { + this._ptyProcess = pty.spawn(this.file, this.args, { + name: this.name, + cwd: this.cwd, + cols: TERMINAL_COLS, + rows: this.rows, + }); - // On Data - this._ptyProcess.onData((data) => { - this.buffer.pushItem(data); - if (this.server.io) { - this.server.io.to(this.name).emit("terminalWrite", this.name, data); + // On Data + this._ptyProcess.onData((data) => { + this.buffer.pushItem(data); + if (this.server.io) { + this.server.io.to(this.name).emit("terminalWrite", this.name, data); + } + }); + + // On Exit + this._ptyProcess.onExit(this.exit); + } catch (error) { + if (error instanceof Error) { + log.error("Terminal", "Failed to start terminal: " + error.message); + const exitCode = Number(error.message.split(" ").pop()); + this.exit({ + exitCode, + }); } - }); - - // On Exit - this._ptyProcess.onExit((res) => { - this.server.io.to(this.name).emit("terminalExit", this.name, res.exitCode); - - // Remove room - this.server.io.in(this.name).socketsLeave(this.name); - - Terminal.terminalMap.delete(this.name); - log.debug("Terminal", "Terminal " + this.name + " exited with code " + res.exitCode); - - if (this.callback) { - this.callback(res.exitCode); - } - }); + } } + /** + * Exit event handler + * @param res + */ + protected exit = (res : {exitCode: number, signal?: number | undefined}) => { + this.server.io.to(this.name).emit("terminalExit", this.name, res.exitCode); + + // Remove room + this.server.io.in(this.name).socketsLeave(this.name); + + Terminal.terminalMap.delete(this.name); + log.debug("Terminal", "Terminal " + this.name + " exited with code " + res.exitCode); + + if (this.callback) { + this.callback(res.exitCode); + } + }; + public onExit(callback : (exitCode : number) => void) { this.callback = callback; } diff --git a/package.json b/package.json index 9192ce5..eef98d2 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "lint": "eslint \"**/*.{ts,vue}\"", "check-ts": "tsc --noEmit", "start": "tsx ./backend/index.ts", - "dev:backend": "cross-env NODE_ENV=development tsx watch ./backend/index.ts", + "dev:backend": "cross-env NODE_ENV=development tsx watch --inspect ./backend/index.ts", "dev:frontend": "cross-env NODE_ENV=development vite --host --config ./frontend/vite.config.ts", "release-final": "tsx ./extra/test-docker.ts && tsx extra/update-version.ts && pnpm run build:frontend && npm run build:docker", "build:frontend": "vite build --config ./frontend/vite.config.ts",