* Starts the C++ background process and waits for the HTTP interface to be ready. * If a service is already running on the target port, it will skip spawning.
()
| 86 | * If a service is already running on the target port, it will skip spawning. |
| 87 | */ |
| 88 | private async startEngine(): Promise<void> { |
| 89 | this.port = await this.findPort(); |
| 90 | this.baseUrl = `http://localhost:${this.port}`; |
| 91 | |
| 92 | // Check if a service is already running on this port |
| 93 | try { |
| 94 | const controller = new AbortController(); |
| 95 | const timeoutId = setTimeout(() => controller.abort(), 200); |
| 96 | const res = await fetch(`${this.baseUrl}/status`, { signal: controller.signal }); |
| 97 | clearTimeout(timeoutId); |
| 98 | if (res.ok) { |
| 99 | // Service already alive, no need to spawn a new one |
| 100 | return; |
| 101 | } |
| 102 | } catch { |
| 103 | // Not running, proceed to spawn |
| 104 | } |
| 105 | |
| 106 | if (!this.binaryPath) { |
| 107 | throw new Error(`Engine binary path is not defined. Please ensure your platform is supported and binaries are correctly bundled.`); |
| 108 | } |
| 109 | |
| 110 | const args = ["--port", this.port.toString()]; |
| 111 | if (this.initialPath) { |
| 112 | const dirArg = Array.isArray(this.initialPath) |
| 113 | ? this.initialPath.join(" ") |
| 114 | : this.initialPath; |
| 115 | args.push("--source", dirArg); |
| 116 | } |
| 117 | |
| 118 | const binDir = path.dirname(this.binaryPath); |
| 119 | const env = { ...process.env }; |
| 120 | if (process.platform === "linux") { |
| 121 | env.LD_LIBRARY_PATH = binDir + (process.env.LD_LIBRARY_PATH ? `:${process.env.LD_LIBRARY_PATH}` : ""); |
| 122 | } else if (process.platform === "darwin") { |
| 123 | env.DYLD_LIBRARY_PATH = binDir + (process.env.DYLD_LIBRARY_PATH ? `:${process.env.DYLD_LIBRARY_PATH}` : ""); |
| 124 | } |
| 125 | |
| 126 | return new Promise((resolve, reject) => { |
| 127 | this.process = spawn(this.binaryPath, args, { |
| 128 | stdio: "ignore", |
| 129 | detached: true, |
| 130 | env: env, |
| 131 | }); |
| 132 | |
| 133 | // Allow the process to stay alive after the parent exits |
| 134 | this.process.unref(); |
| 135 | |
| 136 | this.process.on("error", (err) => { |
| 137 | this.process = null; |
| 138 | reject(err); |
| 139 | }); |
| 140 | |
| 141 | this.process.on("exit", (code) => { |
| 142 | if (code !== 0 && this.process) { |
| 143 | console.error(`DocsAgent engine exited with code ${code}`); |
| 144 | } |
| 145 | this.process = null; |