Browse Source

Improvements (#124)

* Improvements

* Add inspect to dev:backend

* Skip debug log at the beginning
Louis Lam 1 year ago
parent
commit
31726315c3
5 changed files with 79 additions and 46 deletions
  1. 4 0
      backend/log.ts
  2. 1 1
      backend/socket-handlers/docker-socket-handler.ts
  3. 33 20
      backend/stack.ts
  4. 40 24
      backend/terminal.ts
  5. 1 1
      package.json

+ 4 - 0
backend/log.ts

@@ -103,6 +103,10 @@ class Logger {
      * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
      * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
      */
      */
     log(module: string, msg: unknown, level: string) {
     log(module: string, msg: unknown, level: string) {
+        if (level === "DEBUG" && !isDev) {
+            return;
+        }
+
         if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
         if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
             return;
             return;
         }
         }

+ 1 - 1
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");
                     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());
                 const serviceStatusList = Object.fromEntries(await stack.getServiceStatusList());
                 callback({
                 callback({
                     ok: true,
                     ok: true,

+ 33 - 20
backend/stack.ts

@@ -31,17 +31,19 @@ export class Stack {
 
 
     protected static managedStackList: Map<string, Stack> = new Map();
     protected static managedStackList: Map<string, Stack> = new Map();
 
 
-    constructor(server : DockgeServer, name : string, composeYAML? : string) {
+    constructor(server : DockgeServer, name : string, composeYAML? : string, skipFSOperations = false) {
         this.name = name;
         this.name = name;
         this.server = server;
         this.server = server;
         this._composeYAML = composeYAML;
         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);
         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._status = UNKNOWN;
         stack._configFilePath = path.resolve(dir);
         stack._configFilePath = path.resolve(dir);
         return stack;
         return stack;
@@ -386,11 +399,11 @@ export class Stack {
     async getServiceStatusList() {
     async getServiceStatusList() {
         let statusList = new Map<string, number>();
         let statusList = new Map<string, number>();
 
 
-        let res = childProcess.execSync("docker compose ps --format json", {
+        let res = childProcess.spawnSync("docker", [ "compose", "ps", "--format", "json" ], {
             cwd: this.path,
             cwd: this.path,
         });
         });
 
 
-        let lines = res.toString().split("\n");
+        let lines = res.stdout.toString().split("\n");
 
 
         for (let line of lines) {
         for (let line of lines) {
             try {
             try {

+ 40 - 24
backend/terminal.ts

@@ -80,36 +80,52 @@ export class Terminal {
             return;
             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);
+    /**
+     * 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);
+        // 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);
+        Terminal.terminalMap.delete(this.name);
+        log.debug("Terminal", "Terminal " + this.name + " exited with code " + res.exitCode);
 
 
-            if (this.callback) {
-                this.callback(res.exitCode);
-            }
-        });
-    }
+        if (this.callback) {
+            this.callback(res.exitCode);
+        }
+    };
 
 
     public onExit(callback : (exitCode : number) => void) {
     public onExit(callback : (exitCode : number) => void) {
         this.callback = callback;
         this.callback = callback;

+ 1 - 1
package.json

@@ -7,7 +7,7 @@
         "lint": "eslint \"**/*.{ts,vue}\"",
         "lint": "eslint \"**/*.{ts,vue}\"",
         "check-ts": "tsc --noEmit",
         "check-ts": "tsc --noEmit",
         "start": "tsx ./backend/index.ts",
         "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",
         "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",
         "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",
         "build:frontend": "vite build --config ./frontend/vite.config.ts",