channel-worker 1.0.33 → 1.1.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 +82 -13
- package/lib/api-client.js +6 -2
- package/lib/command-poller.js +1 -0
- package/lib/daemon.js +1 -1
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -37,35 +37,88 @@ function saveConfig(config) {
|
|
|
37
37
|
const args = parseArgs(process.argv.slice(2));
|
|
38
38
|
const cmd = args._cmd || 'start';
|
|
39
39
|
|
|
40
|
-
if (cmd === '
|
|
40
|
+
if (cmd === 'pair') {
|
|
41
|
+
// Pair with dashboard using one-time code
|
|
42
|
+
const code = args.code;
|
|
43
|
+
const apiUrl = args.api || 'https://api.channel.tunasm.art';
|
|
44
|
+
const nstKey = args['nst-key'] || '';
|
|
45
|
+
const extensionPath = args.extension || '';
|
|
46
|
+
const maxConcurrent = parseInt(args.concurrent || '2', 10);
|
|
47
|
+
|
|
48
|
+
if (!code) {
|
|
49
|
+
console.error('[channel-worker] Error: --code required. Get a pairing code from the dashboard.');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
(async () => {
|
|
54
|
+
try {
|
|
55
|
+
console.log(`[channel-worker] Pairing with code: ${code}`);
|
|
56
|
+
const res = await fetch(`${apiUrl}/workers/pair`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'Content-Type': 'application/json' },
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
code,
|
|
61
|
+
ip_address: getLocalIP(),
|
|
62
|
+
max_concurrent: maxConcurrent,
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
const json = await res.json();
|
|
66
|
+
|
|
67
|
+
if (!json.success) {
|
|
68
|
+
console.error(`[channel-worker] Pairing failed: ${json.message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const config = {
|
|
73
|
+
worker_id: json.data.worker_id,
|
|
74
|
+
worker_token: json.data.worker_token,
|
|
75
|
+
api_url: apiUrl,
|
|
76
|
+
max_concurrent: maxConcurrent,
|
|
77
|
+
nst_api_key: nstKey,
|
|
78
|
+
extension_path: extensionPath,
|
|
79
|
+
};
|
|
80
|
+
saveConfig(config);
|
|
81
|
+
|
|
82
|
+
console.log(`[channel-worker] Paired successfully!`);
|
|
83
|
+
console.log(` Worker ID: ${config.worker_id}`);
|
|
84
|
+
console.log(` Config saved to: ${CONFIG_FILE}`);
|
|
85
|
+
console.log(`\nRun: channel-worker start`);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(`[channel-worker] Error: ${err.message}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
|
|
92
|
+
} else if (cmd === 'init') {
|
|
41
93
|
const config = {
|
|
42
94
|
worker_id: args.id || `worker-${os.hostname()}`,
|
|
43
95
|
api_url: args.api || 'http://localhost:3001',
|
|
44
96
|
max_concurrent: parseInt(args.concurrent || '2', 10),
|
|
45
97
|
nst_api_key: args['nst-key'] || '',
|
|
46
98
|
extension_path: args.extension || '',
|
|
99
|
+
worker_token: args.token || '',
|
|
47
100
|
};
|
|
48
101
|
saveConfig(config);
|
|
49
102
|
console.log(`[channel-worker] Config saved to ${CONFIG_FILE}`);
|
|
50
103
|
console.log(JSON.stringify(config, null, 2));
|
|
51
104
|
console.log('\nRun: channel-worker start');
|
|
52
105
|
process.exit(0);
|
|
53
|
-
}
|
|
54
106
|
|
|
55
|
-
if (cmd === 'start') {
|
|
107
|
+
} else if (cmd === 'start') {
|
|
56
108
|
// Merge CLI args over saved config
|
|
57
109
|
const saved = loadConfig();
|
|
58
110
|
const config = {
|
|
59
111
|
worker_id: args.id || saved.worker_id || `worker-${os.hostname()}`,
|
|
60
|
-
api_url: args.api || saved.api_url || '
|
|
112
|
+
api_url: args.api || saved.api_url || 'https://api.channel.tunasm.art',
|
|
61
113
|
max_concurrent: parseInt(args.concurrent || saved.max_concurrent || '2', 10),
|
|
62
114
|
nst_api_key: args['nst-key'] || saved.nst_api_key || '',
|
|
63
115
|
extension_path: args.extension || saved.extension_path || '',
|
|
116
|
+
worker_token: args.token || saved.worker_token || '',
|
|
64
117
|
verbose: !!args.verbose,
|
|
65
118
|
};
|
|
66
119
|
|
|
67
|
-
if (!config.
|
|
68
|
-
console.error('[channel-worker] Error:
|
|
120
|
+
if (!config.worker_token) {
|
|
121
|
+
console.error('[channel-worker] Error: No worker token. Run: channel-worker pair --code <CODE> --api <URL>');
|
|
69
122
|
process.exit(1);
|
|
70
123
|
}
|
|
71
124
|
|
|
@@ -78,28 +131,44 @@ if (cmd === 'start') {
|
|
|
78
131
|
|
|
79
132
|
} else if (cmd === 'config') {
|
|
80
133
|
const config = loadConfig();
|
|
81
|
-
|
|
134
|
+
// Hide token in display
|
|
135
|
+
const display = { ...config };
|
|
136
|
+
if (display.worker_token) display.worker_token = display.worker_token.slice(0, 8) + '...';
|
|
137
|
+
console.log(JSON.stringify(display, null, 2));
|
|
82
138
|
|
|
83
139
|
} else {
|
|
84
140
|
console.log(`
|
|
85
141
|
channel-worker — Channel Manager worker daemon
|
|
86
142
|
|
|
87
143
|
Commands:
|
|
88
|
-
|
|
144
|
+
pair Pair with dashboard using a one-time code (recommended)
|
|
145
|
+
init Configure worker manually
|
|
89
146
|
start Start the daemon
|
|
90
147
|
config Show current config
|
|
91
148
|
|
|
149
|
+
Pairing (recommended):
|
|
150
|
+
channel-worker pair --code <CODE> --api <URL>
|
|
151
|
+
|
|
92
152
|
Options:
|
|
93
|
-
--
|
|
94
|
-
--api <url>
|
|
95
|
-
--concurrent <n> Max concurrent
|
|
153
|
+
--code <code> Pairing code from dashboard (for pair command)
|
|
154
|
+
--api <url> API URL (default: https://api.channel.tunasm.art)
|
|
155
|
+
--concurrent <n> Max concurrent browsers (default: 2)
|
|
96
156
|
--nst-key <key> Nstbrowser API key
|
|
97
157
|
--extension <path> Path to content-creator extension
|
|
98
158
|
--verbose Enable verbose logging
|
|
99
159
|
|
|
100
160
|
Examples:
|
|
101
|
-
channel-worker
|
|
161
|
+
channel-worker pair --code A3F1B2 --api https://api.channel.tunasm.art
|
|
102
162
|
channel-worker start
|
|
103
|
-
channel-worker start --id win-worker --api http://192.168.1.52:3001
|
|
104
163
|
`);
|
|
105
164
|
}
|
|
165
|
+
|
|
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/api-client.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
class ApiClient {
|
|
2
|
-
constructor(baseUrl) {
|
|
2
|
+
constructor(baseUrl, workerToken) {
|
|
3
3
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
4
|
+
this.workerToken = workerToken || '';
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
async request(method, path, body = null) {
|
|
7
8
|
const url = `${this.baseUrl}${path}`;
|
|
8
9
|
const options = {
|
|
9
10
|
method,
|
|
10
|
-
headers: {
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
'x-worker-token': this.workerToken,
|
|
14
|
+
},
|
|
11
15
|
};
|
|
12
16
|
if (body) options.body = JSON.stringify(body);
|
|
13
17
|
|
package/lib/command-poller.js
CHANGED
|
@@ -117,6 +117,7 @@ class CommandPoller {
|
|
|
117
117
|
fs.writeFileSync(path.join(uniqueExtPath, 'config.json'), JSON.stringify({
|
|
118
118
|
channelManagerApi: 'https://api.channel.tunasm.art',
|
|
119
119
|
profileId: profile_id,
|
|
120
|
+
workerToken: this.config.worker_token || '',
|
|
120
121
|
}));
|
|
121
122
|
extensionPath = uniqueExtPath;
|
|
122
123
|
console.log(`[commands] Extension dir: ${uniqueExtPath}`);
|
package/lib/daemon.js
CHANGED
|
@@ -7,7 +7,7 @@ const os = require('os');
|
|
|
7
7
|
class Daemon {
|
|
8
8
|
constructor(config) {
|
|
9
9
|
this.config = config;
|
|
10
|
-
this.api = new ApiClient(config.api_url);
|
|
10
|
+
this.api = new ApiClient(config.api_url, config.worker_token);
|
|
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);
|