tirtc-devtools-cli 0.0.9 → 0.0.11
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/README.md +17 -11
- package/USAGE.md +72 -33
- package/bin/tirtc-devtools-cli.js +1 -1
- package/dist/cli/src/bootstrap_flows.d.ts +46 -0
- package/dist/cli/src/bootstrap_flows.js +249 -0
- package/dist/{devtools/cli → cli}/src/config.d.ts +4 -15
- package/dist/{devtools/cli → cli}/src/config.js +7 -31
- package/dist/cli/src/default_paths.d.ts +3 -0
- package/dist/cli/src/default_paths.js +23 -0
- package/dist/{devtools/cli → cli}/src/embedded_paths.d.ts +1 -0
- package/dist/{devtools/cli → cli}/src/embedded_paths.js +18 -1
- package/dist/{devtools/cli → cli}/src/facade.d.ts +41 -235
- package/dist/{devtools/cli → cli}/src/facade.js +8 -27
- package/dist/cli/src/guide.js +47 -0
- package/dist/{devtools/cli → cli}/src/index.js +55 -141
- package/dist/{devtools/cli → cli}/src/session_manager.js +9 -11
- package/dist/{devtools/cli → cli}/src/token_command.js +69 -0
- package/dist/{devtools/cli → cli}/src/token_tool.d.ts +26 -0
- package/dist/{devtools/cli → cli}/src/token_tool.js +123 -22
- package/dist/{devtools/cli → cli}/src/transport.d.ts +1 -1
- package/package.json +6 -2
- package/script/ensure_ffmpeg.sh +1 -1
- package/vendor/app-server/bin/native/linux-x64/credential_napi.node +0 -0
- package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/credential.h +34 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/error.h +13 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/foundation/build_info.h +27 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/http.h +57 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/logging.h +3 -1
- package/vendor/app-server/bin/runtime/linux-x64/lib/libcrypto.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_credential.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_http.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_logging.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libssl.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/manifest.txt +2 -32
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +176 -133
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +223 -182
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +2 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +6 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/transport.h +58 -133
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +47 -224
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libTGTRP.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libTiRTC.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +19 -15
- package/vendor/app-server/dist/host/HostCommandCoordinator.d.ts +19 -0
- package/vendor/app-server/dist/host/HostCommandCoordinator.js +196 -0
- package/vendor/app-server/dist/host/HostProtocol.d.ts +1 -11
- package/vendor/app-server/dist/host/HostProtocol.js +3 -37
- package/vendor/app-server/dist/host/HostServer.d.ts +1 -4
- package/vendor/app-server/dist/host/HostServer.js +16 -152
- package/vendor/app-server/dist/host/RuntimeAdapter.js +2 -2
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +3 -3
- package/vendor/app-server/dist/host/native/RuntimeHostBridge.js +4 -4
- package/vendor/app-server/dist/host/runtime_backed_preflight.js +2 -2
- package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.js +1 -1
- package/vendor/app-server/dist/protocol/contract.d.ts +5 -64
- package/vendor/app-server/dist/protocol/contract.js +3 -12
- package/dist/devtools/cli/src/guide.js +0 -50
- package/dist/dummy.d.ts +0 -0
- package/dist/dummy.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -48
- package/vendor/app-server/bin/native/macos-arm64/libcrypto.dylib +0 -0
- package/vendor/app-server/bin/native/macos-arm64/libssl.dylib +0 -0
- package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_codec.h +0 -23
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_frame.h +0 -36
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io.h +0 -56
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_android.h +0 -19
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_apple.h +0 -19
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_harmony.h +0 -19
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_windows.h +0 -19
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_processing.h +0 -56
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_sample_rate.h +0 -18
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_codec.h +0 -21
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_downlink.h +0 -89
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_uplink.h +0 -115
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/runtime.h +0 -236
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_codec.h +0 -57
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_frame.h +0 -55
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io.h +0 -46
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_android.h +0 -32
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_apple.h +0 -34
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_harmony.h +0 -32
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_windows.h +0 -26
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_processing.h +0 -34
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_audio.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_media.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_video.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libwebrtc_apm.a +0 -0
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.d.ts +0 -30
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.js +0 -224
- /package/dist/{devtools/cli → cli}/src/dummy.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/dummy.js +0 -0
- /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.js +0 -0
- /package/dist/{devtools/cli → cli}/src/guide.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/index.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/media_assets.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/media_assets.js +0 -0
- /package/dist/{devtools/cli → cli}/src/progress.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/progress.js +0 -0
- /package/dist/{devtools/cli → cli}/src/session_manager.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/token_command.d.ts +0 -0
- /package/dist/{devtools/cli → cli}/src/transport.js +0 -0
- /package/vendor/app-server/bin/{native/macos-arm64 → runtime/macos-arm64/lib}/libtgrtc.dylib +0 -0
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
const commander_1 = require("commander");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const protocol_client_1 = require("../../../app-server/protocol-client");
|
|
10
|
-
const facade_1 = require("./facade");
|
|
4
|
+
const protocol_client_1 = require("../../app-server/protocol-client");
|
|
5
|
+
const bootstrap_flows_1 = require("./bootstrap_flows");
|
|
11
6
|
const config_1 = require("./config");
|
|
7
|
+
const facade_1 = require("./facade");
|
|
12
8
|
const guide_1 = require("./guide");
|
|
13
9
|
const session_manager_1 = require("./session_manager");
|
|
14
10
|
const media_assets_1 = require("./media_assets");
|
|
15
11
|
const token_command_1 = require("./token_command");
|
|
16
12
|
const transport_1 = require("./transport");
|
|
17
13
|
const progress_1 = require("./progress");
|
|
18
|
-
const CLI_VERSION = '0.0.
|
|
14
|
+
const CLI_VERSION = '0.0.10';
|
|
19
15
|
const HOST_VERSION = '1.0.0';
|
|
20
16
|
const PROTOCOL_VERSION = '1.0.0';
|
|
21
17
|
if (process.argv.includes('--version') || process.argv.includes('-V')) {
|
|
@@ -29,6 +25,16 @@ function getCliOptions() {
|
|
|
29
25
|
return program.opts();
|
|
30
26
|
}
|
|
31
27
|
function normalizeError(error) {
|
|
28
|
+
if (typeof error === 'object' && error !== null) {
|
|
29
|
+
const typed = error;
|
|
30
|
+
if (typed.reasonCode || typed.message || typed.data !== undefined) {
|
|
31
|
+
return {
|
|
32
|
+
reasonCode: typed.reasonCode ?? 'internal_error',
|
|
33
|
+
message: typed.message ?? 'Internal error',
|
|
34
|
+
data: typed.data,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
32
38
|
if (error instanceof Error) {
|
|
33
39
|
return {
|
|
34
40
|
reasonCode: 'internal_error',
|
|
@@ -36,14 +42,6 @@ function normalizeError(error) {
|
|
|
36
42
|
data: undefined,
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
|
-
if (typeof error === 'object' && error !== null) {
|
|
40
|
-
const typed = error;
|
|
41
|
-
return {
|
|
42
|
-
reasonCode: typed.reasonCode ?? 'internal_error',
|
|
43
|
-
message: typed.message ?? 'Internal error',
|
|
44
|
-
data: typed.data,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
45
|
return {
|
|
48
46
|
reasonCode: 'internal_error',
|
|
49
47
|
message: 'Internal error',
|
|
@@ -55,18 +53,14 @@ function createSessionTransport(sessionId) {
|
|
|
55
53
|
return new transport_1.SocketTransport(session.socketPath);
|
|
56
54
|
}
|
|
57
55
|
function isBootstrapCommand(cmdName) {
|
|
58
|
-
return cmdName === 'service start' || cmdName === 'connection connect';
|
|
56
|
+
return cmdName === 'service start' || cmdName === 'connection connect' || cmdName === 'client start';
|
|
59
57
|
}
|
|
60
|
-
function resolveSessionForCommand(cmdName, options
|
|
61
|
-
|
|
62
|
-
logRootDir: config.logging?.root_dir,
|
|
63
|
-
consoleMirror: config.logging?.console_mirror,
|
|
64
|
-
};
|
|
65
|
-
if (cmdName === 'connection connect') {
|
|
58
|
+
function resolveSessionForCommand(cmdName, options) {
|
|
59
|
+
if (cmdName === 'connection connect' || cmdName === 'client start') {
|
|
66
60
|
if (options.session && options.session.trim().length > 0) {
|
|
67
|
-
throw new Error('
|
|
61
|
+
throw new Error(cmdName + ' always creates a new session; do not pass --session');
|
|
68
62
|
}
|
|
69
|
-
const created = (0, session_manager_1.createSession)({
|
|
63
|
+
const created = (0, session_manager_1.createSession)({ role: 'client' });
|
|
70
64
|
return { sessionId: created.sessionId, created: true };
|
|
71
65
|
}
|
|
72
66
|
if (cmdName === 'service start') {
|
|
@@ -75,7 +69,7 @@ function resolveSessionForCommand(cmdName, options, config) {
|
|
|
75
69
|
(0, session_manager_1.setSessionRole)(existing.sessionId, 'service');
|
|
76
70
|
return { sessionId: existing.sessionId, created: false };
|
|
77
71
|
}
|
|
78
|
-
const created = (0, session_manager_1.createSession)({
|
|
72
|
+
const created = (0, session_manager_1.createSession)({ role: 'service' });
|
|
79
73
|
return { sessionId: created.sessionId, created: true };
|
|
80
74
|
}
|
|
81
75
|
if (cmdName === 'debug bootstrap qrcode') {
|
|
@@ -109,104 +103,21 @@ function toResultObject(result) {
|
|
|
109
103
|
}
|
|
110
104
|
function requireConfigPath(configPath) {
|
|
111
105
|
if (!configPath || configPath.trim().length === 0) {
|
|
112
|
-
throw new Error('
|
|
106
|
+
throw new Error('command requires --config <path>');
|
|
113
107
|
}
|
|
114
108
|
return configPath;
|
|
115
109
|
}
|
|
116
|
-
function validateServerConfig(config) {
|
|
117
|
-
const server = config.server;
|
|
118
|
-
const license = server?.license?.trim() ?? '';
|
|
119
|
-
const mp4Path = server?.mp4_path?.trim() ?? '';
|
|
120
|
-
const audioStreamIdValue = server?.audio_stream_id;
|
|
121
|
-
const videoStreamIdValue = server?.video_stream_id;
|
|
122
|
-
if (license.length === 0) {
|
|
123
|
-
throw new Error('server-only config requires [server].license');
|
|
124
|
-
}
|
|
125
|
-
if (mp4Path.length === 0) {
|
|
126
|
-
throw new Error('server-only config requires [server].mp4_path');
|
|
127
|
-
}
|
|
128
|
-
if (typeof audioStreamIdValue !== 'number') {
|
|
129
|
-
throw new Error('server-only config requires [server].audio_stream_id as non-negative integer');
|
|
130
|
-
}
|
|
131
|
-
if (!Number.isInteger(audioStreamIdValue) || audioStreamIdValue < 0) {
|
|
132
|
-
throw new Error('server-only config requires [server].audio_stream_id as non-negative integer');
|
|
133
|
-
}
|
|
134
|
-
if (typeof videoStreamIdValue !== 'number') {
|
|
135
|
-
throw new Error('server-only config requires [server].video_stream_id as non-negative integer');
|
|
136
|
-
}
|
|
137
|
-
if (!Number.isInteger(videoStreamIdValue) || videoStreamIdValue < 0) {
|
|
138
|
-
throw new Error('server-only config requires [server].video_stream_id as non-negative integer');
|
|
139
|
-
}
|
|
140
|
-
const audioStreamId = audioStreamIdValue;
|
|
141
|
-
const videoStreamId = videoStreamIdValue;
|
|
142
|
-
if (audioStreamId === videoStreamId) {
|
|
143
|
-
throw new Error('server-only config requires distinct audio_stream_id and video_stream_id');
|
|
144
|
-
}
|
|
145
|
-
const resolvedMp4Path = path_1.default.resolve(mp4Path);
|
|
146
|
-
let stats;
|
|
147
|
-
try {
|
|
148
|
-
stats = fs_1.default.statSync(resolvedMp4Path);
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
throw new Error('server-only config mp4_path does not exist: ' + resolvedMp4Path);
|
|
152
|
-
}
|
|
153
|
-
if (!stats.isFile()) {
|
|
154
|
-
throw new Error('server-only config mp4_path must be a readable file: ' + resolvedMp4Path);
|
|
155
|
-
}
|
|
156
|
-
const serviceEntry = server?.service_entry?.trim();
|
|
157
|
-
return {
|
|
158
|
-
serviceEntry: serviceEntry && serviceEntry.length > 0 ? serviceEntry : undefined,
|
|
159
|
-
license,
|
|
160
|
-
mp4Path: resolvedMp4Path,
|
|
161
|
-
audioStreamId,
|
|
162
|
-
videoStreamId,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
110
|
function createProgressIndicator(options) {
|
|
166
111
|
if (options.json) {
|
|
167
112
|
return undefined;
|
|
168
113
|
}
|
|
169
114
|
return new progress_1.ProgressIndicator();
|
|
170
115
|
}
|
|
171
|
-
function resolvePrepareOutputRoot(config) {
|
|
172
|
-
const loggingRoot = config.logging?.root_dir?.trim();
|
|
173
|
-
if (loggingRoot && loggingRoot.length > 0) {
|
|
174
|
-
return path_1.default.resolve(loggingRoot, '..', 'prepared-assets');
|
|
175
|
-
}
|
|
176
|
-
return path_1.default.resolve(process.cwd(), '.tmp', 'tirtc-devtools-cli', 'prepared-assets');
|
|
177
|
-
}
|
|
178
|
-
async function applyConfiguredServerBootstrap(client, config, progress) {
|
|
179
|
-
const server = validateServerConfig(config);
|
|
180
|
-
progress?.start('Preparing MP4 assets');
|
|
181
|
-
const prepared = await (0, media_assets_1.prepareMediaAssets)({
|
|
182
|
-
source: server.mp4Path,
|
|
183
|
-
outputRoot: resolvePrepareOutputRoot(config),
|
|
184
|
-
});
|
|
185
|
-
progress?.update('Prepared MP4 assets');
|
|
186
|
-
const bootstrapSendStreams = [
|
|
187
|
-
{ streamId: server.audioStreamId, media: 'audio' },
|
|
188
|
-
{ streamId: server.videoStreamId, media: 'video' },
|
|
189
|
-
].map(({ streamId, media }) => ({
|
|
190
|
-
streamId,
|
|
191
|
-
media,
|
|
192
|
-
source: {
|
|
193
|
-
mode: 'local_assets',
|
|
194
|
-
local_assets: {
|
|
195
|
-
assets_dir: prepared.assets_dir,
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
}));
|
|
199
|
-
return {
|
|
200
|
-
preparedAssetsDir: prepared.assets_dir,
|
|
201
|
-
mediaSendPolicy: 'AUTO_ON_CONNECTED',
|
|
202
|
-
bootstrapSendStreams,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
116
|
async function runCommand(cmdName, params, options) {
|
|
206
117
|
let transport;
|
|
207
118
|
try {
|
|
208
119
|
const config = (0, config_1.loadConfig)(options.config);
|
|
209
|
-
const session = resolveSessionForCommand(cmdName, options
|
|
120
|
+
const session = resolveSessionForCommand(cmdName, options);
|
|
210
121
|
transport = createSessionTransport(session.sessionId);
|
|
211
122
|
const client = new protocol_client_1.AppServerClient(transport);
|
|
212
123
|
await client.initialize({ name: 'tirtc-devtools-cli', version: CLI_VERSION });
|
|
@@ -218,7 +129,7 @@ async function runCommand(cmdName, params, options) {
|
|
|
218
129
|
if (cmdName === 'service start') {
|
|
219
130
|
const progress = createProgressIndicator(options);
|
|
220
131
|
try {
|
|
221
|
-
const autoApplied = await applyConfiguredServerBootstrap(client, config, progress);
|
|
132
|
+
const autoApplied = await (0, bootstrap_flows_1.applyConfiguredServerBootstrap)(client, config, progress);
|
|
222
133
|
progress?.update('Starting service session');
|
|
223
134
|
const requestParams = {
|
|
224
135
|
...params,
|
|
@@ -240,6 +151,20 @@ async function runCommand(cmdName, params, options) {
|
|
|
240
151
|
throw error;
|
|
241
152
|
}
|
|
242
153
|
}
|
|
154
|
+
if (cmdName === 'client start') {
|
|
155
|
+
const progress = createProgressIndicator(options);
|
|
156
|
+
try {
|
|
157
|
+
const token = String(params.token ?? '');
|
|
158
|
+
const result = await (0, bootstrap_flows_1.applyClientStartBootstrap)(client, config, token, progress);
|
|
159
|
+
printSuccess(options, result, session, cmdName);
|
|
160
|
+
transport.stop();
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
progress?.fail('Client start failed');
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
243
168
|
const result = await client.sendRequest(method, params);
|
|
244
169
|
resultForPrint = result;
|
|
245
170
|
printSuccess(options, resultForPrint, session, cmdName);
|
|
@@ -353,7 +278,7 @@ program.name('tirtc-devtools-cli')
|
|
|
353
278
|
.description('TiRTC DevTools CLI')
|
|
354
279
|
.option('--config <path>', '配置文件路径(TOML)')
|
|
355
280
|
.option('--json', '以机器可读 JSON 输出(便于脚本集成)')
|
|
356
|
-
.option('--session <sessionId>', '指定会话 ID;除 service start/connect 外必须传');
|
|
281
|
+
.option('--session <sessionId>', '指定会话 ID;除 service start / client start / connection connect 外必须传');
|
|
357
282
|
const host = program.command('host').description('Host 基础能力(状态、停止)');
|
|
358
283
|
host.command('status').description('查看 Host/service/connection/artifact 当前状态').action(() => {
|
|
359
284
|
runAndExit(runCommand('host status', {}, getCliOptions()));
|
|
@@ -390,10 +315,7 @@ const hostSession = host.command('session').description('会话管理:start/li
|
|
|
390
315
|
hostSession.command('start').description('创建并启动一个常驻会话,返回 sessionId').action(() => {
|
|
391
316
|
try {
|
|
392
317
|
const options = getCliOptions();
|
|
393
|
-
const config = (0, config_1.loadConfig)(options.config);
|
|
394
318
|
const created = (0, session_manager_1.createSession)({
|
|
395
|
-
logRootDir: config.logging?.root_dir,
|
|
396
|
-
consoleMirror: config.logging?.console_mirror,
|
|
397
319
|
role: 'idle',
|
|
398
320
|
});
|
|
399
321
|
if (options.json) {
|
|
@@ -503,49 +425,41 @@ service.command('start')
|
|
|
503
425
|
.action(() => {
|
|
504
426
|
const options = getCliOptions();
|
|
505
427
|
const config = (0, config_1.loadConfig)(requireConfigPath(options.config));
|
|
506
|
-
const server = validateServerConfig(config);
|
|
428
|
+
const server = (0, bootstrap_flows_1.validateServerConfig)(config);
|
|
507
429
|
runAndExit(runCommand('service start', { serviceEntry: server.serviceEntry, license: server.license, timeoutMs: 5000 }, options));
|
|
508
430
|
});
|
|
509
431
|
service.command('stop').description('停止服务端监听').action(() => {
|
|
510
432
|
runAndExit(runCommand('service stop', {}, getCliOptions()));
|
|
511
433
|
});
|
|
434
|
+
const client = program.command('client').description('客户端正式入口:连接远端并自动挂载本地 web preview');
|
|
435
|
+
client.command('start')
|
|
436
|
+
.description('读取 [client] 配置,连接远端并输出 web preview 地址')
|
|
437
|
+
.requiredOption('--token <token>', '显式 client token;不支持 auto token')
|
|
438
|
+
.action((commandOptions) => {
|
|
439
|
+
const options = getCliOptions();
|
|
440
|
+
(0, config_1.loadConfig)(requireConfigPath(options.config));
|
|
441
|
+
runAndExit(runCommand('client start', { token: commandOptions.token }, options));
|
|
442
|
+
});
|
|
512
443
|
const connection = program.command('connection').description('客户端能力:主动连接远端 peer');
|
|
513
444
|
connection.command('show').description('查看连接状态').action(() => {
|
|
514
445
|
runAndExit(runCommand('connection show', {}, getCliOptions()));
|
|
515
446
|
});
|
|
516
|
-
connection.command('connect [service_entry] <peer_id>
|
|
517
|
-
.description('作为客户端连接远端(总是新建 session
|
|
447
|
+
connection.command('connect [service_entry] <peer_id> <token>')
|
|
448
|
+
.description('作为客户端连接远端(总是新建 session;要求显式 token)')
|
|
518
449
|
.action((serviceEntry, peerId, token) => {
|
|
519
450
|
const config = (0, config_1.loadConfig)(getCliOptions().config);
|
|
520
|
-
const finalServiceEntry = [serviceEntry, config.
|
|
451
|
+
const finalServiceEntry = [serviceEntry, config.client?.service_entry, config.server?.service_entry]
|
|
521
452
|
.find((value) => typeof value === 'string' && value.trim().length > 0);
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const hasAutoToken = Boolean(autoTokenCfg?.access_id && autoTokenCfg?.secret_key);
|
|
526
|
-
if (!manualToken && !hasAutoToken) {
|
|
527
|
-
throw new Error('connection connect requires token or [connection.auto_token] access_id/secret_key');
|
|
453
|
+
const manualToken = token.trim();
|
|
454
|
+
if (manualToken.length === 0) {
|
|
455
|
+
throw new Error('connection connect requires non-empty token');
|
|
528
456
|
}
|
|
529
457
|
const params = {
|
|
530
458
|
serviceEntry: finalServiceEntry,
|
|
531
459
|
peerId,
|
|
460
|
+
token: manualToken,
|
|
532
461
|
timeoutMs: 5000,
|
|
533
462
|
};
|
|
534
|
-
if (manualToken && manualToken.length > 0) {
|
|
535
|
-
params.token = manualToken;
|
|
536
|
-
params.tokenMode = 'manual';
|
|
537
|
-
}
|
|
538
|
-
else {
|
|
539
|
-
params.tokenMode = 'auto';
|
|
540
|
-
params.autoToken = {
|
|
541
|
-
openapiEntry: autoTokenCfg?.openapi_entry,
|
|
542
|
-
accessId: autoTokenCfg?.access_id,
|
|
543
|
-
secretKey: autoTokenCfg?.secret_key,
|
|
544
|
-
localId: autoTokenCfg?.local_id ?? peerId,
|
|
545
|
-
userTtlSeconds: autoTokenCfg?.user_ttl_seconds,
|
|
546
|
-
channelTtlSeconds: autoTokenCfg?.channel_ttl_seconds,
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
463
|
runAndExit(runCommand('connection connect', params, getCliOptions()));
|
|
550
464
|
});
|
|
551
465
|
connection.command('disconnect').description('断开当前连接').action(() => {
|
|
@@ -14,6 +14,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const crypto_1 = require("crypto");
|
|
16
16
|
const child_process_1 = require("child_process");
|
|
17
|
+
const default_paths_1 = require("./default_paths");
|
|
17
18
|
const embedded_paths_1 = require("./embedded_paths");
|
|
18
19
|
const kStartupTimeoutMs = 5000;
|
|
19
20
|
const kStartupPollIntervalMs = 100;
|
|
@@ -26,11 +27,7 @@ function sleepMs(ms) {
|
|
|
26
27
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
27
28
|
}
|
|
28
29
|
function getStateDir() {
|
|
29
|
-
|
|
30
|
-
if (explicit && explicit.trim().length > 0) {
|
|
31
|
-
return explicit.trim();
|
|
32
|
-
}
|
|
33
|
-
return path_1.default.join(os_1.default.homedir(), '.tirtc-devtools-cli');
|
|
30
|
+
return (0, default_paths_1.resolveCliStateRootDir)();
|
|
34
31
|
}
|
|
35
32
|
function getSocketDir() {
|
|
36
33
|
const explicit = process.env.TIRTC_DEVTOOL_SOCKET_DIR;
|
|
@@ -148,10 +145,10 @@ function getHostBinaryPath() {
|
|
|
148
145
|
return embedded;
|
|
149
146
|
}
|
|
150
147
|
const candidates = [
|
|
151
|
-
path_1.default.resolve(__dirname, '../../../app-server/bin/tirtc-devtool-host.js'),
|
|
152
|
-
path_1.default.resolve(__dirname, '../../../../../../app-server/bin/tirtc-devtool-host.js'),
|
|
153
|
-
path_1.default.resolve(process.cwd(), '../app-server/bin/tirtc-devtool-host.js'),
|
|
154
|
-
path_1.default.resolve(process.cwd(), 'app-server/bin/tirtc-devtool-host.js'),
|
|
148
|
+
path_1.default.resolve(__dirname, '../../../products/app-server/bin/tirtc-devtool-host.js'),
|
|
149
|
+
path_1.default.resolve(__dirname, '../../../../../../products/app-server/bin/tirtc-devtool-host.js'),
|
|
150
|
+
path_1.default.resolve(process.cwd(), '../products/app-server/bin/tirtc-devtool-host.js'),
|
|
151
|
+
path_1.default.resolve(process.cwd(), 'products/app-server/bin/tirtc-devtool-host.js'),
|
|
155
152
|
];
|
|
156
153
|
for (const candidate of candidates) {
|
|
157
154
|
if (fs_1.default.existsSync(candidate)) {
|
|
@@ -191,7 +188,7 @@ function waitForSocketReady(socketPath, pid) {
|
|
|
191
188
|
throw new Error(`session startup timeout: socket not ready within ${kStartupTimeoutMs}ms`);
|
|
192
189
|
}
|
|
193
190
|
function resolveDefaultLogRootDir() {
|
|
194
|
-
return
|
|
191
|
+
return (0, default_paths_1.resolveCliLogRootDir)();
|
|
195
192
|
}
|
|
196
193
|
function createSession(options) {
|
|
197
194
|
const runtimePlatform = resolveRuntimePlatform();
|
|
@@ -285,7 +282,8 @@ function killLingeringHostProcesses() {
|
|
|
285
282
|
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) {
|
|
286
283
|
continue;
|
|
287
284
|
}
|
|
288
|
-
if (!command.includes('app-server/bin/tirtc-devtool-host.js')
|
|
285
|
+
if (!command.includes('products/app-server/bin/tirtc-devtool-host.js') &&
|
|
286
|
+
!command.includes('vendor/app-server/bin/tirtc-devtool-host.js')) {
|
|
289
287
|
continue;
|
|
290
288
|
}
|
|
291
289
|
if (!command.includes('--socket /tmp/tirtc-')) {
|
|
@@ -67,6 +67,29 @@ async function runTokenIssue(params, options) {
|
|
|
67
67
|
return printTokenCommandError(error, options);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
async function runLicenseQrcode(params, options) {
|
|
71
|
+
try {
|
|
72
|
+
const result = await (0, token_tool_1.buildLicenseQrcode)(params);
|
|
73
|
+
if (options.json) {
|
|
74
|
+
console.log(JSON.stringify({
|
|
75
|
+
code: 0,
|
|
76
|
+
message: 'OK',
|
|
77
|
+
data: {
|
|
78
|
+
payload: result.payload,
|
|
79
|
+
payloadJson: result.payloadJson,
|
|
80
|
+
qrCodePngPath: result.qrCodePngPath,
|
|
81
|
+
},
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log((0, token_tool_1.formatLicenseQrcodeConsoleOutput)(result));
|
|
86
|
+
}
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return printTokenCommandError(error, options);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
70
93
|
function resolveTokenIssueCredential(explicitValue, envVarName, optionName) {
|
|
71
94
|
const normalizedExplicit = explicitValue?.trim();
|
|
72
95
|
if (normalizedExplicit) {
|
|
@@ -120,6 +143,43 @@ async function runTokenIssueFromCli(peerId, commandOptions, options) {
|
|
|
120
143
|
return printTokenCommandError(error, options);
|
|
121
144
|
}
|
|
122
145
|
}
|
|
146
|
+
async function runLicenseQrcodeFromCli(license, commandOptions, options) {
|
|
147
|
+
const parsePositiveInt = (name, raw) => {
|
|
148
|
+
if (raw === undefined) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
const parsed = Number.parseInt(raw, 10);
|
|
152
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
153
|
+
throw new Error(name + ' must be a positive integer');
|
|
154
|
+
}
|
|
155
|
+
return parsed;
|
|
156
|
+
};
|
|
157
|
+
const parseQrErrorCorrectionLevel = (raw) => {
|
|
158
|
+
if (raw === undefined) {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
const normalized = raw.trim().toUpperCase();
|
|
162
|
+
if (normalized !== 'L' && normalized !== 'M' && normalized !== 'Q' && normalized !== 'H') {
|
|
163
|
+
throw new Error('qr-error-correction-level must be one of: L, M, Q, H');
|
|
164
|
+
}
|
|
165
|
+
return normalized;
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
const normalizedLicense = license.trim();
|
|
169
|
+
if (normalizedLicense.length === 0) {
|
|
170
|
+
throw new Error('license must not be empty');
|
|
171
|
+
}
|
|
172
|
+
return await runLicenseQrcode({
|
|
173
|
+
license: normalizedLicense,
|
|
174
|
+
serviceEntry: commandOptions.serviceEntry,
|
|
175
|
+
qrErrorCorrectionLevel: parseQrErrorCorrectionLevel(commandOptions.qrErrorCorrectionLevel),
|
|
176
|
+
asciiMaxColumns: parsePositiveInt('ascii-max-columns', commandOptions.asciiMaxColumns),
|
|
177
|
+
}, options);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return printTokenCommandError(error, options);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
123
183
|
function registerTokenCommands(program, getCliOptions, runAndExit) {
|
|
124
184
|
const token = program.command('token').description('Token 工具:签发 token,并输出可直接使用的 JSON 与本地二维码 PNG');
|
|
125
185
|
token.command('issue <peer_id>')
|
|
@@ -136,4 +196,13 @@ function registerTokenCommands(program, getCliOptions, runAndExit) {
|
|
|
136
196
|
.action((peerId, commandOptions) => {
|
|
137
197
|
runAndExit(runTokenIssueFromCli(peerId, commandOptions, getCliOptions()));
|
|
138
198
|
});
|
|
199
|
+
const license = program.command('license').description('License 工具:生成 server 扫码 JSON 与本地二维码 PNG');
|
|
200
|
+
license.command('qrcode <license>')
|
|
201
|
+
.description('生成包含 license 与可选 service_entry 的本地二维码')
|
|
202
|
+
.option('--service-entry <entry>', '可选 service entry;留空时消费端走默认值')
|
|
203
|
+
.option('--qr-error-correction-level <level>', '二维码纠错级别:L/M/Q/H;默认 M')
|
|
204
|
+
.option('--ascii-max-columns <columns>', 'ASCII 二维码最大宽度;不传时优先读取当前终端宽度或 COLUMNS')
|
|
205
|
+
.action((licenseValue, commandOptions) => {
|
|
206
|
+
runAndExit(runLicenseQrcodeFromCli(licenseValue, commandOptions, getCliOptions()));
|
|
207
|
+
});
|
|
139
208
|
}
|
|
@@ -30,9 +30,35 @@ export type TokenIssueOutput = {
|
|
|
30
30
|
qrCodeAscii: string;
|
|
31
31
|
qrCodeAsciiIncluded: boolean;
|
|
32
32
|
};
|
|
33
|
+
export type LicenseQrcodeInput = {
|
|
34
|
+
license: string;
|
|
35
|
+
serviceEntry?: string;
|
|
36
|
+
qrErrorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
|
|
37
|
+
asciiMaxColumns?: number;
|
|
38
|
+
};
|
|
39
|
+
export type LicenseQrcodePayload = {
|
|
40
|
+
license: string;
|
|
41
|
+
service_entry: string;
|
|
42
|
+
};
|
|
43
|
+
export type LicenseQrcodeOutput = {
|
|
44
|
+
payload: LicenseQrcodePayload;
|
|
45
|
+
payloadJson: string;
|
|
46
|
+
qrCodePngPath: string;
|
|
47
|
+
qrCodeAscii: string;
|
|
48
|
+
qrCodeAsciiIncluded: boolean;
|
|
49
|
+
};
|
|
50
|
+
export declare function resolveIssueTokenEnvironment(runtimePlatform?: string, fromDir?: string): {
|
|
51
|
+
runtimePlatform: string;
|
|
52
|
+
runtimeBundleRoot: string;
|
|
53
|
+
repoRoot: string;
|
|
54
|
+
addonPath: string;
|
|
55
|
+
};
|
|
33
56
|
export declare function issueToken(input: TokenIssueInput): Promise<string>;
|
|
34
57
|
export declare function buildIssuedTokenPayload(input: TokenIssueInput, token: string): IssuedTokenPayload;
|
|
58
|
+
export declare function buildLicenseQrcodePayload(input: LicenseQrcodeInput): LicenseQrcodePayload;
|
|
35
59
|
export declare function writePngQrcode(payloadJson: string, outputPath: string, errorCorrectionLevel: 'L' | 'M' | 'Q' | 'H'): Promise<string>;
|
|
36
60
|
export declare function buildAsciiQrcode(payloadJson: string, terminalColumns?: number, errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'): Promise<string>;
|
|
37
61
|
export declare function issueTokenWithQrcode(input: TokenIssueInput): Promise<TokenIssueOutput>;
|
|
62
|
+
export declare function buildLicenseQrcode(input: LicenseQrcodeInput): Promise<LicenseQrcodeOutput>;
|
|
38
63
|
export declare function formatTokenIssueConsoleOutput(output: TokenIssueOutput): string;
|
|
64
|
+
export declare function formatLicenseQrcodeConsoleOutput(output: LicenseQrcodeOutput): string;
|