@matterbridge/thread 3.10.13-dev-20261005-49e0dbd → 3.10.13-dev-20261008-55d98fb
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/dist/threadsManager.d.ts +3 -1
- package/dist/threadsManager.js +119 -52
- package/dist/{workerWrapper.d.ts → threadsWrapper.d.ts} +8 -3
- package/dist/{workerWrapper.js → threadsWrapper.js} +28 -23
- package/dist/workerArchiveCommand.d.ts +2 -2
- package/dist/workerArchiveCommand.js +2 -2
- package/dist/workerCheckUpdates.d.ts +2 -2
- package/dist/workerCheckUpdates.js +2 -2
- package/dist/workerDockerVersion.d.ts +2 -2
- package/dist/workerDockerVersion.js +2 -2
- package/dist/workerGlobalPrefix.d.ts +2 -2
- package/dist/workerGlobalPrefix.js +2 -2
- package/dist/workerSpawnCommand.d.ts +2 -2
- package/dist/workerSpawnCommand.js +2 -2
- package/dist/workerSystemCheck.d.ts +2 -2
- package/dist/workerSystemCheck.js +2 -2
- package/dist/zipjs.js +2 -1
- package/package.json +8 -3
package/dist/threadsManager.d.ts
CHANGED
|
@@ -11,11 +11,13 @@ export declare class ThreadsManager {
|
|
|
11
11
|
private readonly boundMsgHandler;
|
|
12
12
|
private interval;
|
|
13
13
|
private intervalMs;
|
|
14
|
+
private readonly coreDirectory;
|
|
14
15
|
private threads;
|
|
15
16
|
private terminateWorkers;
|
|
16
|
-
constructor(intervalMs?: number);
|
|
17
|
+
constructor(coreDirectory: string, intervalMs?: number);
|
|
17
18
|
destroy(): void;
|
|
18
19
|
private msgHandler;
|
|
20
|
+
private sendShutdown;
|
|
19
21
|
private terminateExitedWorkers;
|
|
20
22
|
private intervalHandler;
|
|
21
23
|
runThread(name: string, workerData?: WorkerData, argv?: string[], env?: NodeJS.ProcessEnv, execArgv?: string[], pipedOutput?: boolean): Worker;
|
package/dist/threadsManager.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
4
|
import { Worker } from 'node:worker_threads';
|
|
5
|
-
import { hasParameter } from '@matterbridge/utils/cli';
|
|
5
|
+
import { hasAnyParameter, hasParameter } from '@matterbridge/utils/cli';
|
|
6
6
|
import { getErrorMessage } from '@matterbridge/utils/error';
|
|
7
7
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
8
8
|
import { fireAndForget } from '@matterbridge/utils/wait';
|
|
@@ -19,6 +19,7 @@ export class ThreadsManager {
|
|
|
19
19
|
boundMsgHandler = this.msgHandler.bind(this);
|
|
20
20
|
interval;
|
|
21
21
|
intervalMs;
|
|
22
|
+
coreDirectory;
|
|
22
23
|
threads = [
|
|
23
24
|
{ name: 'CheckUpdates', path: 'workerCheckUpdates.js', type: 'worker' },
|
|
24
25
|
{ name: 'SystemCheck', path: 'workerSystemCheck.js', type: 'worker' },
|
|
@@ -26,12 +27,15 @@ export class ThreadsManager {
|
|
|
26
27
|
{ name: 'SpawnCommand', path: 'workerSpawnCommand.js', type: 'worker' },
|
|
27
28
|
{ name: 'ArchiveCommand', path: 'workerArchiveCommand.js', type: 'worker' },
|
|
28
29
|
{ name: 'DockerVersion', path: 'workerDockerVersion.js', type: 'worker' },
|
|
30
|
+
{ name: 'Backend', path: 'threadBackend.js', type: 'thread' },
|
|
31
|
+
{ name: 'RootNode', path: 'threadRootNode.js', type: 'thread', multiple: true },
|
|
32
|
+
{ name: 'Tracker', path: 'threadTracker.js', type: 'thread', multiple: true, startup: true, shutdown: true },
|
|
29
33
|
];
|
|
30
34
|
terminateWorkers = new Set();
|
|
31
|
-
constructor(intervalMs = 60_000) {
|
|
32
|
-
this.debug =
|
|
33
|
-
this.verbose =
|
|
34
|
-
this.tracker =
|
|
35
|
+
constructor(coreDirectory, intervalMs = 60_000) {
|
|
36
|
+
this.debug = hasAnyParameter('debug', 'verbose', 'debug-threads', 'verbose-threads');
|
|
37
|
+
this.verbose = hasAnyParameter('verbose', 'verbose-threads');
|
|
38
|
+
this.tracker = hasAnyParameter('tracker', 'tracker-threads');
|
|
35
39
|
this.log = new AnsiLogger({
|
|
36
40
|
logName: 'ThreadsManager',
|
|
37
41
|
logNameColor: MAGENTA,
|
|
@@ -43,6 +47,7 @@ export class ThreadsManager {
|
|
|
43
47
|
this.server = new BroadcastServer('manager', this.log);
|
|
44
48
|
this.server.on('broadcast_message', this.boundMsgHandler);
|
|
45
49
|
this.intervalMs = intervalMs;
|
|
50
|
+
this.coreDirectory = coreDirectory;
|
|
46
51
|
this.interval = setInterval(this.intervalHandler.bind(this), this.intervalMs);
|
|
47
52
|
if (this.verbose)
|
|
48
53
|
this.log.notice(`ThreadsManager initialized. Listening for broadcast messages...`);
|
|
@@ -50,6 +55,7 @@ export class ThreadsManager {
|
|
|
50
55
|
destroy() {
|
|
51
56
|
clearInterval(this.interval);
|
|
52
57
|
this.terminateExitedWorkers();
|
|
58
|
+
this.sendShutdown(this.threads.filter((t) => t.shutdown));
|
|
53
59
|
this.server.off('broadcast_message', this.boundMsgHandler);
|
|
54
60
|
this.server.close();
|
|
55
61
|
if (this.verbose)
|
|
@@ -80,12 +86,31 @@ export class ThreadsManager {
|
|
|
80
86
|
this.server.respond({ ...msg, result: { success: false } });
|
|
81
87
|
}
|
|
82
88
|
break;
|
|
89
|
+
case 'manager_shutdown': {
|
|
90
|
+
const threads = msg.params.thread === undefined ? this.threads : this.threads.filter((t) => t.name === msg.params.thread);
|
|
91
|
+
if (threads.length === 0)
|
|
92
|
+
this.log.warn(`Failed to shut down thread ${CYAN}${msg.params.thread}${wr}: thread not found`);
|
|
93
|
+
this.sendShutdown(threads);
|
|
94
|
+
this.server.respond({ ...msg, result: { success: threads.length > 0 } });
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
83
97
|
default:
|
|
84
98
|
if (this.verbose)
|
|
85
99
|
this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
|
|
86
100
|
}
|
|
87
101
|
}
|
|
88
102
|
}
|
|
103
|
+
sendShutdown(threads) {
|
|
104
|
+
for (const thread of threads) {
|
|
105
|
+
for (const info of [thread, ...(thread.instances ?? [])]) {
|
|
106
|
+
if (!info.worker)
|
|
107
|
+
continue;
|
|
108
|
+
const shutdownMessage = { type: 'shutdown', threadName: thread.name, threadId: info.worker.threadId };
|
|
109
|
+
info.worker.postMessage(shutdownMessage);
|
|
110
|
+
this.log.debug(`Thread ${thread.name} sent shutdown message to thread id ${info.worker.threadId}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
89
114
|
terminateExitedWorkers() {
|
|
90
115
|
if (this.terminateWorkers.size > 0) {
|
|
91
116
|
this.log.debug(`Terminating ${this.terminateWorkers.size} workers that have exited...`);
|
|
@@ -103,16 +128,26 @@ export class ThreadsManager {
|
|
|
103
128
|
}
|
|
104
129
|
intervalHandler() {
|
|
105
130
|
for (const thread of this.threads) {
|
|
106
|
-
|
|
131
|
+
if (!thread.multiple) {
|
|
132
|
+
this.log.debug(`Thread ${thread.name} running: ${thread.worker ? 'yes' : 'no'}, threadId: ${thread.worker?.threadId ?? 'none'}, lastSeen: ${thread.lastSeen ? new Date(thread.lastSeen).toISOString() : 'never'}, runs: ${thread.runCount ?? 0}, errors: ${thread.errorCount ?? 0}`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const instances = thread.instances ?? [];
|
|
136
|
+
this.log.debug(`Thread ${thread.name} instances: ${instances.length}, running: ${instances.filter((instance) => instance.worker).length}, runs: ${thread.runCount ?? 0}, errors: ${thread.errorCount ?? 0}`);
|
|
137
|
+
instances.forEach((instance, index) => {
|
|
138
|
+
this.log.debug(`- instance ${index} running: ${instance.worker ? 'yes' : 'no'}, threadId: ${instance.worker?.threadId ?? 'none'}, lastSeen: ${instance.lastSeen ? new Date(instance.lastSeen).toISOString() : 'never'}, lastStarted: ${instance.lastStarted ? new Date(instance.lastStarted).toISOString() : 'never'}, lastStopped: ${instance.lastStopped ? new Date(instance.lastStopped).toISOString() : 'never'}, lastDuration: ${instance.lastDuration ?? 'none'} ms`);
|
|
139
|
+
});
|
|
107
140
|
}
|
|
108
141
|
this.terminateExitedWorkers();
|
|
109
142
|
for (const thread of this.threads) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
for (const info of [thread, ...(thread.instances ?? [])]) {
|
|
144
|
+
if (info.worker && Date.now() - (info.lastSeen ?? 0) > this.intervalMs) {
|
|
145
|
+
const msg = { type: 'ping', threadId: info.worker.threadId, threadName: thread.name };
|
|
146
|
+
info.worker.postMessage(msg);
|
|
147
|
+
}
|
|
148
|
+
if (info.worker && Date.now() - (info.lastSeen ?? 0) > this.intervalMs * 2) {
|
|
149
|
+
this.log.warn(`Thread ${CYAN}${thread.name}${db} has not been seen for more than ${this.intervalMs * 2} ms. It may be unresponsive.`);
|
|
150
|
+
}
|
|
116
151
|
}
|
|
117
152
|
}
|
|
118
153
|
}
|
|
@@ -121,76 +156,100 @@ export class ThreadsManager {
|
|
|
121
156
|
if (!threadInfo) {
|
|
122
157
|
throw new Error(`Thread ${name} not found`);
|
|
123
158
|
}
|
|
124
|
-
if (threadInfo.worker) {
|
|
159
|
+
if (threadInfo.worker && !threadInfo.multiple) {
|
|
125
160
|
throw new Error(`Thread ${name} is already running with thread ID ${threadInfo.worker.threadId}`);
|
|
126
161
|
}
|
|
127
162
|
const path = this.resolvePath(threadInfo.path);
|
|
128
163
|
if (!fs.existsSync(path)) {
|
|
129
164
|
throw new Error(`Thread ${name} file not found at path ${path}`);
|
|
130
165
|
}
|
|
131
|
-
this.log.debug(`Starting thread ${threadInfo.name} from path ${path} type ${threadInfo.type}...`);
|
|
166
|
+
this.log.debug(`Starting thread ${threadInfo.name} from path ${path} type ${threadInfo.type}${threadInfo.multiple ? ` instances: ${threadInfo.instances?.length}` : ''}...`);
|
|
132
167
|
threadInfo.lastStarted = undefined;
|
|
133
168
|
threadInfo.lastStopped = undefined;
|
|
134
169
|
threadInfo.lastDuration = undefined;
|
|
135
|
-
|
|
136
|
-
|
|
170
|
+
const worker = this.createESMWorker(threadInfo.name, path, { ...workerData, type: threadInfo.type, debug: this.debug, verbose: this.verbose, tracker: this.tracker, logLevel: this.log.logLevel }, argv, env, execArgv, pipedOutput);
|
|
171
|
+
if (threadInfo.multiple) {
|
|
172
|
+
threadInfo.instances ??= [];
|
|
173
|
+
threadInfo.instances.push({ worker });
|
|
174
|
+
}
|
|
175
|
+
else
|
|
176
|
+
threadInfo.worker = worker;
|
|
137
177
|
worker.once('online', () => {
|
|
138
178
|
const now = Date.now();
|
|
179
|
+
const info = [threadInfo, ...(threadInfo.instances ?? [])].find((info) => info.worker === worker);
|
|
180
|
+
if (info) {
|
|
181
|
+
info.lastSeen = now;
|
|
182
|
+
info.lastStarted = now;
|
|
183
|
+
}
|
|
139
184
|
this.log.debug(`Thread ${threadInfo.name} is online at ${new Date(now).toISOString()}`);
|
|
140
185
|
});
|
|
141
186
|
worker.once('exit', () => {
|
|
142
187
|
const now = Date.now();
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
188
|
+
const info = [threadInfo, ...(threadInfo.instances ?? [])].find((info) => info.worker === worker);
|
|
189
|
+
if (info) {
|
|
190
|
+
info.lastSeen = now;
|
|
191
|
+
info.lastStopped = now;
|
|
192
|
+
info.lastDuration = Math.max(0, now - (info.lastStarted ?? now));
|
|
193
|
+
info.worker = undefined;
|
|
148
194
|
}
|
|
149
|
-
this.log.debug(`Thread ${threadInfo.name} has exited at ${new Date(now).toISOString()}`);
|
|
195
|
+
this.log.debug(`Thread ${threadInfo.name} has exited at ${new Date(now).toISOString()} after ${info?.lastDuration ?? 0} ms`);
|
|
150
196
|
this.terminateWorkers.delete(worker);
|
|
151
197
|
});
|
|
152
198
|
worker.on('message', (message) => {
|
|
153
199
|
const now = Date.now();
|
|
154
|
-
threadInfo.
|
|
200
|
+
const info = [threadInfo, ...(threadInfo.instances ?? [])].find((info) => info.worker === worker);
|
|
201
|
+
if (info) {
|
|
202
|
+
info.lastSeen = now;
|
|
203
|
+
}
|
|
155
204
|
if (this.verbose)
|
|
156
205
|
this.log.debug(`Thread ${threadInfo.name} sent a message at ${new Date(now).toISOString()}: ${debugStringify(message)}`);
|
|
157
|
-
if (message.type === '
|
|
158
|
-
AnsiLogger.create({ logName: threadInfo.name, logNameColor: MAGENTA, logTimestampFormat: 4, logLevel: this.log.logLevel }).log(message.logLevel, message.message);
|
|
159
|
-
}
|
|
160
|
-
else if (message.type === 'init') {
|
|
161
|
-
threadInfo.lastStarted = now;
|
|
206
|
+
if (message.type === 'init') {
|
|
162
207
|
threadInfo.runCount = (threadInfo.runCount ?? 0) + 1;
|
|
163
208
|
this.log.debug(`Thread ${threadInfo.name} is online started at ${new Date(now).toISOString()} with thread id ${worker.threadId}`);
|
|
209
|
+
if (threadInfo.startup) {
|
|
210
|
+
const startupMessage = { type: 'startup', threadName: threadInfo.name, threadId: worker.threadId };
|
|
211
|
+
worker.postMessage(startupMessage);
|
|
212
|
+
this.log.debug(`Thread ${threadInfo.name} sent startup message to thread id ${worker.threadId}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (message.type === 'pong') {
|
|
216
|
+
this.log.debug(`Thread ${threadInfo.name} received a pong at ${new Date(now).toISOString()}`);
|
|
217
|
+
}
|
|
218
|
+
else if (message.type === 'log') {
|
|
219
|
+
AnsiLogger.create({ logName: threadInfo.name, logNameColor: MAGENTA, logTimestampFormat: 4, logLevel: this.log.logLevel }).log(message.logLevel, message.message);
|
|
164
220
|
}
|
|
165
221
|
else if (message.type === 'exit') {
|
|
166
|
-
threadInfo.lastStopped = now;
|
|
167
|
-
threadInfo.lastDuration = Math.max(0, now - (threadInfo.lastStarted ?? now));
|
|
168
222
|
if (!message.success) {
|
|
169
223
|
threadInfo.errorCount = (threadInfo.errorCount ?? 0) + 1;
|
|
170
224
|
}
|
|
171
225
|
this.terminateWorkers.add(worker);
|
|
172
|
-
threadInfo.
|
|
173
|
-
this.log.debug(`Thread ${threadInfo.name} has exited at ${new Date(now).toISOString()} with thread id ${worker.threadId} after running for ${threadInfo.lastDuration} ms`);
|
|
226
|
+
this.log.debug(`Thread ${threadInfo.name} has exited at ${new Date(now).toISOString()} with thread id ${worker.threadId}`);
|
|
174
227
|
}
|
|
175
228
|
});
|
|
176
229
|
worker.on('messageerror', () => {
|
|
177
230
|
const now = Date.now();
|
|
178
|
-
threadInfo.
|
|
179
|
-
|
|
231
|
+
const info = [threadInfo, ...(threadInfo.instances ?? [])].find((info) => info.worker === worker);
|
|
232
|
+
if (info) {
|
|
233
|
+
info.lastSeen = now;
|
|
234
|
+
threadInfo.errorCount = (threadInfo.errorCount ?? 0) + 1;
|
|
235
|
+
}
|
|
180
236
|
this.log.error(`Thread ${threadInfo.name} encountered a message error at ${new Date(now).toISOString()}`);
|
|
181
237
|
});
|
|
182
238
|
worker.once('error', (error) => {
|
|
183
239
|
const now = Date.now();
|
|
184
|
-
threadInfo.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
240
|
+
const info = [threadInfo, ...(threadInfo.instances ?? [])].find((info) => info.worker === worker);
|
|
241
|
+
if (info) {
|
|
242
|
+
info.lastSeen = now;
|
|
243
|
+
info.lastStopped = now;
|
|
244
|
+
info.lastDuration = Math.max(0, now - (info.lastStarted ?? now));
|
|
245
|
+
threadInfo.errorCount = (threadInfo.errorCount ?? 0) + 1;
|
|
246
|
+
info.worker = undefined;
|
|
247
|
+
}
|
|
189
248
|
this.terminateWorkers.add(worker);
|
|
190
|
-
this.log.error(`Thread ${threadInfo.name} encountered an error at ${new Date(now).toISOString()} after running for ${
|
|
249
|
+
this.log.error(`Thread ${threadInfo.name} encountered an error at ${new Date(now).toISOString()} after running for ${info?.lastDuration} ms: ${getErrorMessage(error)}`);
|
|
191
250
|
});
|
|
192
251
|
this.log.debug(`Started thread ${threadInfo.name} from path ${path} type ${threadInfo.type} with thread id ${worker.threadId}`);
|
|
193
|
-
return
|
|
252
|
+
return worker;
|
|
194
253
|
}
|
|
195
254
|
async runInMainThread(name, workerData = null) {
|
|
196
255
|
const threadInfo = this.threads.find((t) => t.name === name);
|
|
@@ -199,22 +258,30 @@ export class ThreadsManager {
|
|
|
199
258
|
}
|
|
200
259
|
this.log.debug(`Running thread ${threadInfo.name} in the main thread...`);
|
|
201
260
|
let success = false;
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
261
|
+
const threadsWrapper = (await import(this.resolvePath(threadInfo.path))).default;
|
|
262
|
+
if (threadsWrapper && typeof threadsWrapper === 'object' && threadsWrapper.name === name && threadsWrapper.entrypoint && typeof threadsWrapper.entrypoint === 'function') {
|
|
263
|
+
threadsWrapper.workerData = workerData ? { ...workerData, type: threadInfo.type } : null;
|
|
264
|
+
try {
|
|
265
|
+
success = await threadsWrapper.entrypoint(threadsWrapper);
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
if (!success || threadInfo.type !== 'thread')
|
|
269
|
+
threadsWrapper.destroy(success);
|
|
270
|
+
}
|
|
207
271
|
}
|
|
208
272
|
this.log.debug(`Finished running thread ${threadInfo.name} in the main thread.`);
|
|
209
273
|
return success;
|
|
210
274
|
}
|
|
211
275
|
resolvePath(fileName) {
|
|
212
|
-
const
|
|
276
|
+
const threadDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
213
277
|
const candidates = [
|
|
214
|
-
path.join(
|
|
215
|
-
path.join(
|
|
216
|
-
path.join(
|
|
217
|
-
path.join(
|
|
278
|
+
path.join(threadDirectory, fileName),
|
|
279
|
+
path.join(threadDirectory, '..', 'dist', fileName),
|
|
280
|
+
path.join(threadDirectory, '..', 'src', fileName.replace(/\.js$/, '.ts')),
|
|
281
|
+
path.join(threadDirectory, 'workers', fileName),
|
|
282
|
+
path.join(this.coreDirectory, 'runners', fileName),
|
|
283
|
+
path.join(this.coreDirectory, '..', 'dist', 'runners', fileName),
|
|
284
|
+
path.join(this.coreDirectory, '..', 'src', 'runners', fileName.replace(/\.js$/, '.ts')),
|
|
218
285
|
];
|
|
219
286
|
for (const candidate of candidates) {
|
|
220
287
|
if (fs.existsSync(candidate))
|
|
@@ -226,7 +293,7 @@ export class ThreadsManager {
|
|
|
226
293
|
createESMWorker(name, relativePath, workerData, argv, env, execArgv, pipedOutput = false) {
|
|
227
294
|
const fileURL = pathToFileURL(path.resolve(relativePath));
|
|
228
295
|
const options = {
|
|
229
|
-
workerData: { ...workerData, threadName: name, debug: this.debug, verbose: this.verbose,
|
|
296
|
+
workerData: { ...workerData, threadName: name, debug: this.debug, verbose: this.verbose, tracker: this.tracker, logLevel: this.log.logLevel },
|
|
230
297
|
name,
|
|
231
298
|
argv: argv ?? process.argv.slice(2),
|
|
232
299
|
env: env ?? process.env,
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
1
2
|
import type { ParentPortMessage, ThreadNames, WorkerData } from '@matterbridge/types';
|
|
2
3
|
import type { Tracker } from '@matterbridge/utils/tracker';
|
|
3
4
|
import { AnsiLogger, LogLevel } from 'node-ansi-logger';
|
|
4
5
|
import { BroadcastServer } from './broadcastServer.js';
|
|
5
|
-
export
|
|
6
|
+
export interface ThreadsWrapperEvents {
|
|
7
|
+
startup: [];
|
|
8
|
+
shutdown: [];
|
|
9
|
+
}
|
|
10
|
+
export declare class ThreadsWrapper extends EventEmitter<ThreadsWrapperEvents> {
|
|
6
11
|
name: ThreadNames;
|
|
7
|
-
|
|
12
|
+
entrypoint: (worker: ThreadsWrapper) => Promise<boolean>;
|
|
8
13
|
debug: boolean;
|
|
9
14
|
verbose: boolean;
|
|
10
15
|
useTracker: boolean;
|
|
@@ -15,7 +20,7 @@ export declare class WorkerWrapper {
|
|
|
15
20
|
private destroyed;
|
|
16
21
|
private readonly boundUnhandledRejectionHandler;
|
|
17
22
|
private readonly boundUncaughtExceptionHandler;
|
|
18
|
-
constructor(name: ThreadNames,
|
|
23
|
+
constructor(name: ThreadNames, entrypoint: (worker: ThreadsWrapper) => Promise<boolean>);
|
|
19
24
|
destroy(success: boolean): void;
|
|
20
25
|
private handleUnhandledRejection;
|
|
21
26
|
private handleUncaughtException;
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
1
2
|
import { isMainThread, parentPort, threadId, workerData } from 'node:worker_threads';
|
|
2
3
|
import { getErrorMessage, inspectError } from '@matterbridge/utils';
|
|
3
|
-
import {
|
|
4
|
+
import { hasAnyParameter } from '@matterbridge/utils/cli';
|
|
4
5
|
import { formatBytes } from '@matterbridge/utils/format';
|
|
5
6
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
6
7
|
import { AnsiLogger, debugStringify, MAGENTA } from 'node-ansi-logger';
|
|
7
8
|
import { BroadcastServer } from './broadcastServer.js';
|
|
8
9
|
import { ThreadsManager } from './threadsManager.js';
|
|
9
|
-
logModuleLoaded('
|
|
10
|
-
export class
|
|
10
|
+
logModuleLoaded('ThreadsWrapper');
|
|
11
|
+
export class ThreadsWrapper extends EventEmitter {
|
|
11
12
|
name;
|
|
12
|
-
|
|
13
|
-
debug =
|
|
14
|
-
verbose =
|
|
15
|
-
useTracker =
|
|
13
|
+
entrypoint;
|
|
14
|
+
debug = hasAnyParameter('debug', 'verbose', 'debug-threads', 'verbose-threads');
|
|
15
|
+
verbose = hasAnyParameter('verbose', 'verbose-threads');
|
|
16
|
+
useTracker = hasAnyParameter('tracker', 'tracker-threads');
|
|
16
17
|
log;
|
|
17
18
|
server;
|
|
18
19
|
workerData = workerData;
|
|
@@ -24,33 +25,33 @@ export class WorkerWrapper {
|
|
|
24
25
|
boundUncaughtExceptionHandler = (error) => {
|
|
25
26
|
this.handleUncaughtException(error);
|
|
26
27
|
};
|
|
27
|
-
constructor(name,
|
|
28
|
+
constructor(name, entrypoint) {
|
|
29
|
+
super();
|
|
28
30
|
this.name = name;
|
|
29
|
-
this.
|
|
31
|
+
this.entrypoint = entrypoint;
|
|
30
32
|
if (this.workerData) {
|
|
31
33
|
this.debug = this.workerData.debug ?? this.debug;
|
|
32
34
|
this.verbose = this.workerData.verbose ?? this.verbose;
|
|
33
35
|
this.useTracker = this.workerData.tracker ?? this.useTracker;
|
|
34
36
|
}
|
|
37
|
+
this.log = new AnsiLogger({
|
|
38
|
+
logName: this.name,
|
|
39
|
+
logNameColor: MAGENTA,
|
|
40
|
+
logTimestampFormat: 4,
|
|
41
|
+
logLevel: this.debug ? "debug" : "info",
|
|
42
|
+
});
|
|
35
43
|
if (this.useTracker) {
|
|
36
44
|
void import('@matterbridge/utils/tracker')
|
|
37
45
|
.then(({ Tracker }) => {
|
|
38
|
-
this.tracker = new Tracker(`Thread${this.name}`, this.debug, this.verbose);
|
|
46
|
+
this.tracker = new Tracker(`Thread${this.name}`, this.debug || this.useTracker, this.verbose, this.useTracker);
|
|
39
47
|
this.tracker.start();
|
|
40
48
|
return;
|
|
41
49
|
})
|
|
42
50
|
.catch((err) => {
|
|
43
|
-
|
|
44
|
-
console.error(`WorkerWrapper ${this.name}: failed to load Tracker ${getErrorMessage(err)}`);
|
|
51
|
+
this.safeParentLog("error", `ThreadsWrapper ${this.name}: failed to load Tracker ${getErrorMessage(err)}`);
|
|
45
52
|
return;
|
|
46
53
|
});
|
|
47
54
|
}
|
|
48
|
-
this.log = new AnsiLogger({
|
|
49
|
-
logName: this.name,
|
|
50
|
-
logNameColor: MAGENTA,
|
|
51
|
-
logTimestampFormat: 4,
|
|
52
|
-
logLevel: this.debug ? "debug" : "info",
|
|
53
|
-
});
|
|
54
55
|
this.server = new BroadcastServer('matterbridge', this.log);
|
|
55
56
|
if (!isMainThread) {
|
|
56
57
|
process.on('unhandledRejection', this.boundUnhandledRejectionHandler);
|
|
@@ -66,8 +67,11 @@ export class WorkerWrapper {
|
|
|
66
67
|
this.parentPost({ type: 'pong', threadId, threadName: this.name });
|
|
67
68
|
this.parentLog(this.name, "debug", `Worker ${this.name}:${threadId} sent pong message type to parent: ${debugStringify(message)}`);
|
|
68
69
|
break;
|
|
69
|
-
case '
|
|
70
|
-
|
|
70
|
+
case 'startup':
|
|
71
|
+
setImmediate(() => this.emit('startup'));
|
|
72
|
+
break;
|
|
73
|
+
case 'shutdown':
|
|
74
|
+
setImmediate(() => this.emit('shutdown'));
|
|
71
75
|
break;
|
|
72
76
|
default:
|
|
73
77
|
this.parentLog(this.name, "warn", `Worker ${this.name}:${threadId} received unknown message type from parent: ${debugStringify(message)}`);
|
|
@@ -90,13 +94,14 @@ export class WorkerWrapper {
|
|
|
90
94
|
void (async () => {
|
|
91
95
|
let success = false;
|
|
92
96
|
try {
|
|
93
|
-
success = await
|
|
97
|
+
success = await entrypoint(this);
|
|
94
98
|
}
|
|
95
99
|
catch (err) {
|
|
96
|
-
inspectError(this.log, `Worker ${this.name}
|
|
100
|
+
inspectError(this.log, `Worker ${this.name} entrypoint failed`, err);
|
|
97
101
|
}
|
|
98
102
|
finally {
|
|
99
|
-
this.
|
|
103
|
+
if (!success || this.workerData?.type !== 'thread')
|
|
104
|
+
this.destroy(success);
|
|
100
105
|
}
|
|
101
106
|
})();
|
|
102
107
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isArchiveWorkerData } from '@matterbridge/types';
|
|
2
2
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
3
|
-
import {
|
|
3
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
4
4
|
import { createZip, readZip, unZip } from './zipjs.js';
|
|
5
5
|
logModuleLoaded('ArchiveCommand', '\u001B[35m');
|
|
6
|
-
export default new
|
|
6
|
+
export default new ThreadsWrapper('ArchiveCommand', async (worker) => {
|
|
7
7
|
if (!isArchiveWorkerData(worker.workerData)) {
|
|
8
8
|
worker.logger("error", `ArchiveCommand invalid parameters`);
|
|
9
9
|
return false;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { inspectError } from '@matterbridge/utils/error';
|
|
2
2
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
3
3
|
import { checkUpdates } from './checkUpdates.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
5
5
|
logModuleLoaded('CheckUpdates', '\u001B[35m');
|
|
6
|
-
export default new
|
|
6
|
+
export default new ThreadsWrapper('CheckUpdates', async (worker) => {
|
|
7
7
|
worker.logger("info", `Starting check updates...`);
|
|
8
8
|
let success = false;
|
|
9
9
|
try {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -3,9 +3,9 @@ import { inspectError } from '@matterbridge/utils/error';
|
|
|
3
3
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
4
4
|
import { debugStringify } from 'node-ansi-logger';
|
|
5
5
|
import { getDockerVersion, takeDockerVersionWarning } from './dockerVersion.js';
|
|
6
|
-
import {
|
|
6
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
7
7
|
logModuleLoaded('DockerVersion', '\u001B[35m');
|
|
8
|
-
export default new
|
|
8
|
+
export default new ThreadsWrapper('DockerVersion', async (worker) => {
|
|
9
9
|
worker.logger("info", `Starting docker version check...`);
|
|
10
10
|
let success = false;
|
|
11
11
|
let dockerBuildConfig;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { inspectError } from '@matterbridge/utils/error';
|
|
2
2
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
3
3
|
import { getGlobalNodeModules } from '@matterbridge/utils/npm-prefix';
|
|
4
|
-
import {
|
|
4
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
5
5
|
logModuleLoaded('GlobalPrefix', '\u001B[35m');
|
|
6
|
-
export default new
|
|
6
|
+
export default new ThreadsWrapper('GlobalPrefix', async (worker) => {
|
|
7
7
|
let prefix;
|
|
8
8
|
worker.logger("info", `Starting global prefix check...`);
|
|
9
9
|
let success = false;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isSpawnWorkerData } from '@matterbridge/types';
|
|
2
2
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
3
3
|
import { spawnCommand } from './spawnCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
5
5
|
logModuleLoaded('SpawnCommand', '\u001B[35m');
|
|
6
|
-
export default new
|
|
6
|
+
export default new ThreadsWrapper('SpawnCommand', async (worker) => {
|
|
7
7
|
if (!isSpawnWorkerData(worker.workerData)) {
|
|
8
8
|
worker.logger("error", `SpawnCommand invalid parameters`);
|
|
9
9
|
return false;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
2
|
+
declare const _default: ThreadsWrapper;
|
|
3
3
|
export default _default;
|
|
@@ -3,9 +3,9 @@ import { getBunLatestVersion, getBunVersion, isBun } from '@matterbridge/utils/b
|
|
|
3
3
|
import { inspectError } from '@matterbridge/utils/error';
|
|
4
4
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
5
5
|
import { excludedInterfaceNamePattern } from '@matterbridge/utils/network';
|
|
6
|
-
import {
|
|
6
|
+
import { ThreadsWrapper } from './threadsWrapper.js';
|
|
7
7
|
logModuleLoaded('SystemCheck', '\u001B[35m');
|
|
8
|
-
export default new
|
|
8
|
+
export default new ThreadsWrapper('SystemCheck', async (worker) => {
|
|
9
9
|
worker.logger("info", `Starting system check...`);
|
|
10
10
|
let success = false;
|
|
11
11
|
try {
|
package/dist/zipjs.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from '@zip.js/zip.js';
|
|
3
|
+
import { configure, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from '@zip.js/zip.js';
|
|
4
4
|
import { AnsiLogger } from 'node-ansi-logger';
|
|
5
|
+
configure({ useWebWorkers: false });
|
|
5
6
|
export async function createZip(zipPath, sourcePaths) {
|
|
6
7
|
if (sourcePaths.length === 0)
|
|
7
8
|
throw new Error('No files or directories provided to createZip.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/thread",
|
|
3
|
-
"version": "3.10.13-dev-
|
|
3
|
+
"version": "3.10.13-dev-20261008-55d98fb",
|
|
4
4
|
"description": "Matterbridge thread library",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"homepage": "https://matterbridge.io/",
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
"./manager": {
|
|
58
58
|
"types": "./dist/threadsManager.d.ts",
|
|
59
59
|
"import": "./dist/threadsManager.js"
|
|
60
|
+
},
|
|
61
|
+
"./wrapper": {
|
|
62
|
+
"types": "./dist/threadsWrapper.d.ts",
|
|
63
|
+
"import": "./dist/threadsWrapper.js"
|
|
60
64
|
}
|
|
61
65
|
},
|
|
62
66
|
"engines": {
|
|
@@ -75,8 +79,9 @@
|
|
|
75
79
|
"skipTsconfig": true
|
|
76
80
|
},
|
|
77
81
|
"dependencies": {
|
|
78
|
-
"@
|
|
79
|
-
"@matterbridge/
|
|
82
|
+
"@matter/main": "0.17.9",
|
|
83
|
+
"@matterbridge/types": "3.10.13-dev-20261008-55d98fb",
|
|
84
|
+
"@matterbridge/utils": "3.10.13-dev-20261008-55d98fb",
|
|
80
85
|
"@zip.js/zip.js": "2.22.0",
|
|
81
86
|
"node-ansi-logger": "3.3.1"
|
|
82
87
|
}
|