channel-worker 1.3.8 → 1.4.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 +81 -4
- package/lib/api-client.js +5 -2
- package/lib/daemon.js +1 -1
- package/lib/heartbeat.js +8 -2
- package/lib/updater.js +21 -5
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -128,9 +128,32 @@ if (cmd === 'pair') {
|
|
|
128
128
|
// Save merged config for next time
|
|
129
129
|
saveConfig(config);
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
if (args._daemon) {
|
|
132
|
+
// Actually run the daemon (spawned by ourselves)
|
|
133
|
+
const { Daemon } = require('../lib/daemon');
|
|
134
|
+
const daemon = new Daemon(config);
|
|
135
|
+
daemon.start();
|
|
136
|
+
} else {
|
|
137
|
+
// Spawn detached background process and exit
|
|
138
|
+
const { spawn } = require('child_process');
|
|
139
|
+
const LOG_FILE = path.join(CONFIG_DIR, 'daemon.log');
|
|
140
|
+
const logFd = fs.openSync(LOG_FILE, 'a');
|
|
141
|
+
|
|
142
|
+
const child = spawn(process.execPath, [__filename, 'start', '--_daemon'], {
|
|
143
|
+
detached: true,
|
|
144
|
+
stdio: ['ignore', logFd, logFd],
|
|
145
|
+
cwd: os.homedir(),
|
|
146
|
+
});
|
|
147
|
+
child.unref();
|
|
148
|
+
|
|
149
|
+
// Save PID for stop command
|
|
150
|
+
const pidFile = path.join(CONFIG_DIR, 'daemon.pid');
|
|
151
|
+
fs.writeFileSync(pidFile, String(child.pid));
|
|
152
|
+
|
|
153
|
+
console.log(`[channel-worker] Daemon started (PID: ${child.pid})`);
|
|
154
|
+
console.log(`[channel-worker] Logs: ${LOG_FILE}`);
|
|
155
|
+
process.exit(0);
|
|
156
|
+
}
|
|
134
157
|
|
|
135
158
|
} else if (cmd === 'update') {
|
|
136
159
|
const { checkAndUpdate, getLocalVersion } = require('../lib/updater');
|
|
@@ -150,6 +173,55 @@ if (cmd === 'pair') {
|
|
|
150
173
|
}
|
|
151
174
|
})();
|
|
152
175
|
|
|
176
|
+
} else if (cmd === 'stop') {
|
|
177
|
+
const pidFile = path.join(CONFIG_DIR, 'daemon.pid');
|
|
178
|
+
if (!fs.existsSync(pidFile)) {
|
|
179
|
+
console.log('[channel-worker] No daemon running (no PID file).');
|
|
180
|
+
process.exit(0);
|
|
181
|
+
}
|
|
182
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
183
|
+
try {
|
|
184
|
+
process.kill(pid, 'SIGTERM');
|
|
185
|
+
fs.unlinkSync(pidFile);
|
|
186
|
+
console.log(`[channel-worker] Daemon stopped (PID: ${pid})`);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
if (err.code === 'ESRCH') {
|
|
189
|
+
fs.unlinkSync(pidFile);
|
|
190
|
+
console.log(`[channel-worker] Daemon was not running (stale PID: ${pid}). Cleaned up.`);
|
|
191
|
+
} else {
|
|
192
|
+
console.error(`[channel-worker] Failed to stop: ${err.message}`);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
} else if (cmd === 'logs') {
|
|
198
|
+
const LOG_FILE = path.join(CONFIG_DIR, 'daemon.log');
|
|
199
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
200
|
+
console.log('[channel-worker] No log file found.');
|
|
201
|
+
process.exit(0);
|
|
202
|
+
}
|
|
203
|
+
const lines = parseInt(args.lines || '50', 10);
|
|
204
|
+
const content = fs.readFileSync(LOG_FILE, 'utf-8');
|
|
205
|
+
const tail = content.split('\n').slice(-lines).join('\n');
|
|
206
|
+
console.log(tail);
|
|
207
|
+
|
|
208
|
+
} else if (cmd === 'restart') {
|
|
209
|
+
// Stop existing daemon, then start new one
|
|
210
|
+
const pidFile = path.join(CONFIG_DIR, 'daemon.pid');
|
|
211
|
+
if (fs.existsSync(pidFile)) {
|
|
212
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
213
|
+
try { process.kill(pid, 'SIGTERM'); } catch { /* already dead */ }
|
|
214
|
+
fs.unlinkSync(pidFile);
|
|
215
|
+
console.log(`[channel-worker] Stopped old daemon (PID: ${pid})`);
|
|
216
|
+
}
|
|
217
|
+
// Re-invoke start
|
|
218
|
+
const { spawn } = require('child_process');
|
|
219
|
+
const child = spawn(process.execPath, [__filename, 'start'], {
|
|
220
|
+
stdio: 'inherit',
|
|
221
|
+
cwd: process.cwd(),
|
|
222
|
+
});
|
|
223
|
+
child.on('exit', (code) => process.exit(code));
|
|
224
|
+
|
|
153
225
|
} else if (cmd === 'config') {
|
|
154
226
|
const config = loadConfig();
|
|
155
227
|
// Hide token in display
|
|
@@ -164,7 +236,10 @@ channel-worker — Channel Manager worker daemon
|
|
|
164
236
|
Commands:
|
|
165
237
|
pair Pair with dashboard using a one-time code (recommended)
|
|
166
238
|
init Configure worker manually
|
|
167
|
-
start Start the daemon
|
|
239
|
+
start Start the daemon in background
|
|
240
|
+
stop Stop the daemon
|
|
241
|
+
restart Restart the daemon
|
|
242
|
+
logs Show recent daemon logs (--lines <n>, default 50)
|
|
168
243
|
update Check and install updates manually
|
|
169
244
|
config Show current config
|
|
170
245
|
|
|
@@ -182,6 +257,8 @@ Options:
|
|
|
182
257
|
Examples:
|
|
183
258
|
channel-worker pair --code A3F1B2 --api https://api.channel.tunasm.art
|
|
184
259
|
channel-worker start
|
|
260
|
+
channel-worker logs --lines 100
|
|
261
|
+
channel-worker stop
|
|
185
262
|
`);
|
|
186
263
|
}
|
|
187
264
|
|
package/lib/api-client.js
CHANGED
|
@@ -29,8 +29,11 @@ class ApiClient {
|
|
|
29
29
|
return this.request('POST', '/workers/register', workerData);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async heartbeat(workerId) {
|
|
33
|
-
|
|
32
|
+
async heartbeat(workerId, version, extensionVersion) {
|
|
33
|
+
const body = { worker_id: workerId };
|
|
34
|
+
if (version) body.version = version;
|
|
35
|
+
if (extensionVersion) body.extension_version = extensionVersion;
|
|
36
|
+
return this.request('POST', '/workers/heartbeat', body);
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
// Jobs
|
package/lib/daemon.js
CHANGED
|
@@ -9,7 +9,7 @@ class Daemon {
|
|
|
9
9
|
constructor(config) {
|
|
10
10
|
this.config = config;
|
|
11
11
|
this.api = new ApiClient(config.api_url, config.worker_token);
|
|
12
|
-
this.heartbeat = new Heartbeat(this.api, config.worker_id);
|
|
12
|
+
this.heartbeat = new Heartbeat(this.api, config.worker_id, 30000, config);
|
|
13
13
|
this.poller = new JobPoller(this.api, config);
|
|
14
14
|
this.commandPoller = new CommandPoller(this.api, config);
|
|
15
15
|
this.updateChecker = new UpdateChecker(5 * 60 * 1000); // check every 5min
|
package/lib/heartbeat.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
const { getLocalVersion } = require('./updater');
|
|
2
|
+
const { getLocalExtensionVersion } = require('./extension-updater');
|
|
3
|
+
|
|
1
4
|
class Heartbeat {
|
|
2
|
-
constructor(api, workerId, intervalMs = 30000) {
|
|
5
|
+
constructor(api, workerId, intervalMs = 30000, config = {}) {
|
|
3
6
|
this.api = api;
|
|
4
7
|
this.workerId = workerId;
|
|
5
8
|
this.intervalMs = intervalMs;
|
|
9
|
+
this.config = config;
|
|
6
10
|
this.timer = null;
|
|
7
11
|
}
|
|
8
12
|
|
|
@@ -20,7 +24,9 @@ class Heartbeat {
|
|
|
20
24
|
|
|
21
25
|
async send() {
|
|
22
26
|
try {
|
|
23
|
-
|
|
27
|
+
const version = getLocalVersion();
|
|
28
|
+
const extVersion = getLocalExtensionVersion(this.config.extension_path);
|
|
29
|
+
await this.api.heartbeat(this.workerId, version, extVersion);
|
|
24
30
|
} catch (err) {
|
|
25
31
|
console.error(`[heartbeat] Failed: ${err.message}`);
|
|
26
32
|
}
|
package/lib/updater.js
CHANGED
|
@@ -43,15 +43,31 @@ async function checkAndUpdate({ autoRestart = false } = {}) {
|
|
|
43
43
|
installUpdate(latest);
|
|
44
44
|
|
|
45
45
|
if (autoRestart) {
|
|
46
|
-
console.log('[updater] Restarting daemon...');
|
|
47
|
-
// Spawn detached process with same args, then exit current
|
|
46
|
+
console.log('[updater] Restarting daemon with new version...');
|
|
48
47
|
const { spawn } = require('child_process');
|
|
49
|
-
const
|
|
48
|
+
const fs = require('fs');
|
|
49
|
+
const path = require('path');
|
|
50
|
+
const os = require('os');
|
|
51
|
+
|
|
52
|
+
const CONFIG_DIR = path.join(os.homedir(), '.channel-worker');
|
|
53
|
+
const pidFile = path.join(CONFIG_DIR, 'daemon.pid');
|
|
54
|
+
const LOG_FILE = path.join(CONFIG_DIR, 'daemon.log');
|
|
55
|
+
const logFd = fs.openSync(LOG_FILE, 'a');
|
|
56
|
+
|
|
57
|
+
// Spawn new daemon using global binary (picks up new version)
|
|
58
|
+
const isWindows = process.platform === 'win32';
|
|
59
|
+
const binName = isWindows ? 'channel-worker.cmd' : 'channel-worker';
|
|
60
|
+
const child = spawn(binName, ['start'], {
|
|
50
61
|
detached: true,
|
|
51
|
-
stdio: 'ignore',
|
|
52
|
-
cwd:
|
|
62
|
+
stdio: ['ignore', logFd, logFd],
|
|
63
|
+
cwd: os.homedir(),
|
|
64
|
+
shell: isWindows,
|
|
53
65
|
});
|
|
54
66
|
child.unref();
|
|
67
|
+
|
|
68
|
+
// Update PID file
|
|
69
|
+
fs.writeFileSync(pidFile, String(child.pid));
|
|
70
|
+
|
|
55
71
|
process.exit(0);
|
|
56
72
|
}
|
|
57
73
|
|