channel-worker 1.0.3 → 1.0.5

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.
@@ -61,12 +61,11 @@ class CommandPoller {
61
61
  }
62
62
 
63
63
  async handleLaunchProfile(command) {
64
- const { profile_id } = command.payload || {};
64
+ const { profile_id, channel_id } = command.payload || {};
65
65
  console.log(`[commands] Launching Nstbrowser profile: ${profile_id}`);
66
66
 
67
67
  try {
68
68
  if (!this.nst) {
69
- // No Nstbrowser SDK — try to get API key from dashboard settings
70
69
  const apiKey = await this.api.getSetting('nst_api_key');
71
70
  if (apiKey) {
72
71
  this.nst = new NstManager(apiKey);
@@ -75,12 +74,21 @@ class CommandPoller {
75
74
  }
76
75
  }
77
76
 
78
- const result = await this.nst.launchProfile(profile_id);
79
- console.log(`[commands] Profile ${profile_id} launched — user can now login via RDP`);
77
+ // Fetch channel proxy if channel_id provided
78
+ let proxy = null;
79
+ if (channel_id) {
80
+ try {
81
+ const channel = await this.api.getChannel(channel_id);
82
+ proxy = channel?.proxy || null;
83
+ } catch { /* ignore */ }
84
+ }
85
+
86
+ const result = await this.nst.launchProfile(profile_id, { proxy });
87
+ console.log(`[commands] Profile ${profile_id} launched${proxy ? ' (proxy: ' + proxy + ')' : ''}`);
80
88
 
81
89
  await this.api.updateCommand(command._id, {
82
90
  status: 'done',
83
- result: { profile_id: result.profileId, launched_at: new Date().toISOString() },
91
+ result: { profile_id: result.profileId, launched_at: new Date().toISOString(), proxy: proxy || null },
84
92
  });
85
93
  } catch (err) {
86
94
  console.error(`[commands] Failed to launch profile: ${err.message}`);
@@ -2,7 +2,7 @@ let NstBrowserV2;
2
2
  try {
3
3
  NstBrowserV2 = require('nstbrowser-sdk-node').NstBrowserV2;
4
4
  } catch {
5
- // SDK not installed — will fail gracefully
5
+ // SDK not installed
6
6
  }
7
7
 
8
8
  class NstManager {
@@ -16,17 +16,40 @@ class NstManager {
16
16
  });
17
17
  }
18
18
 
19
- // Check if profile exists by name, return profileId
19
+ // Get all running browsers
20
+ async getRunningBrowsers() {
21
+ try {
22
+ const res = await this.client.browsers().getBrowsers('running');
23
+ return res?.data || [];
24
+ } catch (err) {
25
+ console.error(`[nst] Error getting running browsers:`, err.message);
26
+ return [];
27
+ }
28
+ }
29
+
30
+ // Check if profile is already running
31
+ async isProfileRunning(profileId) {
32
+ const running = await this.getRunningBrowsers();
33
+ return running.some(b => b.profileId === profileId);
34
+ }
35
+
36
+ // Find profile by name, return profileId
20
37
  async findProfile(name) {
21
38
  try {
22
39
  const res = await this.client.profiles().getProfiles({ keyword: name });
23
- const profiles = res?.data?.docs || res?.data?.list || [];
24
- if (!Array.isArray(profiles)) {
25
- console.log(`[nst] getProfiles response:`, JSON.stringify(res?.data).slice(0, 200));
26
- return null;
40
+ // Response: { data: { docs: [...], totalDocs, ... } }
41
+ let profiles = [];
42
+ if (res?.data?.docs && Array.isArray(res.data.docs)) {
43
+ profiles = res.data.docs;
44
+ } else if (Array.isArray(res?.data)) {
45
+ profiles = res.data;
27
46
  }
47
+
28
48
  const match = profiles.find(p => p.name === name);
29
- return match?.profileId || match?._id || null;
49
+ if (match) {
50
+ return match.profileId || match._id;
51
+ }
52
+ return null;
30
53
  } catch (err) {
31
54
  console.error(`[nst] Error finding profile "${name}":`, err.message);
32
55
  return null;
@@ -35,14 +58,12 @@ class NstManager {
35
58
 
36
59
  // Create profile if not exists, return profileId
37
60
  async ensureProfile(name) {
38
- // Check existing
39
- let profileId = await this.findProfile(name);
40
- if (profileId) {
41
- console.log(`[nst] Profile "${name}" exists: ${profileId}`);
42
- return profileId;
61
+ const existing = await this.findProfile(name);
62
+ if (existing) {
63
+ console.log(`[nst] Profile "${name}" exists: ${existing}`);
64
+ return existing;
43
65
  }
44
66
 
45
- // Create new
46
67
  console.log(`[nst] Creating profile "${name}"...`);
47
68
  const res = await this.client.profiles().createProfile({
48
69
  name,
@@ -61,48 +82,46 @@ class NstManager {
61
82
  },
62
83
  });
63
84
 
64
- profileId = res?.data?.profileId || res?.data?.id;
85
+ const profileId = res?.data?.profileId || res?.data?._id;
65
86
  if (!profileId) throw new Error('Failed to create profile — no ID returned');
66
87
 
67
88
  console.log(`[nst] Profile "${name}" created: ${profileId}`);
68
89
  return profileId;
69
90
  }
70
91
 
71
- // Launch browser for profile (visible, not headless)
72
- async launchProfile(profileIdOrName) {
73
- // If it looks like a name (not UUID), find/create by name
74
- let profileId = profileIdOrName;
75
- if (!this.isUUID(profileIdOrName)) {
76
- profileId = await this.ensureProfile(profileIdOrName);
77
- }
78
-
79
- console.log(`[nst] Starting browser for profile: ${profileId}`);
80
- const res = await this.client.browsers().startBrowser(profileId);
81
- console.log(`[nst] Browser started`);
82
- return { profileId, response: res };
92
+ // Set proxy on profile
93
+ async setProxy(profileId, proxyUrl) {
94
+ if (!proxyUrl) return;
95
+ console.log(`[nst] Setting proxy for ${profileId}: ${proxyUrl}`);
96
+ await this.client.profiles().updateProfileProxy(profileId, { url: proxyUrl });
97
+ console.log(`[nst] Proxy set`);
83
98
  }
84
99
 
85
- // Launch and get CDP WebSocket URL (for automation)
86
- async connectProfile(profileIdOrName) {
100
+ // Launch browser skip if already running, set proxy if provided
101
+ async launchProfile(profileIdOrName, options = {}) {
87
102
  let profileId = profileIdOrName;
88
103
  if (!this.isUUID(profileIdOrName)) {
89
104
  profileId = await this.ensureProfile(profileIdOrName);
90
105
  }
91
106
 
92
- console.log(`[nst] Connecting to profile: ${profileId}`);
93
- const res = await this.client.cdpEndpoints().connectBrowser(profileId, {
94
- headless: false,
95
- autoClose: false,
96
- });
107
+ // Check if already running
108
+ if (await this.isProfileRunning(profileId)) {
109
+ console.log(`[nst] Profile ${profileId} already running — skipping`);
110
+ return { profileId, alreadyRunning: true };
111
+ }
97
112
 
98
- const wsEndpoint = res?.data?.webSocketDebuggerUrl;
99
- if (!wsEndpoint) throw new Error('No WebSocket endpoint returned');
113
+ // Set proxy before launch
114
+ if (options.proxy) {
115
+ await this.setProxy(profileId, options.proxy);
116
+ }
100
117
 
101
- console.log(`[nst] Connected WS: ${wsEndpoint}`);
102
- return { profileId, wsEndpoint };
118
+ console.log(`[nst] Starting browser for profile: ${profileId}`);
119
+ const res = await this.client.browsers().startBrowser(profileId);
120
+ console.log(`[nst] Browser started`);
121
+ return { profileId, response: res };
103
122
  }
104
123
 
105
- // Stop browser for profile
124
+ // Stop browser
106
125
  async stopProfile(profileIdOrName) {
107
126
  let profileId = profileIdOrName;
108
127
  if (!this.isUUID(profileIdOrName)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
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": {