channel-worker 2.4.1 → 2.4.3

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 CHANGED
@@ -90,6 +90,11 @@ class ApiClient {
90
90
  return this.request('GET', '/workers/chatgpt-queue-count');
91
91
  }
92
92
 
93
+ // Report local Nstbrowser profile list to API so the UI can show a picker.
94
+ async reportNstProfiles(workerId, profiles) {
95
+ return this.request('POST', '/workers/nst-profiles', { worker_id: workerId, profiles });
96
+ }
97
+
93
98
  async sceneDispatch(nstProfileId) {
94
99
  return this.request('POST', '/workers/scene-dispatch', { nst_profile_id: nstProfileId });
95
100
  }
@@ -37,6 +37,13 @@ class CommandPoller {
37
37
  this._chatgptDispatchTimer = setInterval(() => this._dispatchChatgpt(), 5000);
38
38
  this._chatgptDispatching = false;
39
39
 
40
+ // Profile syncer — report local Nstbrowser profile list to API every 60s
41
+ // so the web UI can render a multi-select picker (e.g. for choosing
42
+ // chatgpt_sub profiles).
43
+ console.log('[profile-sync] Started (every 60s)');
44
+ this._syncProfiles().catch(() => {});
45
+ this._profileSyncTimer = setInterval(() => this._syncProfiles().catch(() => {}), 60000);
46
+
40
47
  // Profile timeout — close idle profiles after 30s with no work
41
48
  this._profileTimeoutTimer = setInterval(() => this._checkProfileTimeouts(), 10000);
42
49
  this._profileLastActivity = {}; // { nst_profile_id: timestamp }
@@ -46,6 +53,7 @@ class CommandPoller {
46
53
  if (this.timer) { clearInterval(this.timer); this.timer = null; }
47
54
  if (this._dispatchTimer) { clearInterval(this._dispatchTimer); this._dispatchTimer = null; }
48
55
  if (this._chatgptDispatchTimer) { clearInterval(this._chatgptDispatchTimer); this._chatgptDispatchTimer = null; }
56
+ if (this._profileSyncTimer) { clearInterval(this._profileSyncTimer); this._profileSyncTimer = null; }
49
57
  if (this._profileTimeoutTimer) { clearInterval(this._profileTimeoutTimer); this._profileTimeoutTimer = null; }
50
58
  }
51
59
 
@@ -1359,7 +1367,15 @@ class CommandPoller {
1359
1367
  if (this._chatgptDispatching) return;
1360
1368
  this._chatgptDispatching = true;
1361
1369
  try {
1362
- if (!this.nst) return;
1370
+ // Lazy-init NstManager — the daemon config often ships with an empty
1371
+ // nst_api_key and relies on fetching it from the user's settings.
1372
+ if (!this.nst) {
1373
+ try {
1374
+ const apiKey = await this.api.getSetting('nst_api_key');
1375
+ if (apiKey) this.nst = new NstManager(apiKey);
1376
+ } catch {}
1377
+ if (!this.nst) return;
1378
+ }
1363
1379
  const queue = await this.api.getChatgptQueue().catch(() => null);
1364
1380
  if (!queue || !Array.isArray(queue.profiles) || queue.profiles.length === 0) return;
1365
1381
 
@@ -1390,6 +1406,26 @@ class CommandPoller {
1390
1406
  }
1391
1407
  }
1392
1408
 
1409
+ // ─── Profile sync — report local Nstbrowser profile list to API ──────────
1410
+ async _syncProfiles() {
1411
+ try {
1412
+ if (!this.nst) {
1413
+ try {
1414
+ const apiKey = await this.api.getSetting('nst_api_key');
1415
+ if (apiKey) this.nst = new NstManager(apiKey);
1416
+ } catch {}
1417
+ if (!this.nst) return;
1418
+ }
1419
+ const profiles = await this.nst.listAllProfiles();
1420
+ if (!profiles || profiles.length === 0) return;
1421
+ await this.api.reportNstProfiles(this.config.worker_id, profiles).catch((e) => {
1422
+ if (this.config.verbose) console.warn('[profile-sync] report failed:', e.message);
1423
+ });
1424
+ } catch (err) {
1425
+ if (this.config.verbose) console.warn('[profile-sync]', err.message);
1426
+ }
1427
+ }
1428
+
1393
1429
  // ─── Profile Timeout ───────────────────────────────────────────────────────
1394
1430
  // Close profiles that have been idle (no commands assigned) for too long.
1395
1431
 
@@ -17,6 +17,31 @@ class NstManager {
17
17
  return res.json();
18
18
  }
19
19
 
20
+ // List ALL profiles (not just running). Used by daemon heartbeat to report
21
+ // available profiles up to the API so the dashboard can show a picker.
22
+ async listAllProfiles() {
23
+ try {
24
+ let all = [];
25
+ let page = 1;
26
+ while (true) {
27
+ const res = await this.api(`/profiles/?page=${page}&limit=100`);
28
+ const docs = res?.data?.docs || res?.data || [];
29
+ all = all.concat(docs);
30
+ const totalPages = res?.data?.totalPage || res?.data?.totalPages || 1;
31
+ if (page >= totalPages || docs.length === 0) break;
32
+ page++;
33
+ }
34
+ return all.map(p => ({
35
+ profile_id: p.profileId || p._id,
36
+ name: p.name || '',
37
+ platform: p.platform || '',
38
+ }));
39
+ } catch (err) {
40
+ console.warn(`[nst] listAllProfiles: ${err.message}`);
41
+ return [];
42
+ }
43
+ }
44
+
20
45
  // Get all running browsers
21
46
  async getRunningBrowsers() {
22
47
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {