tirtc-devtools-cli 0.0.1
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 +52 -0
- package/USAGE.md +417 -0
- package/bin/tirtc-devtool.js +2 -0
- package/dist/app-server/protocol-client/index.d.ts +25 -0
- package/dist/app-server/protocol-client/index.js +114 -0
- package/dist/devtools/cli/src/config.d.ts +46 -0
- package/dist/devtools/cli/src/config.js +98 -0
- package/dist/devtools/cli/src/dummy.d.ts +0 -0
- package/dist/devtools/cli/src/dummy.js +1 -0
- package/dist/devtools/cli/src/embedded_paths.d.ts +7 -0
- package/dist/devtools/cli/src/embedded_paths.js +85 -0
- package/dist/devtools/cli/src/facade.d.ts +723 -0
- package/dist/devtools/cli/src/facade.js +194 -0
- package/dist/devtools/cli/src/ffmpeg_tool.d.ts +6 -0
- package/dist/devtools/cli/src/ffmpeg_tool.js +146 -0
- package/dist/devtools/cli/src/guide.d.ts +1 -0
- package/dist/devtools/cli/src/guide.js +49 -0
- package/dist/devtools/cli/src/index.d.ts +1 -0
- package/dist/devtools/cli/src/index.js +753 -0
- package/dist/devtools/cli/src/media_assets.d.ts +25 -0
- package/dist/devtools/cli/src/media_assets.js +121 -0
- package/dist/devtools/cli/src/session_manager.d.ts +25 -0
- package/dist/devtools/cli/src/session_manager.js +393 -0
- package/dist/devtools/cli/src/token_tool.d.ts +33 -0
- package/dist/devtools/cli/src/token_tool.js +217 -0
- package/dist/devtools/cli/src/transport.d.ts +30 -0
- package/dist/devtools/cli/src/transport.js +84 -0
- package/dist/dummy.d.ts +0 -0
- package/dist/dummy.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +48 -0
- package/package.json +54 -0
- package/script/ensure_ffmpeg.sh +22 -0
- package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
- 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/libtgrtc.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 +23 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_frame.h +36 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io.h +56 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_android.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_apple.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_harmony.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_windows.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_processing.h +56 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_sample_rate.h +18 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/error.h +20 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/logging.h +53 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_codec.h +21 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_downlink.h +89 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_uplink.h +115 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/runtime.h +236 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_codec.h +57 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_frame.h +55 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io.h +46 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_android.h +32 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_apple.h +34 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_harmony.h +32 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_windows.h +26 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_processing.h +34 -0
- 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_foundation_logging.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/bin/runtime/linux-x64/lib/libxlog.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/manifest.txt +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +398 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_codec.h +23 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_frame.h +36 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io.h +56 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_android.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_apple.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_harmony.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_windows.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_processing.h +56 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_sample_rate.h +18 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +452 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/credential.h +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +30 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/foundation/build_info.h +27 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/http.h +57 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/logging.h +55 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_codec.h +21 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +95 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_fixture_av_sync.h +61 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_fixture_source.h +77 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_live_source.h +71 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_uplink.h +116 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/transport.h +481 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +541 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_codec.h +58 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_frame.h +55 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io.h +46 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_android.h +32 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_apple.h +47 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_harmony.h +32 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_windows.h +26 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_processing.h +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libcrypto.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libcrypto.dylib +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/lib/libssl.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libssl.dylib +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libwebrtc_apm.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libxlog.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +50 -0
- package/vendor/app-server/bin/tirtc-devtool-host.js +2 -0
- package/vendor/app-server/dist/host/ArtifactManager.d.ts +18 -0
- package/vendor/app-server/dist/host/ArtifactManager.js +83 -0
- package/vendor/app-server/dist/host/HostProtocol.d.ts +107 -0
- package/vendor/app-server/dist/host/HostProtocol.js +256 -0
- package/vendor/app-server/dist/host/HostServer.d.ts +49 -0
- package/vendor/app-server/dist/host/HostServer.js +635 -0
- package/vendor/app-server/dist/host/HostState.d.ts +60 -0
- package/vendor/app-server/dist/host/HostState.js +19 -0
- package/vendor/app-server/dist/host/RuntimeAdapter.d.ts +81 -0
- package/vendor/app-server/dist/host/RuntimeAdapter.js +559 -0
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.d.ts +30 -0
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.js +224 -0
- package/vendor/app-server/dist/host/RuntimeReceiveWorker.d.ts +37 -0
- package/vendor/app-server/dist/host/RuntimeReceiveWorker.js +186 -0
- package/vendor/app-server/dist/host/RuntimeSendWorker.d.ts +42 -0
- package/vendor/app-server/dist/host/RuntimeSendWorker.js +274 -0
- package/vendor/app-server/dist/host/TokenTool.d.ts +15 -0
- package/vendor/app-server/dist/host/TokenTool.js +84 -0
- package/vendor/app-server/dist/host/WebPreviewGateway.d.ts +28 -0
- package/vendor/app-server/dist/host/WebPreviewGateway.js +815 -0
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.d.ts +26 -0
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +118 -0
- package/vendor/app-server/dist/host/native/RuntimeHostBridge.d.ts +19 -0
- package/vendor/app-server/dist/host/native/RuntimeHostBridge.js +141 -0
- package/vendor/app-server/dist/host/runtime_backed_preflight.d.ts +10 -0
- package/vendor/app-server/dist/host/runtime_backed_preflight.js +78 -0
- package/vendor/app-server/dist/host/tests/helpers/host_socket_client.d.ts +28 -0
- package/vendor/app-server/dist/host/tests/helpers/host_socket_client.js +85 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.d.ts +10 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.js +41 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_test_env.d.ts +11 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_test_env.js +32 -0
- package/vendor/app-server/dist/protocol/contract.d.ts +983 -0
- package/vendor/app-server/dist/protocol/contract.js +198 -0
- package/vendor/app-server/dist/protocol-client/index.d.ts +25 -0
- package/vendor/app-server/dist/protocol-client/index.js +114 -0
- package/vendor/app-server/dist/src/index.d.ts +1 -0
- package/vendor/app-server/dist/src/index.js +294 -0
- package/vendor/runtime/script/prepare_runtime_media_dataset.sh +427 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type PrepareMediaAssetsRequest = {
|
|
2
|
+
source: string;
|
|
3
|
+
outputRoot: string;
|
|
4
|
+
outputDir?: string;
|
|
5
|
+
overwrite?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type PrepareMediaAssetsResult = {
|
|
8
|
+
assets_dir: string;
|
|
9
|
+
manifest_path: string;
|
|
10
|
+
cache_hit: boolean;
|
|
11
|
+
};
|
|
12
|
+
type ExecFileLike = (file: string, args: string[], options: {
|
|
13
|
+
cwd: string;
|
|
14
|
+
env: NodeJS.ProcessEnv;
|
|
15
|
+
maxBuffer: number;
|
|
16
|
+
}) => Promise<{
|
|
17
|
+
stdout?: string | Buffer;
|
|
18
|
+
stderr?: string | Buffer;
|
|
19
|
+
}>;
|
|
20
|
+
type PrepareMediaAssetsOptions = {
|
|
21
|
+
repoRoot?: string;
|
|
22
|
+
execFile?: ExecFileLike;
|
|
23
|
+
};
|
|
24
|
+
export declare function prepareMediaAssets(request: PrepareMediaAssetsRequest, options?: PrepareMediaAssetsOptions): Promise<PrepareMediaAssetsResult>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.prepareMediaAssets = prepareMediaAssets;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const util_1 = require("util");
|
|
11
|
+
const embedded_paths_1 = require("./embedded_paths");
|
|
12
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
13
|
+
function resolveRepoRoot(fromDir) {
|
|
14
|
+
const candidates = [
|
|
15
|
+
path_1.default.resolve(fromDir, '../../..'),
|
|
16
|
+
path_1.default.resolve(fromDir, '../../../../..'),
|
|
17
|
+
];
|
|
18
|
+
for (const candidate of candidates) {
|
|
19
|
+
if (fs_1.default.existsSync(path_1.default.join(candidate, 'runtime/script/prepare_runtime_media_dataset.sh'))) {
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return candidates[0];
|
|
24
|
+
}
|
|
25
|
+
function resolveDefaultRepoRoot() {
|
|
26
|
+
const explicitCwd = process.cwd();
|
|
27
|
+
if (fs_1.default.existsSync(path_1.default.join(explicitCwd, 'runtime/script/prepare_runtime_media_dataset.sh'))) {
|
|
28
|
+
return explicitCwd;
|
|
29
|
+
}
|
|
30
|
+
return resolveRepoRoot(__dirname);
|
|
31
|
+
}
|
|
32
|
+
function resolvePrepareScript(repoRoot) {
|
|
33
|
+
const embedded = (0, embedded_paths_1.resolveEmbeddedRuntimeScript)(__dirname);
|
|
34
|
+
if (embedded) {
|
|
35
|
+
return embedded;
|
|
36
|
+
}
|
|
37
|
+
return path_1.default.join(repoRoot, 'runtime/script/prepare_runtime_media_dataset.sh');
|
|
38
|
+
}
|
|
39
|
+
function parseExecError(error) {
|
|
40
|
+
if (!error || typeof error !== 'object') {
|
|
41
|
+
return String(error);
|
|
42
|
+
}
|
|
43
|
+
const typed = error;
|
|
44
|
+
const stderr = typeof typed.stderr === 'string' ? typed.stderr.trim() : typed.stderr?.toString('utf8').trim();
|
|
45
|
+
if (stderr && stderr.length > 0) {
|
|
46
|
+
return stderr;
|
|
47
|
+
}
|
|
48
|
+
const stdout = typeof typed.stdout === 'string' ? typed.stdout.trim() : typed.stdout?.toString('utf8').trim();
|
|
49
|
+
if (stdout && stdout.length > 0) {
|
|
50
|
+
return stdout;
|
|
51
|
+
}
|
|
52
|
+
if (typed.message && typed.message.length > 0) {
|
|
53
|
+
return typed.message;
|
|
54
|
+
}
|
|
55
|
+
return 'process failed';
|
|
56
|
+
}
|
|
57
|
+
function assertPrepareRequest(request) {
|
|
58
|
+
if (!request.source || request.source.trim().length === 0) {
|
|
59
|
+
throw new Error('media assets prepare requires non-empty --source');
|
|
60
|
+
}
|
|
61
|
+
if (!request.outputRoot || request.outputRoot.trim().length === 0) {
|
|
62
|
+
throw new Error('media assets prepare requires non-empty --output-root');
|
|
63
|
+
}
|
|
64
|
+
if (request.outputDir !== undefined && request.outputDir.trim().length === 0) {
|
|
65
|
+
throw new Error('media assets prepare requires non-empty --output-dir when provided');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function prepareMediaAssets(request, options = {}) {
|
|
69
|
+
assertPrepareRequest(request);
|
|
70
|
+
const repoRoot = options.repoRoot ? path_1.default.resolve(options.repoRoot) : resolveDefaultRepoRoot();
|
|
71
|
+
const execFile = options.execFile ?? execFileAsync;
|
|
72
|
+
const scriptPath = resolvePrepareScript(repoRoot);
|
|
73
|
+
if (!fs_1.default.existsSync(scriptPath)) {
|
|
74
|
+
throw new Error('media assets prepare backend missing: ' + scriptPath);
|
|
75
|
+
}
|
|
76
|
+
const ensureFfmpegScriptPath = (0, embedded_paths_1.resolveCliScriptPath)(__dirname, 'script/ensure_ffmpeg.sh');
|
|
77
|
+
if (!fs_1.default.existsSync(ensureFfmpegScriptPath)) {
|
|
78
|
+
throw new Error('ffmpeg bootstrap script missing: ' + ensureFfmpegScriptPath);
|
|
79
|
+
}
|
|
80
|
+
const source = path_1.default.resolve(request.source);
|
|
81
|
+
const outputRoot = path_1.default.resolve(request.outputRoot);
|
|
82
|
+
const args = ['--source', source, '--output-root', outputRoot];
|
|
83
|
+
if (request.outputDir) {
|
|
84
|
+
args.push('--output-dir', path_1.default.resolve(request.outputDir));
|
|
85
|
+
}
|
|
86
|
+
if (request.overwrite) {
|
|
87
|
+
args.push('--overwrite');
|
|
88
|
+
}
|
|
89
|
+
let stdout = '';
|
|
90
|
+
try {
|
|
91
|
+
const result = await execFile('bash', [scriptPath, ...args], {
|
|
92
|
+
cwd: repoRoot,
|
|
93
|
+
env: {
|
|
94
|
+
...process.env,
|
|
95
|
+
TIRTC_ENSURE_FFMPEG_SCRIPT: ensureFfmpegScriptPath,
|
|
96
|
+
},
|
|
97
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
98
|
+
});
|
|
99
|
+
stdout = String(result.stdout ?? '').trim();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw new Error(parseExecError(error));
|
|
103
|
+
}
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(stdout);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
throw new Error('media assets prepare returned malformed json: ' + stdout);
|
|
110
|
+
}
|
|
111
|
+
if (typeof parsed.assets_dir !== 'string' ||
|
|
112
|
+
typeof parsed.manifest_path !== 'string' ||
|
|
113
|
+
typeof parsed.cache_hit !== 'boolean') {
|
|
114
|
+
throw new Error('media assets prepare returned incomplete result');
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
assets_dir: path_1.default.resolve(parsed.assets_dir),
|
|
118
|
+
manifest_path: path_1.default.resolve(parsed.manifest_path),
|
|
119
|
+
cache_hit: parsed.cache_hit,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type SessionRole = 'idle' | 'service' | 'client';
|
|
2
|
+
export type SessionRecord = {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
hostEndpoint: string;
|
|
5
|
+
socketPath: string;
|
|
6
|
+
runtimePlatform: string;
|
|
7
|
+
runtimeBundleRoot: string;
|
|
8
|
+
artifactDir: string;
|
|
9
|
+
logDir: string;
|
|
10
|
+
pid: number;
|
|
11
|
+
startedAt: string;
|
|
12
|
+
role: SessionRole;
|
|
13
|
+
};
|
|
14
|
+
type CreateSessionOptions = {
|
|
15
|
+
logRootDir?: string;
|
|
16
|
+
consoleMirror?: boolean;
|
|
17
|
+
role?: SessionRole;
|
|
18
|
+
};
|
|
19
|
+
export declare function createSession(options?: CreateSessionOptions): SessionRecord;
|
|
20
|
+
export declare function listSessions(): SessionRecord[];
|
|
21
|
+
export declare function stopSession(sessionId: string): SessionRecord;
|
|
22
|
+
export declare function stopAllSessions(): SessionRecord[];
|
|
23
|
+
export declare function resolveSession(sessionId?: string): SessionRecord;
|
|
24
|
+
export declare function setSessionRole(sessionId: string, role: SessionRole): SessionRecord;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createSession = createSession;
|
|
7
|
+
exports.listSessions = listSessions;
|
|
8
|
+
exports.stopSession = stopSession;
|
|
9
|
+
exports.stopAllSessions = stopAllSessions;
|
|
10
|
+
exports.resolveSession = resolveSession;
|
|
11
|
+
exports.setSessionRole = setSessionRole;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const os_1 = __importDefault(require("os"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const crypto_1 = require("crypto");
|
|
16
|
+
const child_process_1 = require("child_process");
|
|
17
|
+
const embedded_paths_1 = require("./embedded_paths");
|
|
18
|
+
const kStartupTimeoutMs = 5000;
|
|
19
|
+
const kStartupPollIntervalMs = 100;
|
|
20
|
+
function ensureDir(dir) {
|
|
21
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
22
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function sleepMs(ms) {
|
|
26
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
27
|
+
}
|
|
28
|
+
function getStateDir() {
|
|
29
|
+
const explicit = process.env.TIRTC_DEVTOOL_STATE_DIR;
|
|
30
|
+
if (explicit && explicit.trim().length > 0) {
|
|
31
|
+
return explicit.trim();
|
|
32
|
+
}
|
|
33
|
+
return path_1.default.join(os_1.default.homedir(), '.tirtc-devtool');
|
|
34
|
+
}
|
|
35
|
+
function getSocketDir() {
|
|
36
|
+
const explicit = process.env.TIRTC_DEVTOOL_SOCKET_DIR;
|
|
37
|
+
if (explicit && explicit.trim().length > 0) {
|
|
38
|
+
return explicit.trim();
|
|
39
|
+
}
|
|
40
|
+
return '/tmp';
|
|
41
|
+
}
|
|
42
|
+
function buildSocketPath(sessionId) {
|
|
43
|
+
const compact = sessionId.replace(/-/g, '').slice(0, 16);
|
|
44
|
+
return path_1.default.join(getSocketDir(), `tirtc-${compact}.sock`);
|
|
45
|
+
}
|
|
46
|
+
function getRegistryPath() {
|
|
47
|
+
return path_1.default.join(getStateDir(), 'sessions.json');
|
|
48
|
+
}
|
|
49
|
+
function loadRegistry() {
|
|
50
|
+
const file = getRegistryPath();
|
|
51
|
+
if (!fs_1.default.existsSync(file)) {
|
|
52
|
+
return { sessions: [] };
|
|
53
|
+
}
|
|
54
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
|
|
55
|
+
return {
|
|
56
|
+
sessions: Array.isArray(parsed.sessions) ? parsed.sessions : [],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function saveRegistry(registry) {
|
|
60
|
+
ensureDir(getStateDir());
|
|
61
|
+
fs_1.default.writeFileSync(getRegistryPath(), JSON.stringify(registry, null, 2));
|
|
62
|
+
}
|
|
63
|
+
function pidAlive(pid) {
|
|
64
|
+
if (!Number.isInteger(pid) || pid <= 1) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
process.kill(pid, 0);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof Error && error.code === 'EPERM') {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function tryUnlink(filePath) {
|
|
79
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
fs_1.default.unlinkSync(filePath);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// no-op
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function socketExists(socketPath) {
|
|
90
|
+
return fs_1.default.existsSync(socketPath);
|
|
91
|
+
}
|
|
92
|
+
function normalizeRole(role) {
|
|
93
|
+
return role === 'service' || role === 'client' ? role : 'idle';
|
|
94
|
+
}
|
|
95
|
+
function purgeDeadSessions(registry) {
|
|
96
|
+
const alive = [];
|
|
97
|
+
for (const session of registry.sessions) {
|
|
98
|
+
if (pidAlive(session.pid) && socketExists(session.socketPath)) {
|
|
99
|
+
alive.push({
|
|
100
|
+
...session,
|
|
101
|
+
role: normalizeRole(session.role),
|
|
102
|
+
});
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
tryUnlink(session.socketPath);
|
|
106
|
+
}
|
|
107
|
+
return { sessions: alive };
|
|
108
|
+
}
|
|
109
|
+
function resolveRuntimePlatform() {
|
|
110
|
+
const raw = process.env.TIRTC_RUNTIME_PLATFORM;
|
|
111
|
+
if (raw && raw.trim().length > 0) {
|
|
112
|
+
return raw.trim();
|
|
113
|
+
}
|
|
114
|
+
if (process.platform === 'darwin' && process.arch === 'arm64') {
|
|
115
|
+
return 'macos-arm64';
|
|
116
|
+
}
|
|
117
|
+
return 'linux-x64';
|
|
118
|
+
}
|
|
119
|
+
function resolveRuntimeBundleRoot(runtimePlatform) {
|
|
120
|
+
const explicit = process.env.TIRTC_RUNTIME_BUNDLE_ROOT;
|
|
121
|
+
if (explicit && explicit.trim().length > 0) {
|
|
122
|
+
return explicit.trim();
|
|
123
|
+
}
|
|
124
|
+
const embedded = (0, embedded_paths_1.resolveEmbeddedRuntimeBundleRoot)(__dirname, runtimePlatform);
|
|
125
|
+
if (embedded) {
|
|
126
|
+
return embedded;
|
|
127
|
+
}
|
|
128
|
+
const execDir = path_1.default.dirname(process.execPath);
|
|
129
|
+
const candidates = [
|
|
130
|
+
path_1.default.resolve(execDir, 'runtime', runtimePlatform),
|
|
131
|
+
path_1.default.resolve(execDir, '../runtime', runtimePlatform),
|
|
132
|
+
path_1.default.resolve(__dirname, '../bin/runtime', runtimePlatform),
|
|
133
|
+
path_1.default.resolve(__dirname, '../../../../bin/runtime', runtimePlatform),
|
|
134
|
+
path_1.default.resolve(process.cwd(), 'bin/runtime', runtimePlatform),
|
|
135
|
+
path_1.default.resolve(process.cwd(), '../bin/runtime', runtimePlatform),
|
|
136
|
+
];
|
|
137
|
+
for (const candidate of candidates) {
|
|
138
|
+
const manifest = path_1.default.join(candidate, 'manifest.txt');
|
|
139
|
+
if (fs_1.default.existsSync(manifest)) {
|
|
140
|
+
return candidate;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return candidates[0];
|
|
144
|
+
}
|
|
145
|
+
function getHostBinaryPath() {
|
|
146
|
+
const embedded = (0, embedded_paths_1.resolveEmbeddedHostBinary)(__dirname);
|
|
147
|
+
if (embedded) {
|
|
148
|
+
return embedded;
|
|
149
|
+
}
|
|
150
|
+
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'),
|
|
155
|
+
];
|
|
156
|
+
for (const candidate of candidates) {
|
|
157
|
+
if (fs_1.default.existsSync(candidate)) {
|
|
158
|
+
return candidate;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return 'tirtc-devtool-host';
|
|
162
|
+
}
|
|
163
|
+
function spawnDetachedHost(env, socketPath, processLogPath) {
|
|
164
|
+
const hostPath = getHostBinaryPath();
|
|
165
|
+
const appServerRoot = hostPath.endsWith('.js') ? path_1.default.resolve(hostPath, '../..') : undefined;
|
|
166
|
+
const hostCmd = hostPath.endsWith('.js') ? process.execPath : hostPath;
|
|
167
|
+
const hostArgs = hostPath.endsWith('.js') ? [hostPath, '--socket', socketPath] : ['--socket', socketPath];
|
|
168
|
+
ensureDir(path_1.default.dirname(processLogPath));
|
|
169
|
+
ensureDir(getSocketDir());
|
|
170
|
+
const outFd = fs_1.default.openSync(processLogPath, 'a');
|
|
171
|
+
return (0, child_process_1.spawn)(hostCmd, hostArgs, {
|
|
172
|
+
env: {
|
|
173
|
+
...env,
|
|
174
|
+
...(appServerRoot ? { TIRTC_APP_SERVER_ROOT: appServerRoot } : {}),
|
|
175
|
+
},
|
|
176
|
+
detached: true,
|
|
177
|
+
stdio: ['ignore', outFd, outFd],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function waitForSocketReady(socketPath, pid) {
|
|
181
|
+
const start = Date.now();
|
|
182
|
+
while (Date.now() - start < kStartupTimeoutMs) {
|
|
183
|
+
if (fs_1.default.existsSync(socketPath)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!pidAlive(pid)) {
|
|
187
|
+
throw new Error('host process exited before socket became ready');
|
|
188
|
+
}
|
|
189
|
+
sleepMs(kStartupPollIntervalMs);
|
|
190
|
+
}
|
|
191
|
+
throw new Error(`session startup timeout: socket not ready within ${kStartupTimeoutMs}ms`);
|
|
192
|
+
}
|
|
193
|
+
function resolveDefaultLogRootDir() {
|
|
194
|
+
return path_1.default.resolve(process.cwd(), '.tmp/tirtc-devtool/logging');
|
|
195
|
+
}
|
|
196
|
+
function createSession(options) {
|
|
197
|
+
const runtimePlatform = resolveRuntimePlatform();
|
|
198
|
+
const runtimeBundleRoot = resolveRuntimeBundleRoot(runtimePlatform);
|
|
199
|
+
const sessionId = (0, crypto_1.randomUUID)();
|
|
200
|
+
const artifactDir = path_1.default.join(os_1.default.tmpdir(), `tirtc-session-${sessionId}`);
|
|
201
|
+
const socketPath = buildSocketPath(sessionId);
|
|
202
|
+
const logRootDir = options?.logRootDir && options.logRootDir.trim().length > 0 ?
|
|
203
|
+
path_1.default.resolve(options.logRootDir) :
|
|
204
|
+
resolveDefaultLogRootDir();
|
|
205
|
+
const logDir = path_1.default.join(logRootDir, sessionId);
|
|
206
|
+
const processLogPath = path_1.default.join(logDir, 'host.process.log');
|
|
207
|
+
const role = normalizeRole(options?.role);
|
|
208
|
+
const registry = purgeDeadSessions(loadRegistry());
|
|
209
|
+
if (role === 'service') {
|
|
210
|
+
const existingService = registry.sessions.find((session) => session.role === 'service');
|
|
211
|
+
if (existingService) {
|
|
212
|
+
saveRegistry(registry);
|
|
213
|
+
throw new Error(`service session already exists: ${existingService.sessionId}; stop it first with "host stop --all" or "host session stop ${existingService.sessionId}"`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
ensureDir(logDir);
|
|
217
|
+
tryUnlink(socketPath);
|
|
218
|
+
const child = spawnDetachedHost({
|
|
219
|
+
...process.env,
|
|
220
|
+
TIRTC_RUNTIME_PLATFORM: runtimePlatform,
|
|
221
|
+
TIRTC_RUNTIME_BUNDLE_ROOT: runtimeBundleRoot,
|
|
222
|
+
TIRTC_HOST_ARTIFACT_DIR: artifactDir,
|
|
223
|
+
TIRTC_HOST_ENDPOINT: `ipc://${socketPath}`,
|
|
224
|
+
TIRTC_HOST_LOG_DIR: logDir,
|
|
225
|
+
TIRTC_HOST_LOG_STDOUT_MIRROR: options?.consoleMirror === false ? '0' : '1',
|
|
226
|
+
}, socketPath, processLogPath);
|
|
227
|
+
const pid = child.pid ?? -1;
|
|
228
|
+
child.unref();
|
|
229
|
+
waitForSocketReady(socketPath, pid);
|
|
230
|
+
const record = {
|
|
231
|
+
sessionId,
|
|
232
|
+
hostEndpoint: `ipc://${socketPath}`,
|
|
233
|
+
socketPath,
|
|
234
|
+
runtimePlatform,
|
|
235
|
+
runtimeBundleRoot,
|
|
236
|
+
artifactDir,
|
|
237
|
+
logDir,
|
|
238
|
+
pid,
|
|
239
|
+
startedAt: new Date().toISOString(),
|
|
240
|
+
role,
|
|
241
|
+
};
|
|
242
|
+
registry.sessions.push(record);
|
|
243
|
+
saveRegistry(registry);
|
|
244
|
+
return record;
|
|
245
|
+
}
|
|
246
|
+
function listSessions() {
|
|
247
|
+
const registry = purgeDeadSessions(loadRegistry());
|
|
248
|
+
saveRegistry(registry);
|
|
249
|
+
return registry.sessions;
|
|
250
|
+
}
|
|
251
|
+
function stopSessionRecord(target) {
|
|
252
|
+
try {
|
|
253
|
+
process.kill(target.pid, 'SIGTERM');
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
// no-op
|
|
257
|
+
}
|
|
258
|
+
sleepMs(100);
|
|
259
|
+
if (pidAlive(target.pid)) {
|
|
260
|
+
try {
|
|
261
|
+
process.kill(target.pid, 'SIGKILL');
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// no-op
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
tryUnlink(target.socketPath);
|
|
268
|
+
}
|
|
269
|
+
function killLingeringHostProcesses() {
|
|
270
|
+
const killed = [];
|
|
271
|
+
try {
|
|
272
|
+
const output = (0, child_process_1.execFileSync)('ps', ['-eo', 'pid=,command='], { encoding: 'utf8' });
|
|
273
|
+
const lines = output.split(/\r?\n/);
|
|
274
|
+
for (const line of lines) {
|
|
275
|
+
const trimmed = line.trim();
|
|
276
|
+
if (trimmed.length === 0) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const match = trimmed.match(/^(\d+)\s+(.+)$/);
|
|
280
|
+
if (!match) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const pid = Number.parseInt(match[1], 10);
|
|
284
|
+
const command = match[2];
|
|
285
|
+
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (!command.includes('app-server/bin/tirtc-devtool-host.js')) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (!command.includes('--socket /tmp/tirtc-')) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
process.kill(pid, 'SIGTERM');
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
// no-op
|
|
299
|
+
}
|
|
300
|
+
if (pidAlive(pid)) {
|
|
301
|
+
try {
|
|
302
|
+
process.kill(pid, 'SIGKILL');
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// no-op
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (!pidAlive(pid)) {
|
|
309
|
+
killed.push(pid);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
// no-op
|
|
315
|
+
}
|
|
316
|
+
return killed;
|
|
317
|
+
}
|
|
318
|
+
function stopSession(sessionId) {
|
|
319
|
+
const registry = purgeDeadSessions(loadRegistry());
|
|
320
|
+
const idx = registry.sessions.findIndex((session) => session.sessionId === sessionId);
|
|
321
|
+
if (idx < 0) {
|
|
322
|
+
throw new Error(`session not found: ${sessionId}`);
|
|
323
|
+
}
|
|
324
|
+
const target = registry.sessions[idx];
|
|
325
|
+
stopSessionRecord(target);
|
|
326
|
+
registry.sessions.splice(idx, 1);
|
|
327
|
+
saveRegistry(registry);
|
|
328
|
+
return target;
|
|
329
|
+
}
|
|
330
|
+
function stopAllSessions() {
|
|
331
|
+
const registry = purgeDeadSessions(loadRegistry());
|
|
332
|
+
const stopped = [];
|
|
333
|
+
for (const session of registry.sessions) {
|
|
334
|
+
stopSessionRecord(session);
|
|
335
|
+
stopped.push(session);
|
|
336
|
+
}
|
|
337
|
+
const lingeringPids = killLingeringHostProcesses();
|
|
338
|
+
for (const pid of lingeringPids) {
|
|
339
|
+
stopped.push({
|
|
340
|
+
sessionId: `orphan-pid-${pid}`,
|
|
341
|
+
hostEndpoint: '',
|
|
342
|
+
socketPath: '',
|
|
343
|
+
runtimePlatform: '',
|
|
344
|
+
runtimeBundleRoot: '',
|
|
345
|
+
artifactDir: '',
|
|
346
|
+
logDir: '',
|
|
347
|
+
pid,
|
|
348
|
+
startedAt: '',
|
|
349
|
+
role: 'idle',
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
saveRegistry({ sessions: [] });
|
|
353
|
+
return stopped;
|
|
354
|
+
}
|
|
355
|
+
function resolveSession(sessionId) {
|
|
356
|
+
const sessions = listSessions();
|
|
357
|
+
if (sessionId && sessionId.trim().length > 0) {
|
|
358
|
+
const found = sessions.find((session) => session.sessionId === sessionId.trim());
|
|
359
|
+
if (!found) {
|
|
360
|
+
throw new Error(`session not found: ${sessionId}`);
|
|
361
|
+
}
|
|
362
|
+
return found;
|
|
363
|
+
}
|
|
364
|
+
if (sessions.length === 1) {
|
|
365
|
+
return sessions[0];
|
|
366
|
+
}
|
|
367
|
+
if (sessions.length === 0) {
|
|
368
|
+
throw new Error('no active session; run "host session start" first');
|
|
369
|
+
}
|
|
370
|
+
throw new Error('multiple active sessions; please specify --session <sessionId>');
|
|
371
|
+
}
|
|
372
|
+
function setSessionRole(sessionId, role) {
|
|
373
|
+
const registry = purgeDeadSessions(loadRegistry());
|
|
374
|
+
const normalizedRole = normalizeRole(role);
|
|
375
|
+
const idx = registry.sessions.findIndex((session) => session.sessionId === sessionId);
|
|
376
|
+
if (idx < 0) {
|
|
377
|
+
throw new Error(`session not found: ${sessionId}`);
|
|
378
|
+
}
|
|
379
|
+
if (normalizedRole === 'service') {
|
|
380
|
+
const existingService = registry.sessions.find((session, index) => index !== idx && session.role === 'service');
|
|
381
|
+
if (existingService) {
|
|
382
|
+
saveRegistry(registry);
|
|
383
|
+
throw new Error(`service session already exists: ${existingService.sessionId}; stop it first with "host stop --all" or "host session stop ${existingService.sessionId}"`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const updated = {
|
|
387
|
+
...registry.sessions[idx],
|
|
388
|
+
role: normalizedRole,
|
|
389
|
+
};
|
|
390
|
+
registry.sessions[idx] = updated;
|
|
391
|
+
saveRegistry(registry);
|
|
392
|
+
return updated;
|
|
393
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type TokenIssueInput = {
|
|
2
|
+
accessId: string;
|
|
3
|
+
secretKey: string;
|
|
4
|
+
localId: string;
|
|
5
|
+
peerId: string;
|
|
6
|
+
openapiEntry?: string;
|
|
7
|
+
serviceEntry?: string;
|
|
8
|
+
userTtlSeconds?: number;
|
|
9
|
+
channelTtlSeconds?: number;
|
|
10
|
+
};
|
|
11
|
+
export type IssuedTokenPayload = {
|
|
12
|
+
version: 1;
|
|
13
|
+
type: 'tirtc-connect-token';
|
|
14
|
+
peer_id: string;
|
|
15
|
+
local_id: string;
|
|
16
|
+
service_entry: string;
|
|
17
|
+
token: string;
|
|
18
|
+
openapi_entry: string;
|
|
19
|
+
user_ttl_seconds: number;
|
|
20
|
+
channel_ttl_seconds: number;
|
|
21
|
+
generated_at: string;
|
|
22
|
+
};
|
|
23
|
+
export type TokenIssueOutput = {
|
|
24
|
+
payload: IssuedTokenPayload;
|
|
25
|
+
payloadJson: string;
|
|
26
|
+
token: string;
|
|
27
|
+
qrCodePngPath: string;
|
|
28
|
+
};
|
|
29
|
+
export declare function issueToken(input: TokenIssueInput): Promise<string>;
|
|
30
|
+
export declare function buildIssuedTokenPayload(input: TokenIssueInput, token: string): IssuedTokenPayload;
|
|
31
|
+
export declare function writePngQrcode(payloadJson: string, outputPath: string): Promise<string>;
|
|
32
|
+
export declare function issueTokenWithQrcode(input: TokenIssueInput): Promise<TokenIssueOutput>;
|
|
33
|
+
export declare function formatTokenIssueConsoleOutput(output: TokenIssueOutput): string;
|