channel-worker 1.1.8 → 1.2.0
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/bin/cli.js +20 -11
- package/lib/daemon.js +9 -14
- package/lib/nst-manager.js +18 -4
- package/lib/updater.js +93 -0
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -58,7 +58,6 @@ if (cmd === 'pair') {
|
|
|
58
58
|
headers: { 'Content-Type': 'application/json' },
|
|
59
59
|
body: JSON.stringify({
|
|
60
60
|
code,
|
|
61
|
-
ip_address: getLocalIP(),
|
|
62
61
|
max_concurrent: maxConcurrent,
|
|
63
62
|
}),
|
|
64
63
|
});
|
|
@@ -129,6 +128,24 @@ if (cmd === 'pair') {
|
|
|
129
128
|
const daemon = new Daemon(config);
|
|
130
129
|
daemon.start();
|
|
131
130
|
|
|
131
|
+
} else if (cmd === 'update') {
|
|
132
|
+
const { checkAndUpdate, getLocalVersion } = require('../lib/updater');
|
|
133
|
+
console.log(`[channel-worker] Current version: ${getLocalVersion()}`);
|
|
134
|
+
(async () => {
|
|
135
|
+
try {
|
|
136
|
+
const result = await checkAndUpdate({ autoRestart: false });
|
|
137
|
+
if (result.updated) {
|
|
138
|
+
console.log(`[channel-worker] Updated: ${result.local} → ${result.latest}`);
|
|
139
|
+
console.log('[channel-worker] Restart the daemon to use the new version.');
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`[channel-worker] Already up to date (${result.local})`);
|
|
142
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.error(`[channel-worker] Update failed: ${err.message}`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
})();
|
|
148
|
+
|
|
132
149
|
} else if (cmd === 'config') {
|
|
133
150
|
const config = loadConfig();
|
|
134
151
|
// Hide token in display
|
|
@@ -143,7 +160,8 @@ channel-worker — Channel Manager worker daemon
|
|
|
143
160
|
Commands:
|
|
144
161
|
pair Pair with dashboard using a one-time code (recommended)
|
|
145
162
|
init Configure worker manually
|
|
146
|
-
start Start the daemon
|
|
163
|
+
start Start the daemon (auto-checks for updates every 5min)
|
|
164
|
+
update Check and install updates manually
|
|
147
165
|
config Show current config
|
|
148
166
|
|
|
149
167
|
Pairing (recommended):
|
|
@@ -163,12 +181,3 @@ Examples:
|
|
|
163
181
|
`);
|
|
164
182
|
}
|
|
165
183
|
|
|
166
|
-
function getLocalIP() {
|
|
167
|
-
const interfaces = os.networkInterfaces();
|
|
168
|
-
for (const name of Object.keys(interfaces)) {
|
|
169
|
-
for (const iface of interfaces[name]) {
|
|
170
|
-
if (iface.family === 'IPv4' && !iface.internal) return iface.address;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return '127.0.0.1';
|
|
174
|
-
}
|
package/lib/daemon.js
CHANGED
|
@@ -2,7 +2,7 @@ const { ApiClient } = require('./api-client');
|
|
|
2
2
|
const { Heartbeat } = require('./heartbeat');
|
|
3
3
|
const { JobPoller } = require('./job-poller');
|
|
4
4
|
const { CommandPoller } = require('./command-poller');
|
|
5
|
-
const
|
|
5
|
+
const { UpdateChecker, getLocalVersion } = require('./updater');
|
|
6
6
|
|
|
7
7
|
class Daemon {
|
|
8
8
|
constructor(config) {
|
|
@@ -11,12 +11,14 @@ class Daemon {
|
|
|
11
11
|
this.heartbeat = new Heartbeat(this.api, config.worker_id);
|
|
12
12
|
this.poller = new JobPoller(this.api, config);
|
|
13
13
|
this.commandPoller = new CommandPoller(this.api, config);
|
|
14
|
+
this.updateChecker = new UpdateChecker(5 * 60 * 1000); // check every 5min
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
async start() {
|
|
18
|
+
const version = getLocalVersion();
|
|
17
19
|
console.log(`
|
|
18
20
|
╔══════════════════════════════════════╗
|
|
19
|
-
║ channel-worker
|
|
21
|
+
║ channel-worker v${version.padEnd(14)}║
|
|
20
22
|
╠══════════════════════════════════════╣
|
|
21
23
|
║ Worker ID: ${this.config.worker_id.padEnd(22)}║
|
|
22
24
|
║ API URL: ${this.config.api_url.padEnd(22)}║
|
|
@@ -29,7 +31,6 @@ class Daemon {
|
|
|
29
31
|
await this.api.register({
|
|
30
32
|
worker_id: this.config.worker_id,
|
|
31
33
|
name: this.config.worker_id,
|
|
32
|
-
ip_address: this.getLocalIP(),
|
|
33
34
|
max_concurrent: this.config.max_concurrent,
|
|
34
35
|
});
|
|
35
36
|
console.log('[daemon] Registered with dashboard ✓');
|
|
@@ -51,6 +52,10 @@ class Daemon {
|
|
|
51
52
|
// Start command polling
|
|
52
53
|
this.commandPoller.start();
|
|
53
54
|
console.log('[daemon] Command poller started (every 3s)');
|
|
55
|
+
|
|
56
|
+
// Start auto-update checker
|
|
57
|
+
this.updateChecker.start();
|
|
58
|
+
console.log('[daemon] Auto-update checker started (every 5min)');
|
|
54
59
|
console.log('[daemon] Waiting for jobs & commands...\n');
|
|
55
60
|
|
|
56
61
|
// Graceful shutdown
|
|
@@ -59,6 +64,7 @@ class Daemon {
|
|
|
59
64
|
this.heartbeat.stop();
|
|
60
65
|
this.poller.stop();
|
|
61
66
|
this.commandPoller.stop();
|
|
67
|
+
this.updateChecker.stop();
|
|
62
68
|
|
|
63
69
|
// Mark offline
|
|
64
70
|
try {
|
|
@@ -75,17 +81,6 @@ class Daemon {
|
|
|
75
81
|
process.on('SIGTERM', shutdown);
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
getLocalIP() {
|
|
79
|
-
const interfaces = os.networkInterfaces();
|
|
80
|
-
for (const name of Object.keys(interfaces)) {
|
|
81
|
-
for (const iface of interfaces[name]) {
|
|
82
|
-
if (iface.family === 'IPv4' && !iface.internal) {
|
|
83
|
-
return iface.address;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return '127.0.0.1';
|
|
88
|
-
}
|
|
89
84
|
}
|
|
90
85
|
|
|
91
86
|
module.exports = { Daemon };
|
package/lib/nst-manager.js
CHANGED
|
@@ -88,6 +88,7 @@ class NstManager {
|
|
|
88
88
|
},
|
|
89
89
|
hardwareConcurrency: 8,
|
|
90
90
|
deviceMemory: 8,
|
|
91
|
+
language: 'en-US',
|
|
91
92
|
},
|
|
92
93
|
});
|
|
93
94
|
|
|
@@ -119,6 +120,15 @@ class NstManager {
|
|
|
119
120
|
return { profileId, alreadyRunning: true };
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
// Ensure profile language is en-US to prevent auto-translate
|
|
124
|
+
try {
|
|
125
|
+
await this.client.profiles().updateProfile(profileId, {
|
|
126
|
+
fingerprint: { language: 'en-US' },
|
|
127
|
+
});
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.warn(`[nst] Could not update profile language:`, err.message);
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
// Set proxy before launch
|
|
123
133
|
if (options.proxy) {
|
|
124
134
|
await this.setProxy(profileId, options.proxy);
|
|
@@ -129,11 +139,15 @@ class NstManager {
|
|
|
129
139
|
autoClose: false,
|
|
130
140
|
};
|
|
131
141
|
|
|
142
|
+
// Disable Chrome auto-translate
|
|
143
|
+
connectConfig.args = {
|
|
144
|
+
'--lang': 'en-US',
|
|
145
|
+
'--disable-features': 'Translate',
|
|
146
|
+
};
|
|
147
|
+
|
|
132
148
|
if (options.extensionPath) {
|
|
133
|
-
connectConfig.args =
|
|
134
|
-
|
|
135
|
-
'--disable-extensions-except': options.extensionPath,
|
|
136
|
-
};
|
|
149
|
+
connectConfig.args['--load-extension'] = options.extensionPath;
|
|
150
|
+
connectConfig.args['--disable-extensions-except'] = options.extensionPath;
|
|
137
151
|
console.log(`[nst] Loading extension: ${options.extensionPath}`);
|
|
138
152
|
}
|
|
139
153
|
|
package/lib/updater.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const PKG_NAME = 'channel-worker';
|
|
5
|
+
|
|
6
|
+
function getLocalVersion() {
|
|
7
|
+
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
8
|
+
return pkg.version;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function getLatestVersion() {
|
|
12
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`);
|
|
13
|
+
if (!res.ok) throw new Error(`npm registry returned ${res.status}`);
|
|
14
|
+
const data = await res.json();
|
|
15
|
+
return data.version;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isNewer(remote, local) {
|
|
19
|
+
const r = remote.split('.').map(Number);
|
|
20
|
+
const l = local.split('.').map(Number);
|
|
21
|
+
for (let i = 0; i < 3; i++) {
|
|
22
|
+
if (r[i] > l[i]) return true;
|
|
23
|
+
if (r[i] < l[i]) return false;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function installUpdate(version) {
|
|
29
|
+
console.log(`[updater] Installing ${PKG_NAME}@${version}...`);
|
|
30
|
+
execSync(`npm install -g ${PKG_NAME}@${version}`, { stdio: 'inherit' });
|
|
31
|
+
console.log(`[updater] Installed ${PKG_NAME}@${version}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function checkAndUpdate({ autoRestart = false } = {}) {
|
|
35
|
+
const local = getLocalVersion();
|
|
36
|
+
const latest = await getLatestVersion();
|
|
37
|
+
|
|
38
|
+
if (!isNewer(latest, local)) {
|
|
39
|
+
return { updated: false, local, latest };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(`[updater] Update available: ${local} → ${latest}`);
|
|
43
|
+
installUpdate(latest);
|
|
44
|
+
|
|
45
|
+
if (autoRestart) {
|
|
46
|
+
console.log('[updater] Restarting daemon...');
|
|
47
|
+
// Spawn detached process with same args, then exit current
|
|
48
|
+
const { spawn } = require('child_process');
|
|
49
|
+
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
50
|
+
detached: true,
|
|
51
|
+
stdio: 'ignore',
|
|
52
|
+
cwd: process.cwd(),
|
|
53
|
+
});
|
|
54
|
+
child.unref();
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { updated: true, local, latest };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class UpdateChecker {
|
|
62
|
+
constructor(intervalMs = 5 * 60 * 1000) {
|
|
63
|
+
this.intervalMs = intervalMs;
|
|
64
|
+
this.timer = null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
start() {
|
|
68
|
+
// Check on startup after 10s delay
|
|
69
|
+
setTimeout(() => this.check(), 10000);
|
|
70
|
+
// Then periodically
|
|
71
|
+
this.timer = setInterval(() => this.check(), this.intervalMs);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
stop() {
|
|
75
|
+
if (this.timer) {
|
|
76
|
+
clearInterval(this.timer);
|
|
77
|
+
this.timer = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async check() {
|
|
82
|
+
try {
|
|
83
|
+
const result = await checkAndUpdate({ autoRestart: true });
|
|
84
|
+
if (!result.updated) {
|
|
85
|
+
// Silent — only log in verbose or when there's an update
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.warn(`[updater] Check failed: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { checkAndUpdate, getLocalVersion, getLatestVersion, isNewer, UpdateChecker };
|