tirtc-devtools-cli 0.0.6 → 0.0.7
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 +1 -1
- package/USAGE.md +4 -2
- package/dist/devtools/cli/src/config.js +2 -2
- package/dist/devtools/cli/src/guide.js +1 -1
- package/dist/devtools/cli/src/index.js +33 -15
- package/dist/devtools/cli/src/progress.d.ts +19 -0
- package/dist/devtools/cli/src/progress.js +63 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
- **唯一用户产品门面**:提供 `tirtc-devtools-cli` 命令族,覆盖常见的 RTC 测试操作,让内部研发、外部开发者和 AI agent 脚本无需手写底层协议。
|
|
14
14
|
- **配置解析与翻译**:负责解析用户传入的 CLI 参数和 TOML 配置文件,进行本地必填校验、脱敏,并翻译为 App Server 协议的 request。
|
|
15
|
-
- **产品级 Observability**:将底层的运行时事件和状态翻译为结构化输出 (JSON)
|
|
15
|
+
- **产品级 Observability**:将底层的运行时事件和状态翻译为结构化输出 (JSON) 或友好的终端日志输出;对长耗时命令补轻量进度提示。
|
|
16
16
|
- **调试期工具内聚**:承接调试期必要工具(如 token bootstrap、二维码与媒体预处理)的产品化入口,避免把调试流程散落在 runtime 或外部手工步骤中。
|
|
17
17
|
- **本地 token 工具**:提供直接签发 token、打印组合 JSON、单独 token 与本地二维码 PNG 路径的公开 CLI 能力,服务本地联调与体验验证。
|
|
18
18
|
|
package/USAGE.md
CHANGED
|
@@ -130,8 +130,8 @@ server-only 正式路径只认 `[server] + [logging]`:
|
|
|
130
130
|
service_entry = ""
|
|
131
131
|
license = "runtime-license"
|
|
132
132
|
mp4_path = "/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.refers/simple.mp4"
|
|
133
|
-
video_stream_id =
|
|
134
|
-
audio_stream_id =
|
|
133
|
+
video_stream_id = 11
|
|
134
|
+
audio_stream_id = 10
|
|
135
135
|
|
|
136
136
|
[logging]
|
|
137
137
|
root_dir = "./.tmp/tirtc-devtools-cli/logging"
|
|
@@ -159,6 +159,8 @@ node devtools/cli/bin/tirtc-devtools-cli.js --config ./server.toml --json servic
|
|
|
159
159
|
4. 自动调用两次 `stream/sendStart`:一次音频、一次视频。
|
|
160
160
|
5. 返回 `autoApplied` 摘要:`preparedAssetsDir`、固定 `mediaSendPolicy=AUTO_ON_CONNECTED`、以及音视频 sendStart 结果。
|
|
161
161
|
|
|
162
|
+
非 `--json` 模式下,CLI 会在 `stderr` 输出轻量进度提示:先显示 MP4 prepare,再显示 service start,避免长时间静默。
|
|
163
|
+
|
|
162
164
|
### 3. 自动发送语义
|
|
163
165
|
|
|
164
166
|
- App Server server 角色固定使用 `AUTO_ON_CONNECTED`。
|
|
@@ -37,8 +37,8 @@ function renderTomlConfigTemplate() {
|
|
|
37
37
|
'# server-only service start 时必填',
|
|
38
38
|
'license = ""',
|
|
39
39
|
'mp4_path = "./source.mp4"',
|
|
40
|
-
'video_stream_id =
|
|
41
|
-
'audio_stream_id =
|
|
40
|
+
'video_stream_id = 11',
|
|
41
|
+
'audio_stream_id = 10',
|
|
42
42
|
'',
|
|
43
43
|
'[connection]',
|
|
44
44
|
'# 作为客户端 connection connect 默认 service_entry(可留空)',
|
|
@@ -16,7 +16,7 @@ function printQuickstartGuide() {
|
|
|
16
16
|
' # 记下输出里的 sessionId,后续命令都显式带 --session',
|
|
17
17
|
'',
|
|
18
18
|
'步骤 2:CLI 会自动 prepare MP4 并绑定音视频 stream,不再需要手工 prepare assets_dir',
|
|
19
|
-
' [server] service_entry = "" license = "<LICENSE>" mp4_path = "./.refers/simple.mp4" video_stream_id =
|
|
19
|
+
' [server] service_entry = "" license = "<LICENSE>" mp4_path = "./.refers/simple.mp4" video_stream_id = 11 audio_stream_id = 10',
|
|
20
20
|
' # service start 成功后会自动 prepare 并按 AUTO_ON_CONNECTED 进入待发流语义',
|
|
21
21
|
'',
|
|
22
22
|
'步骤 3:生成连接 bootstrap 二维码(给安卓扫码)',
|
|
@@ -14,6 +14,7 @@ const session_manager_1 = require("./session_manager");
|
|
|
14
14
|
const media_assets_1 = require("./media_assets");
|
|
15
15
|
const token_command_1 = require("./token_command");
|
|
16
16
|
const transport_1 = require("./transport");
|
|
17
|
+
const progress_1 = require("./progress");
|
|
17
18
|
const CLI_VERSION = '0.0.6';
|
|
18
19
|
const HOST_VERSION = '1.0.0';
|
|
19
20
|
const PROTOCOL_VERSION = '1.0.0';
|
|
@@ -161,6 +162,12 @@ function validateServerConfig(config) {
|
|
|
161
162
|
videoStreamId,
|
|
162
163
|
};
|
|
163
164
|
}
|
|
165
|
+
function createProgressIndicator(options) {
|
|
166
|
+
if (options.json) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
return new progress_1.ProgressIndicator();
|
|
170
|
+
}
|
|
164
171
|
function resolvePrepareOutputRoot(config) {
|
|
165
172
|
const loggingRoot = config.logging?.root_dir?.trim();
|
|
166
173
|
if (loggingRoot && loggingRoot.length > 0) {
|
|
@@ -168,12 +175,14 @@ function resolvePrepareOutputRoot(config) {
|
|
|
168
175
|
}
|
|
169
176
|
return path_1.default.resolve(process.cwd(), '.tmp', 'tirtc-devtools-cli', 'prepared-assets');
|
|
170
177
|
}
|
|
171
|
-
async function applyConfiguredServerBootstrap(client, config) {
|
|
178
|
+
async function applyConfiguredServerBootstrap(client, config, progress) {
|
|
172
179
|
const server = validateServerConfig(config);
|
|
180
|
+
progress?.start('Preparing MP4 assets');
|
|
173
181
|
const prepared = await (0, media_assets_1.prepareMediaAssets)({
|
|
174
182
|
source: server.mp4Path,
|
|
175
183
|
outputRoot: resolvePrepareOutputRoot(config),
|
|
176
184
|
});
|
|
185
|
+
progress?.update('Prepared MP4 assets');
|
|
177
186
|
const bootstrapSendStreams = [
|
|
178
187
|
{ streamId: server.audioStreamId, media: 'audio' },
|
|
179
188
|
{ streamId: server.videoStreamId, media: 'video' },
|
|
@@ -207,20 +216,29 @@ async function runCommand(cmdName, params, options) {
|
|
|
207
216
|
}
|
|
208
217
|
let resultForPrint;
|
|
209
218
|
if (cmdName === 'service start') {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
const progress = createProgressIndicator(options);
|
|
220
|
+
try {
|
|
221
|
+
const autoApplied = await applyConfiguredServerBootstrap(client, config, progress);
|
|
222
|
+
progress?.update('Starting service session');
|
|
223
|
+
const requestParams = {
|
|
224
|
+
...params,
|
|
225
|
+
bootstrapSendStreams: autoApplied.bootstrapSendStreams,
|
|
226
|
+
};
|
|
227
|
+
const result = await client.sendRequest(method, requestParams, 180_000);
|
|
228
|
+
progress?.succeed('Service session is ready');
|
|
229
|
+
const resultObject = toResultObject(result);
|
|
230
|
+
resultForPrint = {
|
|
231
|
+
...resultObject,
|
|
232
|
+
autoApplied,
|
|
233
|
+
};
|
|
234
|
+
printSuccess(options, resultForPrint, session, cmdName);
|
|
235
|
+
transport.stop();
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
progress?.fail('Service start failed');
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
224
242
|
}
|
|
225
243
|
const result = await client.sendRequest(method, params);
|
|
226
244
|
resultForPrint = result;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const SPINNER_INTERVAL_MS = 120;
|
|
2
|
+
type ProgressStream = {
|
|
3
|
+
isTTY?: boolean;
|
|
4
|
+
write(chunk: string): boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare class ProgressIndicator {
|
|
7
|
+
private readonly stream;
|
|
8
|
+
private timer;
|
|
9
|
+
private frameIndex;
|
|
10
|
+
private activeMessage;
|
|
11
|
+
constructor(stream?: ProgressStream);
|
|
12
|
+
start(message: string): void;
|
|
13
|
+
update(message: string): void;
|
|
14
|
+
succeed(message: string): void;
|
|
15
|
+
fail(message: string): void;
|
|
16
|
+
private render;
|
|
17
|
+
private finish;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressIndicator = exports.SPINNER_INTERVAL_MS = void 0;
|
|
4
|
+
const SPINNER_FRAMES = ['|', '/', '-', '\\'];
|
|
5
|
+
exports.SPINNER_INTERVAL_MS = 120;
|
|
6
|
+
function clearLine(text) {
|
|
7
|
+
return `\r\u001b[2K${text}`;
|
|
8
|
+
}
|
|
9
|
+
class ProgressIndicator {
|
|
10
|
+
stream;
|
|
11
|
+
timer;
|
|
12
|
+
frameIndex = 0;
|
|
13
|
+
activeMessage;
|
|
14
|
+
constructor(stream = process.stderr) {
|
|
15
|
+
this.stream = stream;
|
|
16
|
+
}
|
|
17
|
+
start(message) {
|
|
18
|
+
this.activeMessage = message;
|
|
19
|
+
if (this.stream.isTTY) {
|
|
20
|
+
if (this.timer === undefined) {
|
|
21
|
+
this.render();
|
|
22
|
+
this.timer = setInterval(() => {
|
|
23
|
+
this.render();
|
|
24
|
+
}, exports.SPINNER_INTERVAL_MS);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.render();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.stream.write(`${message}...\n`);
|
|
31
|
+
}
|
|
32
|
+
update(message) {
|
|
33
|
+
this.start(message);
|
|
34
|
+
}
|
|
35
|
+
succeed(message) {
|
|
36
|
+
this.finish('OK', message);
|
|
37
|
+
}
|
|
38
|
+
fail(message) {
|
|
39
|
+
this.finish('FAIL', message);
|
|
40
|
+
}
|
|
41
|
+
render() {
|
|
42
|
+
if (this.activeMessage === undefined) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const frame = SPINNER_FRAMES[this.frameIndex % SPINNER_FRAMES.length];
|
|
46
|
+
this.frameIndex += 1;
|
|
47
|
+
this.stream.write(clearLine(`${frame} ${this.activeMessage}...`));
|
|
48
|
+
}
|
|
49
|
+
finish(tag, message) {
|
|
50
|
+
if (this.timer !== undefined) {
|
|
51
|
+
clearInterval(this.timer);
|
|
52
|
+
this.timer = undefined;
|
|
53
|
+
}
|
|
54
|
+
if (this.stream.isTTY) {
|
|
55
|
+
this.stream.write(`${clearLine(`[${tag}] ${message}`)}\n`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.stream.write(`[${tag}] ${message}\n`);
|
|
59
|
+
}
|
|
60
|
+
this.activeMessage = undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.ProgressIndicator = ProgressIndicator;
|