coding-tool-x 3.9.5-261012 → 3.9.5-261013
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/daemon.js +45 -27
- package/src/commands/proxy-control.js +14 -4
package/package.json
CHANGED
package/src/commands/daemon.js
CHANGED
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
formatPortToolIssue
|
|
13
13
|
} = require('../utils/port-helper');
|
|
14
14
|
const { hasHostFlag } = require('../utils/cli-flags');
|
|
15
|
-
const { getPlatformRegistry
|
|
15
|
+
const { getPlatformRegistry } = require('../platforms/runtime');
|
|
16
|
+
const { createProxyControl } = require('./proxy-control');
|
|
16
17
|
const PM2_APP_NAME = 'cc-tool';
|
|
17
18
|
const STARTUP_LOG_FILE = 'cc-tool-out.log';
|
|
18
19
|
const PM2_RUNTIME_ENV_KEYS = [
|
|
@@ -279,40 +280,48 @@ function getPlatformPort(platform, config = {}) {
|
|
|
279
280
|
return configured || platform.defaultPort || null;
|
|
280
281
|
}
|
|
281
282
|
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
283
|
+
function getUIConnectionOptions(existing, config = loadConfig()) {
|
|
284
|
+
const env = existing?.pm2_env || {};
|
|
285
|
+
const port = Number(env.CC_TOOL_PORT || env.env?.CC_TOOL_PORT || config.ports?.webUI || 19999);
|
|
286
|
+
const args = Array.isArray(env.args) ? env.args : String(env.args || '').split(/\s+/);
|
|
287
|
+
return { port, useHttps: args.includes('--https') };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function getProxyStatusEntries({ registry = getPlatformRegistry(), config = loadConfig(), httpRequest, connection } = {}) {
|
|
291
|
+
// Servers live in the UI daemon. Loading a driver here creates a separate
|
|
292
|
+
// singleton in the CLI process whose status will always be stopped.
|
|
293
|
+
const control = createProxyControl({ registry, loadConfig: () => config, httpRequest, connection });
|
|
294
|
+
return Promise.all(listProxyPlatforms(registry).map(async (platform) => {
|
|
285
295
|
const context = {
|
|
286
296
|
platform: platform.key,
|
|
287
297
|
capability: 'proxy',
|
|
288
298
|
operation: 'status'
|
|
289
299
|
};
|
|
290
300
|
try {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
: null;
|
|
294
|
-
if (!driver || (typeof driver.status === 'string' && driver.status !== 'ok')) {
|
|
295
|
-
entries.push({ platform, state: { status: 'unsupported', ...context }, port: getPlatformPort(platform, config) });
|
|
296
|
-
continue;
|
|
301
|
+
if (platform.capabilities?.proxy === 'unsupported' || platform.capabilities?.proxy === false) {
|
|
302
|
+
return { platform, state: { status: 'unsupported', ...context }, port: getPlatformPort(platform, config) };
|
|
297
303
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
304
|
+
const { response } = await control.status(platform.key);
|
|
305
|
+
const result = response.data;
|
|
306
|
+
if (!Number.isInteger(response.status) || response.status < 200 || response.status >= 300) {
|
|
307
|
+
const failure = result?.error;
|
|
308
|
+
if (failure && typeof failure === 'object') {
|
|
309
|
+
return { platform, state: { ...failure, status: failure.status && failure.status !== 'ok' ? failure.status : 'failed', ...context }, port: getPlatformPort(platform, config) };
|
|
310
|
+
}
|
|
311
|
+
throw new Error(typeof failure === 'string' ? failure : `HTTP ${response.status}`);
|
|
301
312
|
}
|
|
302
|
-
|
|
303
|
-
//
|
|
304
|
-
// service status payloads in { status: 'ok', data }. Keep compatibility
|
|
305
|
-
// with legacy drivers that return the service payload directly.
|
|
313
|
+
// The API normally unwraps the Driver result. Accept wrapped payloads
|
|
314
|
+
// too, but never interpret an invalid response as a stopped proxy.
|
|
306
315
|
const state = result && result.status === 'ok'
|
|
307
316
|
? (result.data && typeof result.data === 'object' ? result.data : {})
|
|
308
317
|
: result;
|
|
309
318
|
if (state && typeof state.status === 'string' && state.status !== 'ok') {
|
|
310
|
-
|
|
311
|
-
} else {
|
|
312
|
-
entries.push({ platform, state: state || {}, port: getPlatformPort(platform, config) });
|
|
319
|
+
return { platform, state: { ...state, ...context }, port: getPlatformPort(platform, config) };
|
|
313
320
|
}
|
|
321
|
+
if (!state || typeof state.running !== 'boolean') throw new Error('Invalid proxy status response');
|
|
322
|
+
return { platform, state, port: getPlatformPort(platform, config) };
|
|
314
323
|
} catch (error) {
|
|
315
|
-
|
|
324
|
+
return {
|
|
316
325
|
platform,
|
|
317
326
|
state: {
|
|
318
327
|
status: 'failed',
|
|
@@ -320,10 +329,9 @@ async function getProxyStatusEntries({ registry = getPlatformRegistry(), runtime
|
|
|
320
329
|
error: error && error.message ? error.message : String(error)
|
|
321
330
|
},
|
|
322
331
|
port: getPlatformPort(platform, config)
|
|
323
|
-
}
|
|
332
|
+
};
|
|
324
333
|
}
|
|
325
|
-
}
|
|
326
|
-
return entries;
|
|
334
|
+
}));
|
|
327
335
|
}
|
|
328
336
|
|
|
329
337
|
function getManagedPorts(config = loadConfig(), registry = getPlatformRegistry()) {
|
|
@@ -739,6 +747,12 @@ async function handleStatus() {
|
|
|
739
747
|
|
|
740
748
|
const existing = await getCCToolProcess();
|
|
741
749
|
const config = loadConfig();
|
|
750
|
+
const connection = getUIConnectionOptions(existing, config);
|
|
751
|
+
const protocol = connection.useHttps ? 'https' : 'http';
|
|
752
|
+
if (connection.useHttps && PATHS.config) {
|
|
753
|
+
const certPath = path.join(PATHS.config, 'https', 'localhost-cert.pem');
|
|
754
|
+
if (fs.existsSync(certPath)) connection.ca = fs.readFileSync(certPath);
|
|
755
|
+
}
|
|
742
756
|
|
|
743
757
|
console.log(chalk.bold.cyan('\n╔======================================╗'));
|
|
744
758
|
console.log(chalk.bold.cyan('║ Coding-Tool 服务状态 ║'));
|
|
@@ -748,7 +762,7 @@ async function handleStatus() {
|
|
|
748
762
|
console.log(chalk.bold('[UI] Web UI 服务:'));
|
|
749
763
|
if (existing && existing.pm2_env.status === 'online') {
|
|
750
764
|
console.log(chalk.green(' [OK] 状态: 运行中'));
|
|
751
|
-
console.log(chalk.gray(` [NET] 地址:
|
|
765
|
+
console.log(chalk.gray(` [NET] 地址: ${protocol}://localhost:${connection.port}`));
|
|
752
766
|
console.log(chalk.gray(` [KEY] 进程 ID: ${existing.pid}`));
|
|
753
767
|
console.log(chalk.gray(` [TIMER] 运行时长: ${formatUptime(existing.pm2_env.pm_uptime)}`));
|
|
754
768
|
console.log(chalk.gray(` [SAVE] 内存使用: ${formatMemory(existing.monit?.memory)}`));
|
|
@@ -757,8 +771,11 @@ async function handleStatus() {
|
|
|
757
771
|
console.log(chalk.gray(' [ERROR] 状态: 未运行'));
|
|
758
772
|
}
|
|
759
773
|
|
|
760
|
-
//
|
|
761
|
-
const proxyStatuses = await getProxyStatusEntries({
|
|
774
|
+
// Query the drivers in the running backend through manifest-declared APIs.
|
|
775
|
+
const proxyStatuses = await getProxyStatusEntries({
|
|
776
|
+
config: { ...config, ports: { ...config.ports, webUI: connection.port } },
|
|
777
|
+
connection
|
|
778
|
+
});
|
|
762
779
|
|
|
763
780
|
console.log(chalk.bold('\n[PROXY] 代理服务:'));
|
|
764
781
|
for (const entry of proxyStatuses) {
|
|
@@ -835,6 +852,7 @@ module.exports = {
|
|
|
835
852
|
shouldTreatPortOwnershipAsReady,
|
|
836
853
|
getManagedPorts,
|
|
837
854
|
getProxyStatusEntries,
|
|
855
|
+
getUIConnectionOptions,
|
|
838
856
|
listProxyPlatforms,
|
|
839
857
|
shouldStopPM2Process
|
|
840
858
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const http = require('http');
|
|
3
|
+
const https = require('https');
|
|
3
4
|
const { loadConfig } = require('../config/loader');
|
|
4
5
|
const { normalizePlatformKey } = require('../shared/platforms');
|
|
5
6
|
|
|
@@ -38,7 +39,7 @@ function getPlatformInfo(channel, registry = getDefaultRegistry()) {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
function createHttpRequest(loadConfigImpl = loadConfig) {
|
|
42
|
+
function createHttpRequest(loadConfigImpl = loadConfig, { useHttps = false, ca } = {}) {
|
|
42
43
|
return function request(method, requestPath, data = null) {
|
|
43
44
|
const config = loadConfigImpl();
|
|
44
45
|
const port = config.ports?.webUI || 19999;
|
|
@@ -56,10 +57,19 @@ function createHttpRequest(loadConfigImpl = loadConfig) {
|
|
|
56
57
|
},
|
|
57
58
|
timeout: 5000
|
|
58
59
|
};
|
|
60
|
+
if (useHttps) {
|
|
61
|
+
// This client only connects to localhost. Trust the daemon's generated
|
|
62
|
+
// certificate when available (Windows may use a PFX instead of PEM).
|
|
63
|
+
options.ca = ca;
|
|
64
|
+
options.rejectUnauthorized = Boolean(ca);
|
|
65
|
+
}
|
|
59
66
|
|
|
60
|
-
const req = http.request(options, (res) => {
|
|
67
|
+
const req = (useHttps ? https : http).request(options, (res) => {
|
|
61
68
|
let responseData = '';
|
|
62
69
|
|
|
70
|
+
res.on('error', reject);
|
|
71
|
+
res.on('aborted', () => reject(new Error('Response connection closed unexpectedly')));
|
|
72
|
+
|
|
63
73
|
res.on('data', (chunk) => {
|
|
64
74
|
responseData += chunk;
|
|
65
75
|
});
|
|
@@ -86,8 +96,8 @@ function createHttpRequest(loadConfigImpl = loadConfig) {
|
|
|
86
96
|
};
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
function createProxyControl({ registry = getDefaultRegistry(), httpRequest: request, loadConfig: loadConfigImpl, sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) } = {}) {
|
|
90
|
-
const requestImpl = request || createHttpRequest(loadConfigImpl || loadConfig);
|
|
99
|
+
function createProxyControl({ registry = getDefaultRegistry(), httpRequest: request, loadConfig: loadConfigImpl, connection, sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) } = {}) {
|
|
100
|
+
const requestImpl = request || createHttpRequest(loadConfigImpl || loadConfig, connection);
|
|
91
101
|
|
|
92
102
|
function resolve(channel) {
|
|
93
103
|
const info = getPlatformInfo(channel, registry);
|