tirtc-devtools-cli 0.0.11 → 0.0.13
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 +85 -13
- package/dist/cli/src/guide.js +4 -3
- package/dist/cli/src/index.js +13 -13
- package/dist/cli/src/token_command.js +39 -31
- package/dist/cli/src/token_tool.d.ts +10 -17
- package/dist/cli/src/token_tool.js +84 -31
- package/package.json +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/error.h +36 -17
- 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/manifest.txt +1 -1
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +39 -316
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +33 -372
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +36 -17
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +47 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +57 -325
- 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 +14 -14
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.d.ts +2 -5
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +2 -5
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
- **产品级 Observability**:将底层的运行时事件和状态翻译为结构化输出 (JSON) 或友好的终端日志输出;对长耗时命令补轻量进度提示。
|
|
21
21
|
- **调试期工具内聚**:承接调试期必要工具(如 token bootstrap、二维码与媒体预处理)的产品化入口,避免把调试流程散落在 runtime 或外部手工步骤中。
|
|
22
22
|
- **本地 token 工具**:提供直接签发 token、打印组合 JSON、单独 token 与本地二维码 PNG 路径的公开 CLI 能力,服务本地联调与体验验证。
|
|
23
|
-
- **本地 license 二维码工具**:提供 server 扫码用的 license JSON 二维码生成能力,支持可选 `
|
|
23
|
+
- **本地 license 二维码工具**:提供 server 扫码用的 license JSON 二维码生成能力,支持可选 `endpoint`。
|
|
24
24
|
|
|
25
25
|
## 不负责什么
|
|
26
26
|
|
package/USAGE.md
CHANGED
|
@@ -70,6 +70,7 @@ node products/cli/bin/tirtc-devtools-cli.js service --help
|
|
|
70
70
|
node products/cli/bin/tirtc-devtools-cli.js stream --help
|
|
71
71
|
node products/cli/bin/tirtc-devtools-cli.js command --help
|
|
72
72
|
node products/cli/bin/tirtc-devtools-cli.js token issue --help
|
|
73
|
+
node products/cli/bin/tirtc-devtools-cli.js license qrcode --help
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
当前关键子菜单快照:
|
|
@@ -96,20 +97,22 @@ Commands:
|
|
|
96
97
|
tail 持续监听命令相关事件
|
|
97
98
|
|
|
98
99
|
$ node ... token issue --help
|
|
100
|
+
Usage: tirtc-devtools-cli token issue [options] <remote_id>
|
|
101
|
+
|
|
99
102
|
Options:
|
|
100
|
-
--access-id <
|
|
101
|
-
--secret-key <
|
|
102
|
-
--
|
|
103
|
-
--openapi-
|
|
104
|
-
--
|
|
105
|
-
--user-ttl-seconds <seconds>
|
|
106
|
-
--channel-ttl-seconds <seconds>
|
|
103
|
+
--access-key-id <accessKeyId>
|
|
104
|
+
--secret-key-id <secretKeyId>
|
|
105
|
+
--app-id <appId>
|
|
106
|
+
--openapi-endpoint <url>
|
|
107
|
+
--endpoint <entry>
|
|
107
108
|
--qr-error-correction-level <level>
|
|
108
109
|
--ascii-max-columns <columns>
|
|
109
110
|
|
|
110
111
|
$ node ... license qrcode --help
|
|
112
|
+
Usage: tirtc-devtools-cli license qrcode [options] <license>
|
|
113
|
+
|
|
111
114
|
Options:
|
|
112
|
-
--
|
|
115
|
+
--endpoint <entry>
|
|
113
116
|
--qr-error-correction-level <level>
|
|
114
117
|
--ascii-max-columns <columns>
|
|
115
118
|
```
|
|
@@ -143,7 +146,6 @@ license = "runtime-license"
|
|
|
143
146
|
mp4_path = "/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.refers/simple.mp4"
|
|
144
147
|
video_stream_id = 11
|
|
145
148
|
audio_stream_id = 10
|
|
146
|
-
|
|
147
149
|
```
|
|
148
150
|
|
|
149
151
|
说明:
|
|
@@ -250,10 +252,80 @@ CLI 仍会在本地收紧最小组合矩阵:
|
|
|
250
252
|
|
|
251
253
|
`command request` 是 canonical 主语,`command send` 只保留为兼容别名。若要发 JSON,请把 JSON 文本作为 `payload` 传入。`command pending list` 用于恢复或轮询当前积压,`command reply` 基于 `remoteRequestId` 显式回复待处理请求。
|
|
252
254
|
|
|
253
|
-
## 十、token / debug / report
|
|
255
|
+
## 十、token / license / debug / report
|
|
256
|
+
|
|
257
|
+
### token issue
|
|
258
|
+
|
|
259
|
+
命令形态:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
export TIRTC_ACCESS_KEY_ID="<ACCESS_KEY_ID>"
|
|
263
|
+
export TIRTC_SECRET_KEY_ID="<SECRET_KEY_ID>"
|
|
264
|
+
export TIRTC_APP_ID="<APP_ID>"
|
|
265
|
+
node products/cli/bin/tirtc-devtools-cli.js --json token issue <REMOTE_ID>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
如果要覆盖默认 endpoint,并显式透传给底层签发路径:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
node products/cli/bin/tirtc-devtools-cli.js --json token issue <REMOTE_ID> \
|
|
272
|
+
--endpoint <ENDPOINT> \
|
|
273
|
+
--openapi-endpoint <OPENAPI_ENDPOINT>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
当前 CLI 合同:
|
|
277
|
+
|
|
278
|
+
- 位置参数改为 `<remote_id>`。
|
|
279
|
+
- `app_id` 必填;可通过 `--app-id` 或 `TIRTC_APP_ID` 提供。
|
|
280
|
+
- `--endpoint` 取代旧 `--service-entry`。
|
|
281
|
+
- `--openapi-endpoint` 取代旧 `--openapi-entry`。
|
|
282
|
+
- 不再接收 `local_id`。
|
|
283
|
+
- 显式传入的 `endpoint` / `openapi_endpoint` 会透传给 C 层签发路径;其中 `app_id` / `endpoint` / `openapi_endpoint` 会进入二维码 payload。
|
|
284
|
+
- 若未显式传入 `endpoint` / `openapi_endpoint`,则 payload 中不再补默认字段。
|
|
285
|
+
|
|
286
|
+
`--json` 输出保持外层 envelope 不变:
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"code": 0,
|
|
291
|
+
"message": "OK",
|
|
292
|
+
"data": {
|
|
293
|
+
"payload": {
|
|
294
|
+
"app_id": "AD_testapp",
|
|
295
|
+
"remote_id": "TESTFENGJUN4",
|
|
296
|
+
"token": "<TOKEN>",
|
|
297
|
+
"endpoint": "http://ep-test-tirtc.tange365.com",
|
|
298
|
+
"openapi_endpoint": "http://api-test-tirtc.tange365.com"
|
|
299
|
+
},
|
|
300
|
+
"payloadJson": "{\"app_id\":\"AD_testapp\",\"remote_id\":\"TESTFENGJUN4\",\"token\":\"<TOKEN>\",\"endpoint\":\"http://ep-test-tirtc.tange365.com\",\"openapi_endpoint\":\"http://api-test-tirtc.tange365.com\"}",
|
|
301
|
+
"token": "<TOKEN>",
|
|
302
|
+
"qrCodePngPath": "/absolute/path/to/token-*.png"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
说明:
|
|
308
|
+
|
|
309
|
+
- payload 只保留 `app_id`、`remote_id`、`token`、可选 `endpoint`、可选 `openapi_endpoint`。
|
|
310
|
+
- 已删除字段不再出现:`version`、`type`、`local_id`、`peer_id`、`openapi_entry`、`service_entry`、`user_ttl_seconds`、`channel_ttl_seconds`、`generated_at`。
|
|
311
|
+
|
|
312
|
+
### license qrcode
|
|
313
|
+
|
|
314
|
+
命令形态:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
node products/cli/bin/tirtc-devtools-cli.js --json license qrcode <LICENSE>
|
|
318
|
+
node products/cli/bin/tirtc-devtools-cli.js --json license qrcode <LICENSE> --endpoint <ENDPOINT>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
当前 CLI 合同:
|
|
322
|
+
|
|
323
|
+
- 只保留 `license` 和可选 `endpoint`。
|
|
324
|
+
- `--endpoint` 取代旧 `--service-entry`。
|
|
325
|
+
- 若未显式传入 `endpoint`,payload 中不再补默认字段。
|
|
326
|
+
|
|
327
|
+
### 其他命令
|
|
254
328
|
|
|
255
|
-
- `token issue <peerId>`:本地签发 token。
|
|
256
|
-
- `license qrcode <license>`:本地生成 server 扫码二维码。
|
|
257
329
|
- `debug bootstrap qrcode ...` / `debug bootstrap qrcode-from-config`:生成联调用二维码。
|
|
258
330
|
- `events tail`:实时查看事件流。
|
|
259
331
|
- `logs export <outputPath>`:导出日志。
|
|
@@ -267,7 +339,7 @@ CLI 仍会在本地收紧最小组合矩阵:
|
|
|
267
339
|
- `client.local.toml` 字段:`[client]` + `[debug.token_issue]`
|
|
268
340
|
- CLI server-only E2E 不再要求先手工 `media assets prepare` 再回填 `assetsDir`
|
|
269
341
|
|
|
270
|
-
##
|
|
342
|
+
## 十二、Android 人工闭环脚本
|
|
271
343
|
|
|
272
344
|
如果需要把 CLI 侧闭环常驻起来,再手工去操作 Android example,使用:
|
|
273
345
|
|
package/dist/cli/src/guide.js
CHANGED
|
@@ -21,9 +21,10 @@ function printQuickstartGuide() {
|
|
|
21
21
|
' # service start 成功后会自动 prepare 并按 AUTO_ON_CONNECTED 进入待发流语义',
|
|
22
22
|
'',
|
|
23
23
|
'步骤 3:显式签发 client token(可本地执行,也可由外部系统提供)',
|
|
24
|
-
' export
|
|
25
|
-
' export
|
|
26
|
-
'
|
|
24
|
+
' export TIRTC_ACCESS_KEY_ID="<ACCESS_KEY_ID>"',
|
|
25
|
+
' export TIRTC_SECRET_KEY_ID="<SECRET_KEY_ID>"',
|
|
26
|
+
' export TIRTC_APP_ID="<APP_ID>"',
|
|
27
|
+
' node products/cli/bin/tirtc-devtools-cli.js --json token issue "<REMOTE_ID>" --endpoint "<ENDPOINT>"',
|
|
27
28
|
'',
|
|
28
29
|
'步骤 4:启动 client 本地 web preview',
|
|
29
30
|
' node products/cli/bin/tirtc-devtools-cli.js --config ./client.toml client start --token "<TOKEN>"',
|
package/dist/cli/src/index.js
CHANGED
|
@@ -11,7 +11,7 @@ const media_assets_1 = require("./media_assets");
|
|
|
11
11
|
const token_command_1 = require("./token_command");
|
|
12
12
|
const transport_1 = require("./transport");
|
|
13
13
|
const progress_1 = require("./progress");
|
|
14
|
-
const CLI_VERSION = '0.0.
|
|
14
|
+
const CLI_VERSION = '0.0.13';
|
|
15
15
|
const HOST_VERSION = '1.0.0';
|
|
16
16
|
const PROTOCOL_VERSION = '1.0.0';
|
|
17
17
|
if (process.argv.includes('--version') || process.argv.includes('-V')) {
|
|
@@ -585,15 +585,15 @@ const debugBootstrap = debug.command('bootstrap').description('连接 bootstrap
|
|
|
585
585
|
debugBootstrap.command('qrcode <access_id> <secret_key> <peer_id> [service_entry]')
|
|
586
586
|
.description('生成客户端连接 bootstrap 二维码(payload 包含 access_id/secret_key/peer_id)')
|
|
587
587
|
.action((accessId, secretKey, peerId, serviceEntry) => {
|
|
588
|
-
const
|
|
589
|
-
version: 1,
|
|
590
|
-
type: 'tirtc-connect-bootstrap',
|
|
588
|
+
const payloadObject = {
|
|
591
589
|
access_id: accessId,
|
|
592
590
|
secret_key: secretKey,
|
|
593
591
|
peer_id: peerId,
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
592
|
+
};
|
|
593
|
+
if (serviceEntry && serviceEntry.length > 0) {
|
|
594
|
+
payloadObject.service_entry = serviceEntry;
|
|
595
|
+
}
|
|
596
|
+
const payload = JSON.stringify(payloadObject);
|
|
597
597
|
runAndExit(runCommand('debug bootstrap qrcode', { payload, outputStem: 'connect-bootstrap' }, getCliOptions()));
|
|
598
598
|
});
|
|
599
599
|
debugBootstrap.command('qrcode-from-config')
|
|
@@ -607,15 +607,15 @@ debugBootstrap.command('qrcode-from-config')
|
|
|
607
607
|
if (!bootstrap.access_id || !bootstrap.secret_key || !bootstrap.peer_id) {
|
|
608
608
|
throw new Error('debug.connect_bootstrap requires access_id + secret_key + peer_id');
|
|
609
609
|
}
|
|
610
|
-
const
|
|
611
|
-
version: 1,
|
|
612
|
-
type: 'tirtc-connect-bootstrap',
|
|
610
|
+
const payloadObject = {
|
|
613
611
|
access_id: bootstrap.access_id,
|
|
614
612
|
secret_key: bootstrap.secret_key,
|
|
615
613
|
peer_id: bootstrap.peer_id,
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
614
|
+
};
|
|
615
|
+
if (bootstrap.service_entry && bootstrap.service_entry.length > 0) {
|
|
616
|
+
payloadObject.service_entry = bootstrap.service_entry;
|
|
617
|
+
}
|
|
618
|
+
const payload = JSON.stringify(payloadObject);
|
|
619
619
|
runAndExit(runCommand('debug bootstrap qrcode', { payload, outputStem: 'connect-bootstrap' }, getCliOptions()));
|
|
620
620
|
});
|
|
621
621
|
const events = program.command('events').description('事件订阅:实时观察 Host 事件');
|
|
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.registerTokenCommands = registerTokenCommands;
|
|
4
4
|
const facade_1 = require("./facade");
|
|
5
5
|
const token_tool_1 = require("./token_tool");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const kTokenIssueAccessKeyIdEnvVar = 'TIRTC_ACCESS_KEY_ID';
|
|
7
|
+
const kTokenIssueSecretKeyIdEnvVar = 'TIRTC_SECRET_KEY_ID';
|
|
8
|
+
const kTokenIssueAppIdEnvVar = 'TIRTC_APP_ID';
|
|
8
9
|
function normalizeTokenCommandError(error) {
|
|
9
10
|
if (error instanceof Error) {
|
|
10
11
|
return {
|
|
@@ -45,7 +46,16 @@ function printTokenCommandError(error, options) {
|
|
|
45
46
|
}
|
|
46
47
|
async function runTokenIssue(params, options) {
|
|
47
48
|
try {
|
|
48
|
-
const result = await (0, token_tool_1.issueTokenWithQrcode)(
|
|
49
|
+
const result = await (0, token_tool_1.issueTokenWithQrcode)({
|
|
50
|
+
accessId: params.accessKeyId,
|
|
51
|
+
secretKey: params.secretKeyId,
|
|
52
|
+
appId: params.appId,
|
|
53
|
+
remoteId: params.remoteId,
|
|
54
|
+
openapiEndpoint: params.openapiEndpoint,
|
|
55
|
+
endpoint: params.endpoint,
|
|
56
|
+
qrErrorCorrectionLevel: params.qrErrorCorrectionLevel,
|
|
57
|
+
asciiMaxColumns: params.asciiMaxColumns,
|
|
58
|
+
});
|
|
49
59
|
if (options.json) {
|
|
50
60
|
console.log(JSON.stringify({
|
|
51
61
|
code: 0,
|
|
@@ -90,7 +100,7 @@ async function runLicenseQrcode(params, options) {
|
|
|
90
100
|
return printTokenCommandError(error, options);
|
|
91
101
|
}
|
|
92
102
|
}
|
|
93
|
-
function
|
|
103
|
+
function resolveRequiredTokenIssueValue(explicitValue, fieldName, envVarName, optionName) {
|
|
94
104
|
const normalizedExplicit = explicitValue?.trim();
|
|
95
105
|
if (normalizedExplicit) {
|
|
96
106
|
return normalizedExplicit;
|
|
@@ -99,10 +109,10 @@ function resolveTokenIssueCredential(explicitValue, envVarName, optionName) {
|
|
|
99
109
|
if (normalizedEnv) {
|
|
100
110
|
return normalizedEnv;
|
|
101
111
|
}
|
|
102
|
-
throw new Error('missing
|
|
112
|
+
throw new Error('missing required ' + fieldName + ': set environment variable ' + envVarName +
|
|
103
113
|
' or pass ' + optionName + ' explicitly');
|
|
104
114
|
}
|
|
105
|
-
async function runTokenIssueFromCli(
|
|
115
|
+
async function runTokenIssueFromCli(remoteId, commandOptions, options) {
|
|
106
116
|
const parsePositiveInt = (name, raw) => {
|
|
107
117
|
if (raw === undefined) {
|
|
108
118
|
return undefined;
|
|
@@ -124,17 +134,16 @@ async function runTokenIssueFromCli(peerId, commandOptions, options) {
|
|
|
124
134
|
return normalized;
|
|
125
135
|
};
|
|
126
136
|
try {
|
|
127
|
-
const
|
|
128
|
-
const
|
|
137
|
+
const accessKeyId = resolveRequiredTokenIssueValue(commandOptions.accessKeyId, 'access_key_id', kTokenIssueAccessKeyIdEnvVar, '--access-key-id');
|
|
138
|
+
const secretKeyId = resolveRequiredTokenIssueValue(commandOptions.secretKeyId, 'secret_key_id', kTokenIssueSecretKeyIdEnvVar, '--secret-key-id');
|
|
139
|
+
const appId = resolveRequiredTokenIssueValue(commandOptions.appId, 'app_id', kTokenIssueAppIdEnvVar, '--app-id');
|
|
129
140
|
return await runTokenIssue({
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
userTtlSeconds: parsePositiveInt('user-ttl-seconds', commandOptions.userTtlSeconds),
|
|
137
|
-
channelTtlSeconds: parsePositiveInt('channel-ttl-seconds', commandOptions.channelTtlSeconds),
|
|
141
|
+
accessKeyId,
|
|
142
|
+
secretKeyId,
|
|
143
|
+
appId,
|
|
144
|
+
remoteId,
|
|
145
|
+
openapiEndpoint: commandOptions.openapiEndpoint,
|
|
146
|
+
endpoint: commandOptions.endpoint,
|
|
138
147
|
qrErrorCorrectionLevel: parseQrErrorCorrectionLevel(commandOptions.qrErrorCorrectionLevel),
|
|
139
148
|
asciiMaxColumns: parsePositiveInt('ascii-max-columns', commandOptions.asciiMaxColumns),
|
|
140
149
|
}, options);
|
|
@@ -169,11 +178,12 @@ async function runLicenseQrcodeFromCli(license, commandOptions, options) {
|
|
|
169
178
|
if (normalizedLicense.length === 0) {
|
|
170
179
|
throw new Error('license must not be empty');
|
|
171
180
|
}
|
|
181
|
+
const asciiMaxColumns = commandOptions.asciiMaxColumns === undefined ? undefined : parsePositiveInt('ascii-max-columns', commandOptions.asciiMaxColumns);
|
|
172
182
|
return await runLicenseQrcode({
|
|
173
183
|
license: normalizedLicense,
|
|
174
|
-
|
|
184
|
+
endpoint: commandOptions.endpoint,
|
|
175
185
|
qrErrorCorrectionLevel: parseQrErrorCorrectionLevel(commandOptions.qrErrorCorrectionLevel),
|
|
176
|
-
asciiMaxColumns
|
|
186
|
+
asciiMaxColumns,
|
|
177
187
|
}, options);
|
|
178
188
|
}
|
|
179
189
|
catch (error) {
|
|
@@ -182,24 +192,22 @@ async function runLicenseQrcodeFromCli(license, commandOptions, options) {
|
|
|
182
192
|
}
|
|
183
193
|
function registerTokenCommands(program, getCliOptions, runAndExit) {
|
|
184
194
|
const token = program.command('token').description('Token 工具:签发 token,并输出可直接使用的 JSON 与本地二维码 PNG');
|
|
185
|
-
token.command('issue <
|
|
186
|
-
.description('默认从环境变量读取
|
|
187
|
-
.option('--access-id <
|
|
188
|
-
.option('--secret-key <
|
|
189
|
-
.option('--
|
|
190
|
-
.option('--openapi-
|
|
191
|
-
.option('--
|
|
192
|
-
.option('--user-ttl-seconds <seconds>', '可选 user token ttl(秒)')
|
|
193
|
-
.option('--channel-ttl-seconds <seconds>', '可选 channel token ttl(秒)')
|
|
195
|
+
token.command('issue <remote_id>')
|
|
196
|
+
.description('默认从环境变量读取 access_key_id / secret_key_id / app_id,并基于 remote_id 签发 token')
|
|
197
|
+
.option('--access-key-id <accessKeyId>', '显式 access_key_id;不传时读取 ' + kTokenIssueAccessKeyIdEnvVar)
|
|
198
|
+
.option('--secret-key-id <secretKeyId>', '显式 secret_key_id;不传时读取 ' + kTokenIssueSecretKeyIdEnvVar)
|
|
199
|
+
.option('--app-id <appId>', '必填 app_id;不传时读取 ' + kTokenIssueAppIdEnvVar)
|
|
200
|
+
.option('--openapi-endpoint <url>', '可选 openapi endpoint;传了就透传到底层签发')
|
|
201
|
+
.option('--endpoint <entry>', '可选 endpoint;传了就写入 payload 与二维码')
|
|
194
202
|
.option('--qr-error-correction-level <level>', '二维码纠错级别:L/M/Q/H;默认 M')
|
|
195
203
|
.option('--ascii-max-columns <columns>', 'ASCII 二维码最大宽度;不传时优先读取当前终端宽度或 COLUMNS')
|
|
196
|
-
.action((
|
|
197
|
-
runAndExit(runTokenIssueFromCli(
|
|
204
|
+
.action((remoteId, commandOptions) => {
|
|
205
|
+
runAndExit(runTokenIssueFromCli(remoteId, commandOptions, getCliOptions()));
|
|
198
206
|
});
|
|
199
207
|
const license = program.command('license').description('License 工具:生成 server 扫码 JSON 与本地二维码 PNG');
|
|
200
208
|
license.command('qrcode <license>')
|
|
201
|
-
.description('生成包含 license 与可选
|
|
202
|
-
.option('--
|
|
209
|
+
.description('生成包含 license 与可选 endpoint 的本地二维码')
|
|
210
|
+
.option('--endpoint <entry>', '可选 endpoint;传了就写入 payload 与二维码')
|
|
203
211
|
.option('--qr-error-correction-level <level>', '二维码纠错级别:L/M/Q/H;默认 M')
|
|
204
212
|
.option('--ascii-max-columns <columns>', 'ASCII 二维码最大宽度;不传时优先读取当前终端宽度或 COLUMNS')
|
|
205
213
|
.action((licenseValue, commandOptions) => {
|
|
@@ -1,26 +1,19 @@
|
|
|
1
1
|
export type TokenIssueInput = {
|
|
2
2
|
accessId: string;
|
|
3
3
|
secretKey: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
userTtlSeconds?: number;
|
|
9
|
-
channelTtlSeconds?: number;
|
|
4
|
+
appId: string;
|
|
5
|
+
remoteId: string;
|
|
6
|
+
openapiEndpoint?: string;
|
|
7
|
+
endpoint?: string;
|
|
10
8
|
qrErrorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
|
|
11
9
|
asciiMaxColumns?: number;
|
|
12
10
|
};
|
|
13
11
|
export type IssuedTokenPayload = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
peer_id: string;
|
|
17
|
-
local_id: string;
|
|
18
|
-
service_entry: string;
|
|
12
|
+
app_id: string;
|
|
13
|
+
remote_id: string;
|
|
19
14
|
token: string;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
channel_ttl_seconds: number;
|
|
23
|
-
generated_at: string;
|
|
15
|
+
endpoint?: string;
|
|
16
|
+
openapi_endpoint?: string;
|
|
24
17
|
};
|
|
25
18
|
export type TokenIssueOutput = {
|
|
26
19
|
payload: IssuedTokenPayload;
|
|
@@ -32,13 +25,13 @@ export type TokenIssueOutput = {
|
|
|
32
25
|
};
|
|
33
26
|
export type LicenseQrcodeInput = {
|
|
34
27
|
license: string;
|
|
35
|
-
|
|
28
|
+
endpoint?: string;
|
|
36
29
|
qrErrorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
|
|
37
30
|
asciiMaxColumns?: number;
|
|
38
31
|
};
|
|
39
32
|
export type LicenseQrcodePayload = {
|
|
40
33
|
license: string;
|
|
41
|
-
|
|
34
|
+
endpoint?: string;
|
|
42
35
|
};
|
|
43
36
|
export type LicenseQrcodeOutput = {
|
|
44
37
|
payload: LicenseQrcodePayload;
|
|
@@ -51,9 +51,6 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
51
51
|
const path_1 = __importDefault(require("path"));
|
|
52
52
|
const qrcode_1 = __importDefault(require("qrcode"));
|
|
53
53
|
const embedded_paths_1 = require("./embedded_paths");
|
|
54
|
-
const kDefaultOpenapiEntry = 'http://api-test-tirtc.tange365.com';
|
|
55
|
-
const kDefaultUserTtlSeconds = 86400;
|
|
56
|
-
const kDefaultChannelTtlSeconds = 300;
|
|
57
54
|
const kAsciiQrQuietZoneModules = 2;
|
|
58
55
|
function pathExists(filePath) {
|
|
59
56
|
return fs_1.default.existsSync(filePath);
|
|
@@ -76,7 +73,7 @@ function buildQrCodePngPath(prefix, ...parts) {
|
|
|
76
73
|
return path_1.default.join(resolveQrCodeOutputDir(), fileName);
|
|
77
74
|
}
|
|
78
75
|
function buildTokenQrCodePngPath(payload) {
|
|
79
|
-
return buildQrCodePngPath('token', payload.
|
|
76
|
+
return buildQrCodePngPath('token', payload.remote_id);
|
|
80
77
|
}
|
|
81
78
|
function buildLicenseQrCodePngPath(payload) {
|
|
82
79
|
return buildQrCodePngPath('license', payload.license);
|
|
@@ -206,13 +203,10 @@ function buildIssueTokenHelperSource() {
|
|
|
206
203
|
'});',
|
|
207
204
|
'try {',
|
|
208
205
|
' const token = addon.issueToken({',
|
|
209
|
-
'
|
|
206
|
+
' openapiEndpoint: input.openapiEndpoint,',
|
|
210
207
|
' accessId: input.accessId,',
|
|
211
208
|
' secretKey: input.secretKey,',
|
|
212
|
-
'
|
|
213
|
-
' peerId: input.peerId,',
|
|
214
|
-
' userTtlSeconds: input.userTtlSeconds,',
|
|
215
|
-
' channelTtlSeconds: input.channelTtlSeconds,',
|
|
209
|
+
' remoteId: input.remoteId,',
|
|
216
210
|
' });',
|
|
217
211
|
' process.stdout.write(String(token).trim());',
|
|
218
212
|
'} finally {',
|
|
@@ -220,6 +214,62 @@ function buildIssueTokenHelperSource() {
|
|
|
220
214
|
'}',
|
|
221
215
|
].join('\n');
|
|
222
216
|
}
|
|
217
|
+
function parseIssueTokenFailure(message) {
|
|
218
|
+
const matched = message.match(/issue token failed error=(\d+) http_status=(\d+)/i);
|
|
219
|
+
if (!matched) {
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
const errorCode = Number.parseInt(matched[1] ?? '', 10);
|
|
223
|
+
const httpStatus = Number.parseInt(matched[2] ?? '', 10);
|
|
224
|
+
return {
|
|
225
|
+
errorCode: Number.isNaN(errorCode) ? undefined : errorCode,
|
|
226
|
+
httpStatus: Number.isNaN(httpStatus) ? undefined : httpStatus,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function isNodeStackNoise(line) {
|
|
230
|
+
return line.startsWith('[eval]:') ||
|
|
231
|
+
line.startsWith('at [eval]') ||
|
|
232
|
+
line.startsWith('at runScriptInThisContext') ||
|
|
233
|
+
line.startsWith('at node:internal/') ||
|
|
234
|
+
line.startsWith('Node.js v');
|
|
235
|
+
}
|
|
236
|
+
function sanitizeIssueTokenFailureText(message) {
|
|
237
|
+
const lines = message
|
|
238
|
+
.split(/\r?\n/)
|
|
239
|
+
.map((line) => line.trim())
|
|
240
|
+
.filter((line) => line.length > 0 && !isNodeStackNoise(line));
|
|
241
|
+
const collapsed = lines.join(' | ');
|
|
242
|
+
if (collapsed.length === 0) {
|
|
243
|
+
return 'token issuing failed';
|
|
244
|
+
}
|
|
245
|
+
return collapsed;
|
|
246
|
+
}
|
|
247
|
+
function formatIssueTokenFailureMessage(message) {
|
|
248
|
+
const parsed = parseIssueTokenFailure(message);
|
|
249
|
+
const detail = sanitizeIssueTokenFailureText(message);
|
|
250
|
+
if (parsed.httpStatus === 200 && parsed.errorCode === 3) {
|
|
251
|
+
return [
|
|
252
|
+
'token issuing failed: remote service rejected the request.',
|
|
253
|
+
'Check whether remote_id, access_key_id, secret_key_id, and openapi-endpoint are correct.',
|
|
254
|
+
'detail: error=3 http_status=200',
|
|
255
|
+
].join(' ');
|
|
256
|
+
}
|
|
257
|
+
if (parsed.httpStatus !== undefined || parsed.errorCode !== undefined) {
|
|
258
|
+
const detailParts = [];
|
|
259
|
+
if (parsed.errorCode !== undefined) {
|
|
260
|
+
detailParts.push('error=' + parsed.errorCode);
|
|
261
|
+
}
|
|
262
|
+
if (parsed.httpStatus !== undefined) {
|
|
263
|
+
detailParts.push('http_status=' + parsed.httpStatus);
|
|
264
|
+
}
|
|
265
|
+
return [
|
|
266
|
+
'token issuing failed: remote authentication request was not accepted.',
|
|
267
|
+
'Check whether remote_id, access_key_id, secret_key_id, and openapi-endpoint are correct.',
|
|
268
|
+
'detail: ' + detailParts.join(' '),
|
|
269
|
+
].join(' ');
|
|
270
|
+
}
|
|
271
|
+
return 'token issuing failed: ' + detail;
|
|
272
|
+
}
|
|
223
273
|
function issueTokenViaSubprocess(addonPath, input) {
|
|
224
274
|
const result = childProcess.spawnSync(process.execPath, ['-e', buildIssueTokenHelperSource()], {
|
|
225
275
|
encoding: 'utf8',
|
|
@@ -235,7 +285,7 @@ function issueTokenViaSubprocess(addonPath, input) {
|
|
|
235
285
|
}
|
|
236
286
|
if (result.status !== 0) {
|
|
237
287
|
const details = String(result.stderr || result.stdout || 'issue token subprocess failed').trim();
|
|
238
|
-
throw new Error(details || 'issue token subprocess failed');
|
|
288
|
+
throw new Error(formatIssueTokenFailureMessage(details || 'issue token subprocess failed'));
|
|
239
289
|
}
|
|
240
290
|
return normalizeIssuedToken(String(result.stdout || ''));
|
|
241
291
|
}
|
|
@@ -301,28 +351,34 @@ async function issueToken(input) {
|
|
|
301
351
|
}
|
|
302
352
|
catch (error) {
|
|
303
353
|
const message = error instanceof Error ? error.message : String(error);
|
|
304
|
-
throw new Error(
|
|
354
|
+
throw new Error(message);
|
|
305
355
|
}
|
|
306
356
|
}
|
|
307
357
|
function buildIssuedTokenPayload(input, token) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
peer_id: input.peerId,
|
|
312
|
-
local_id: input.localId,
|
|
313
|
-
service_entry: input.serviceEntry ?? '',
|
|
358
|
+
const payload = {
|
|
359
|
+
app_id: input.appId.trim(),
|
|
360
|
+
remote_id: input.remoteId,
|
|
314
361
|
token,
|
|
315
|
-
openapi_entry: input.openapiEntry?.trim() || kDefaultOpenapiEntry,
|
|
316
|
-
user_ttl_seconds: input.userTtlSeconds ?? kDefaultUserTtlSeconds,
|
|
317
|
-
channel_ttl_seconds: input.channelTtlSeconds ?? kDefaultChannelTtlSeconds,
|
|
318
|
-
generated_at: new Date().toISOString(),
|
|
319
362
|
};
|
|
363
|
+
const normalizedEndpoint = input.endpoint?.trim();
|
|
364
|
+
if (normalizedEndpoint) {
|
|
365
|
+
payload.endpoint = normalizedEndpoint;
|
|
366
|
+
}
|
|
367
|
+
const normalizedOpenapiEndpoint = input.openapiEndpoint?.trim();
|
|
368
|
+
if (normalizedOpenapiEndpoint) {
|
|
369
|
+
payload.openapi_endpoint = normalizedOpenapiEndpoint;
|
|
370
|
+
}
|
|
371
|
+
return payload;
|
|
320
372
|
}
|
|
321
373
|
function buildLicenseQrcodePayload(input) {
|
|
322
|
-
|
|
374
|
+
const payload = {
|
|
323
375
|
license: input.license.trim(),
|
|
324
|
-
service_entry: input.serviceEntry?.trim() ?? '',
|
|
325
376
|
};
|
|
377
|
+
const normalizedEndpoint = input.endpoint?.trim();
|
|
378
|
+
if (normalizedEndpoint) {
|
|
379
|
+
payload.endpoint = normalizedEndpoint;
|
|
380
|
+
}
|
|
381
|
+
return payload;
|
|
326
382
|
}
|
|
327
383
|
async function writePngQrcode(payloadJson, outputPath, errorCorrectionLevel) {
|
|
328
384
|
const resolvedPath = path_1.default.resolve(outputPath);
|
|
@@ -382,13 +438,10 @@ async function buildLicenseQrcode(input) {
|
|
|
382
438
|
function formatTokenIssueConsoleOutput(output) {
|
|
383
439
|
const summaryLines = [
|
|
384
440
|
'Issued Token Summary:',
|
|
385
|
-
'
|
|
386
|
-
'
|
|
387
|
-
'
|
|
388
|
-
'
|
|
389
|
-
' user_ttl_seconds: ' + output.payload.user_ttl_seconds,
|
|
390
|
-
' channel_ttl_seconds: ' + output.payload.channel_ttl_seconds,
|
|
391
|
-
' generated_at: ' + output.payload.generated_at,
|
|
441
|
+
' app_id: ' + output.payload.app_id,
|
|
442
|
+
' remote_id: ' + output.payload.remote_id,
|
|
443
|
+
' endpoint: ' + (output.payload.endpoint ?? '(omitted)'),
|
|
444
|
+
' openapi_endpoint: ' + (output.payload.openapi_endpoint ?? '(omitted)'),
|
|
392
445
|
'',
|
|
393
446
|
'Token:',
|
|
394
447
|
output.token,
|
|
@@ -408,7 +461,7 @@ function formatLicenseQrcodeConsoleOutput(output) {
|
|
|
408
461
|
const summaryLines = [
|
|
409
462
|
'License QR Code Summary:',
|
|
410
463
|
' license: ' + output.payload.license,
|
|
411
|
-
'
|
|
464
|
+
' endpoint: ' + (output.payload.endpoint ?? '(omitted)'),
|
|
412
465
|
'',
|
|
413
466
|
'Payload JSON:',
|
|
414
467
|
JSON.stringify(output.payload, null, 2),
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -7,25 +7,44 @@ extern "C" {
|
|
|
7
7
|
|
|
8
8
|
typedef enum TirtcError {
|
|
9
9
|
TIRTC_ERROR_OK = 0,
|
|
10
|
-
TIRTC_ERROR_INVALID_ARGUMENT =
|
|
11
|
-
TIRTC_ERROR_NOT_INITIALIZED =
|
|
12
|
-
TIRTC_ERROR_INTERNAL =
|
|
13
|
-
TIRTC_ERROR_NOT_READY =
|
|
14
|
-
TIRTC_ERROR_UNSUPPORTED_LOOP_POLICY =
|
|
15
|
-
TIRTC_ERROR_SOURCE_HASH_MISMATCH =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
TIRTC_ERROR_INVALID_ARGUMENT = 6000,
|
|
11
|
+
TIRTC_ERROR_NOT_INITIALIZED = 6001,
|
|
12
|
+
TIRTC_ERROR_INTERNAL = 6002,
|
|
13
|
+
TIRTC_ERROR_NOT_READY = 6003,
|
|
14
|
+
TIRTC_ERROR_UNSUPPORTED_LOOP_POLICY = 6004,
|
|
15
|
+
TIRTC_ERROR_SOURCE_HASH_MISMATCH = 6005,
|
|
16
|
+
TIRTC_ERROR_ALREADY_STOPPED = 6006,
|
|
17
|
+
TIRTC_ERROR_STOPPED = TIRTC_ERROR_ALREADY_STOPPED,
|
|
18
|
+
TIRTC_ERROR_ALREADY_DESTROYED = 6007,
|
|
19
|
+
TIRTC_ERROR_DESTROYED = TIRTC_ERROR_ALREADY_DESTROYED,
|
|
20
|
+
TIRTC_ERROR_TRANSPORT_INVALID_LICENSE = 6008,
|
|
21
|
+
TIRTC_ERROR_TRANSPORT_TIMEOUT = 6009,
|
|
22
|
+
TIRTC_ERROR_TRANSPORT_BUSY = 6010,
|
|
23
|
+
TIRTC_ERROR_TRANSPORT_CONNECTION_TIMEOUT_CLOSED = 6011,
|
|
24
|
+
TIRTC_ERROR_TRANSPORT_REMOTE_CLOSED = 6012,
|
|
25
|
+
TIRTC_ERROR_TRANSPORT_CONNECTION_OTHER_ERROR = 6013,
|
|
26
|
+
TIRTC_ERROR_TRANSPORT_TOKEN_EXPIRED = 6014,
|
|
27
|
+
TIRTC_ERROR_DUMP_ROOT_UNAVAILABLE = 6015,
|
|
28
|
+
TIRTC_ERROR_DUMP_ALREADY_ACTIVE = 6016,
|
|
29
|
+
TIRTC_ERROR_TRANSPORT_RESOURCE_EXHAUSTED = 6017,
|
|
30
|
+
TIRTC_ERROR_TRANSPORT_SERVER_ERROR = 6018,
|
|
31
|
+
TIRTC_ERROR_TRANSPORT_BACKEND_INTERNAL_ERROR = 6019,
|
|
32
|
+
TIRTC_ERROR_TRANSPORT_NO_SECRET_KEY = 6020,
|
|
33
|
+
TIRTC_ERROR_TRANSPORT_UNEXPECTED_RESPONSE = 6021,
|
|
34
|
+
TIRTC_ERROR_ALREADY_INITIALIZED = 6022,
|
|
35
|
+
TIRTC_ERROR_INVALID_THREAD = 6023,
|
|
36
|
+
TIRTC_ERROR_PERMISSION_DENIED = 6024,
|
|
37
|
+
TIRTC_ERROR_ALREADY_BOUND = 6025,
|
|
38
|
+
TIRTC_ERROR_IN_USE = 6026,
|
|
39
|
+
TIRTC_ERROR_NOT_STARTED = 6027,
|
|
40
|
+
TIRTC_ERROR_NOT_CONNECTED = 6028,
|
|
41
|
+
TIRTC_ERROR_NOT_BOUND = 6029,
|
|
42
|
+
TIRTC_ERROR_NOT_CONFIGURED = 6030,
|
|
43
|
+
TIRTC_ERROR_NOT_OPEN = 6031,
|
|
27
44
|
} TirtcError;
|
|
28
45
|
|
|
46
|
+
const char* tirtc_error_to_string(TirtcError error);
|
|
47
|
+
|
|
29
48
|
#ifdef __cplusplus
|
|
30
49
|
}
|
|
31
50
|
#endif
|