channel-worker 2.3.5 → 2.4.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/lib/api-client.js +7 -0
- package/lib/command-poller.js +52 -3
- package/package.json +1 -1
package/lib/api-client.js
CHANGED
|
@@ -83,6 +83,13 @@ class ApiClient {
|
|
|
83
83
|
return this.request('GET', '/workers/scene-queue-count');
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// ChatGPT subscription dispatch — returns { count, profile_id } so the
|
|
87
|
+
// daemon knows whether to launch a dedicated capture profile (distinct
|
|
88
|
+
// from the Veo3/FlowKit renderers pool).
|
|
89
|
+
async getChatgptQueue() {
|
|
90
|
+
return this.request('GET', '/workers/chatgpt-queue-count');
|
|
91
|
+
}
|
|
92
|
+
|
|
86
93
|
async sceneDispatch(nstProfileId) {
|
|
87
94
|
return this.request('POST', '/workers/scene-dispatch', { nst_profile_id: nstProfileId });
|
|
88
95
|
}
|
package/lib/command-poller.js
CHANGED
|
@@ -31,14 +31,21 @@ class CommandPoller {
|
|
|
31
31
|
this._dispatchTimer = setInterval(() => this._dispatchScenes(), 5000);
|
|
32
32
|
this._dispatching = false;
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
|
|
34
|
+
// ChatGPT-subscription dispatcher — launches the configured profile when
|
|
35
|
+
// a thumbnail command is waiting, independent from the scene renderers pool.
|
|
36
|
+
console.log('[chatgpt-dispatch] Started (every 5s)');
|
|
37
|
+
this._chatgptDispatchTimer = setInterval(() => this._dispatchChatgpt(), 5000);
|
|
38
|
+
this._chatgptDispatching = false;
|
|
39
|
+
|
|
40
|
+
// Profile timeout — close idle profiles after 30s with no work
|
|
41
|
+
this._profileTimeoutTimer = setInterval(() => this._checkProfileTimeouts(), 10000);
|
|
36
42
|
this._profileLastActivity = {}; // { nst_profile_id: timestamp }
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
stop() {
|
|
40
46
|
if (this.timer) { clearInterval(this.timer); this.timer = null; }
|
|
41
47
|
if (this._dispatchTimer) { clearInterval(this._dispatchTimer); this._dispatchTimer = null; }
|
|
48
|
+
if (this._chatgptDispatchTimer) { clearInterval(this._chatgptDispatchTimer); this._chatgptDispatchTimer = null; }
|
|
42
49
|
if (this._profileTimeoutTimer) { clearInterval(this._profileTimeoutTimer); this._profileTimeoutTimer = null; }
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -1234,6 +1241,8 @@ class CommandPoller {
|
|
|
1234
1241
|
const excess = runningRenderers.length - parallelLimit;
|
|
1235
1242
|
const idleRenderers = [];
|
|
1236
1243
|
for (const r of runningRenderers) {
|
|
1244
|
+
// Only daemon-launched profiles are eligible — skip manual launches
|
|
1245
|
+
if (!this._profileLastActivity[r.nst_profile_id]) continue;
|
|
1237
1246
|
try {
|
|
1238
1247
|
const c = await this.api.rendererHasCommands(r.nst_profile_id);
|
|
1239
1248
|
if (c === 0) idleRenderers.push(r);
|
|
@@ -1341,6 +1350,46 @@ class CommandPoller {
|
|
|
1341
1350
|
await this.nst.launchProfile(renderer.nst_profile_id, { proxy: renderer.proxy || null, extensionPath, forceRelaunch: options.forceRelaunch });
|
|
1342
1351
|
}
|
|
1343
1352
|
|
|
1353
|
+
// ─── ChatGPT Subscription Dispatch ─────────────────────────────────────────
|
|
1354
|
+
// Separate dispatcher for the dedicated ChatGPT profile (configured via
|
|
1355
|
+
// Setting: chatgpt_sub_profile_id). Launches the profile on-demand when a
|
|
1356
|
+
// generate_thumbnail command is pending, so Veo3 renderers stay untouched.
|
|
1357
|
+
|
|
1358
|
+
async _dispatchChatgpt() {
|
|
1359
|
+
if (this._chatgptDispatching) return;
|
|
1360
|
+
this._chatgptDispatching = true;
|
|
1361
|
+
try {
|
|
1362
|
+
if (!this.nst) return;
|
|
1363
|
+
const queue = await this.api.getChatgptQueue().catch(() => null);
|
|
1364
|
+
if (!queue || !Array.isArray(queue.profiles) || queue.profiles.length === 0) return;
|
|
1365
|
+
|
|
1366
|
+
let running = [];
|
|
1367
|
+
try { running = await this.nst.getRunningBrowsers(); } catch {}
|
|
1368
|
+
|
|
1369
|
+
for (const item of queue.profiles) {
|
|
1370
|
+
const profileId = item.id;
|
|
1371
|
+
const alreadyRunning = running.some(b =>
|
|
1372
|
+
b.profileId === profileId || (b.name && b.name.toLowerCase() === profileId.toLowerCase()));
|
|
1373
|
+
if (alreadyRunning) {
|
|
1374
|
+
this._profileLastActivity[profileId] = Date.now();
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
console.log(`[chatgpt-dispatch] Launching ${profileId} (pending=${item.pending})`);
|
|
1378
|
+
try {
|
|
1379
|
+
await this._launchRendererProfile({ nst_profile_id: profileId, os: 'windows', proxy: null });
|
|
1380
|
+
this._profileLastActivity[profileId] = Date.now();
|
|
1381
|
+
console.log(`[chatgpt-dispatch] ${profileId} launched`);
|
|
1382
|
+
} catch (err) {
|
|
1383
|
+
console.error(`[chatgpt-dispatch] Failed to launch ${profileId}: ${err.message}`);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
} catch (err) {
|
|
1387
|
+
console.error(`[chatgpt-dispatch] Error: ${err.message}`);
|
|
1388
|
+
} finally {
|
|
1389
|
+
this._chatgptDispatching = false;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1344
1393
|
// ─── Profile Timeout ───────────────────────────────────────────────────────
|
|
1345
1394
|
// Close profiles that have been idle (no commands assigned) for too long.
|
|
1346
1395
|
|
|
@@ -1348,7 +1397,7 @@ class CommandPoller {
|
|
|
1348
1397
|
try {
|
|
1349
1398
|
if (!this.nst) return;
|
|
1350
1399
|
|
|
1351
|
-
const IDLE_TIMEOUT =
|
|
1400
|
+
const IDLE_TIMEOUT = 30 * 1000; // 30s — matches old extension-side behavior
|
|
1352
1401
|
const now = Date.now();
|
|
1353
1402
|
const running = await this.nst.getRunningBrowsers();
|
|
1354
1403
|
if (running.length === 0) return;
|