@scrypted/server 0.6.24 → 0.7.2
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.
Potentially problematic release.
This version of @scrypted/server might be problematic. Click here for more details.
- package/dist/http-interfaces.js +4 -1
- package/dist/http-interfaces.js.map +1 -1
- package/dist/listen-zero.js +5 -2
- package/dist/listen-zero.js.map +1 -1
- package/dist/plugin/media.js +25 -20
- package/dist/plugin/media.js.map +1 -1
- package/dist/plugin/plugin-console.js +157 -4
- package/dist/plugin/plugin-console.js.map +1 -1
- package/dist/plugin/plugin-device.js +2 -0
- package/dist/plugin/plugin-device.js.map +1 -1
- package/dist/plugin/plugin-host.js +5 -0
- package/dist/plugin/plugin-host.js.map +1 -1
- package/dist/plugin/plugin-remote-stats.js +30 -0
- package/dist/plugin/plugin-remote-stats.js.map +1 -0
- package/dist/plugin/plugin-remote-worker.js +69 -149
- package/dist/plugin/plugin-remote-worker.js.map +1 -1
- package/dist/plugin/plugin-repl.js +4 -1
- package/dist/plugin/plugin-repl.js.map +1 -1
- package/dist/plugin/runtime/python-worker.js +1 -0
- package/dist/plugin/runtime/python-worker.js.map +1 -1
- package/dist/plugin/system.js +4 -0
- package/dist/plugin/system.js.map +1 -1
- package/dist/rpc.js +183 -45
- package/dist/rpc.js.map +1 -1
- package/dist/runtime.js +3 -0
- package/dist/runtime.js.map +1 -1
- package/dist/threading.js +1 -0
- package/dist/threading.js.map +1 -1
- package/package.json +3 -4
- package/python/plugin_remote.py +134 -51
- package/python/rpc-iterator-test.py +45 -0
- package/python/rpc.py +168 -50
- package/python/rpc_reader.py +57 -60
- package/src/http-interfaces.ts +5 -1
- package/src/listen-zero.ts +6 -2
- package/src/plugin/media.ts +38 -35
- package/src/plugin/plugin-api.ts +4 -1
- package/src/plugin/plugin-console.ts +154 -6
- package/src/plugin/plugin-device.ts +3 -0
- package/src/plugin/plugin-host.ts +5 -0
- package/src/plugin/plugin-remote-stats.ts +36 -0
- package/src/plugin/plugin-remote-worker.ts +77 -178
- package/src/plugin/plugin-remote.ts +1 -1
- package/src/plugin/plugin-repl.ts +4 -1
- package/src/plugin/runtime/python-worker.ts +2 -0
- package/src/plugin/system.ts +6 -0
- package/src/rpc.ts +230 -52
- package/src/runtime.ts +3 -0
- package/src/threading.ts +2 -0
- package/test/rpc-iterator-test.ts +46 -0
- package/test/rpc-python-test.ts +44 -0
package/src/plugin/media.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { BufferConverter, DeviceManager, FFmpegInput, MediaManager, MediaObject, MediaObjectOptions, MediaStreamUrl, ScryptedDevice, ScryptedInterface, ScryptedInterfaceProperty, ScryptedMimeTypes, ScryptedNativeId, SystemDeviceState, SystemManager } from "@scrypted/types";
|
1
|
+
import { BufferConverter, DeviceManager, FFmpegInput, MediaManager, MediaObject as MediaObjectInterface, MediaObjectOptions, MediaStreamUrl, ScryptedDevice, ScryptedInterface, ScryptedInterfaceProperty, ScryptedMimeTypes, ScryptedNativeId, SystemDeviceState, SystemManager } from "@scrypted/types";
|
2
2
|
import axios from 'axios';
|
3
3
|
import pathToFfmpeg from 'ffmpeg-static';
|
4
4
|
import fs from 'fs';
|
@@ -9,8 +9,28 @@ import Graph from 'node-dijkstra';
|
|
9
9
|
import os from 'os';
|
10
10
|
import path from 'path';
|
11
11
|
import MimeType from 'whatwg-mimetype';
|
12
|
+
import { RpcPeer } from "../rpc";
|
12
13
|
import { MediaObjectRemote } from "./plugin-api";
|
13
14
|
|
15
|
+
class MediaObject implements MediaObjectRemote {
|
16
|
+
__proxy_props: any;
|
17
|
+
|
18
|
+
constructor(public mimeType: string, public data: any, options: MediaObjectOptions) {
|
19
|
+
this.__proxy_props = {}
|
20
|
+
options ||= {};
|
21
|
+
options.mimeType = mimeType;
|
22
|
+
for (const [key, value] of Object.entries(options)) {
|
23
|
+
if (RpcPeer.isTransportSafe(value))
|
24
|
+
this.__proxy_props[key] = value;
|
25
|
+
(this as any)[key] = value;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
async getData(): Promise<Buffer | string> {
|
30
|
+
return Promise.resolve(this.data);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
14
34
|
function typeMatches(target: string, candidate: string): boolean {
|
15
35
|
// candidate will accept anything
|
16
36
|
if (candidate === '*' || target === '*')
|
@@ -164,7 +184,7 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
164
184
|
this.extraConverters = [];
|
165
185
|
}
|
166
186
|
|
167
|
-
async convertMediaObjectToJSON<T>(mediaObject:
|
187
|
+
async convertMediaObjectToJSON<T>(mediaObject: MediaObjectInterface, toMimeType: string): Promise<T> {
|
168
188
|
const buffer = await this.convertMediaObjectToBuffer(mediaObject, toMimeType);
|
169
189
|
return JSON.parse(buffer.toString());
|
170
190
|
}
|
@@ -231,7 +251,7 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
231
251
|
return converters;
|
232
252
|
}
|
233
253
|
|
234
|
-
ensureMediaObjectRemote(mediaObject: string |
|
254
|
+
ensureMediaObjectRemote(mediaObject: string | MediaObjectInterface): MediaObjectRemote {
|
235
255
|
if (typeof mediaObject === 'string') {
|
236
256
|
const mime = mimeType.getType(mediaObject);
|
237
257
|
return this.createMediaObjectRemote(mediaObject, mime);
|
@@ -239,36 +259,36 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
239
259
|
return mediaObject as MediaObjectRemote;
|
240
260
|
}
|
241
261
|
|
242
|
-
async convertMediaObject<T>(mediaObject:
|
262
|
+
async convertMediaObject<T>(mediaObject: MediaObjectInterface, toMimeType: string): Promise<T> {
|
243
263
|
const converted = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
244
264
|
return converted.data;
|
245
265
|
}
|
246
266
|
|
247
|
-
async convertMediaObjectToInsecureLocalUrl(mediaObject: string |
|
267
|
+
async convertMediaObjectToInsecureLocalUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string> {
|
248
268
|
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
249
269
|
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
250
270
|
const url = await this.convert(this.getConverters(), converted, ScryptedMimeTypes.InsecureLocalUrl);
|
251
271
|
return url.data.toString();
|
252
272
|
}
|
253
273
|
|
254
|
-
async convertMediaObjectToBuffer(mediaObject:
|
274
|
+
async convertMediaObjectToBuffer(mediaObject: MediaObjectInterface, toMimeType: string): Promise<Buffer> {
|
255
275
|
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
256
276
|
return intermediate.data as Buffer;
|
257
277
|
}
|
258
|
-
async convertMediaObjectToLocalUrl(mediaObject: string |
|
278
|
+
async convertMediaObjectToLocalUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string> {
|
259
279
|
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
260
280
|
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
261
281
|
const url = await this.convert(this.getConverters(), converted, ScryptedMimeTypes.LocalUrl);
|
262
282
|
return url.data.toString();
|
263
283
|
}
|
264
|
-
async convertMediaObjectToUrl(mediaObject: string |
|
284
|
+
async convertMediaObjectToUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string> {
|
265
285
|
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
266
286
|
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
267
287
|
const url = await this.convert(this.getConverters(), converted, ScryptedMimeTypes.Url);
|
268
288
|
return url.data.toString();
|
269
289
|
}
|
270
290
|
|
271
|
-
createMediaObjectRemote(data: any | Buffer | Promise<string | Buffer>, mimeType: string, options?:
|
291
|
+
createMediaObjectRemote<T extends MediaObjectOptions>(data: any | Buffer | Promise<string | Buffer>, mimeType: string, options?: T): MediaObjectRemote & T {
|
272
292
|
if (typeof data === 'string')
|
273
293
|
throw new Error('string is not a valid type. if you intended to send a url, use createMediaObjectFromUrl.');
|
274
294
|
if (!mimeType)
|
@@ -280,26 +300,19 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
280
300
|
data = Buffer.from(JSON.stringify(data));
|
281
301
|
|
282
302
|
const sourceId = typeof options?.sourceId === 'string' ? options?.sourceId : this.getPluginDeviceId();
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
sourceId,
|
287
|
-
}
|
288
|
-
|
289
|
-
mimeType = mimeType;
|
290
|
-
sourceId = sourceId;
|
291
|
-
async getData(): Promise<Buffer | string> {
|
292
|
-
return Promise.resolve(data);
|
293
|
-
}
|
303
|
+
if (sourceId) {
|
304
|
+
options ||= {} as T;
|
305
|
+
options.sourceId = sourceId;
|
294
306
|
}
|
295
|
-
|
307
|
+
|
308
|
+
return new MediaObject(mimeType, data, options) as MediaObject & T;
|
296
309
|
}
|
297
310
|
|
298
|
-
async createFFmpegMediaObject(ffMpegInput: FFmpegInput, options?: MediaObjectOptions): Promise<
|
311
|
+
async createFFmpegMediaObject(ffMpegInput: FFmpegInput, options?: MediaObjectOptions): Promise<MediaObjectInterface> {
|
299
312
|
return this.createMediaObjectRemote(Buffer.from(JSON.stringify(ffMpegInput)), ScryptedMimeTypes.FFmpegInput, options);
|
300
313
|
}
|
301
314
|
|
302
|
-
async createMediaObjectFromUrl(data: string, options?: MediaObjectOptions): Promise<
|
315
|
+
async createMediaObjectFromUrl(data: string, options?: MediaObjectOptions): Promise<MediaObjectInterface> {
|
303
316
|
const url = new URL(data);
|
304
317
|
const scheme = url.protocol.slice(0, -1);
|
305
318
|
const mimeType = ScryptedMimeTypes.SchemePrefix + scheme;
|
@@ -320,7 +333,7 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
320
333
|
return new MediaObjectImpl();
|
321
334
|
}
|
322
335
|
|
323
|
-
async createMediaObject(data: any, mimeType: string, options?:
|
336
|
+
async createMediaObject<T extends MediaObjectOptions>(data: any, mimeType: string, options?: T): Promise<MediaObjectInterface & T> {
|
324
337
|
return this.createMediaObjectRemote(data, mimeType, options);
|
325
338
|
}
|
326
339
|
|
@@ -423,7 +436,7 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
423
436
|
}
|
424
437
|
|
425
438
|
if (converter.toMimeType === ScryptedMimeTypes.MediaObject) {
|
426
|
-
const mo = await converter.convert(value, valueMime.essence, toMimeType, { sourceId }) as
|
439
|
+
const mo = await converter.convert(value, valueMime.essence, toMimeType, { sourceId }) as MediaObjectInterface;
|
427
440
|
const found = await this.convertMediaObject(mo, toMimeType);
|
428
441
|
return {
|
429
442
|
data: found,
|
@@ -445,16 +458,6 @@ export abstract class MediaManagerBase implements MediaManager {
|
|
445
458
|
export class MediaManagerImpl extends MediaManagerBase {
|
446
459
|
constructor(public systemManager: SystemManager, public deviceManager: DeviceManager) {
|
447
460
|
super();
|
448
|
-
|
449
|
-
this.builtinConverters.push({
|
450
|
-
id: getBuiltinId(this.builtinConverters.length),
|
451
|
-
name: 'ScryptedDeviceId to ScryptedDevice Converter',
|
452
|
-
fromMimeType: ScryptedMimeTypes.ScryptedDeviceId,
|
453
|
-
toMimeType: ScryptedMimeTypes.ScryptedDevice,
|
454
|
-
convert: async (data, fromMimeType, toMimeType) => {
|
455
|
-
return this.getDeviceById(data.toString());
|
456
|
-
}
|
457
|
-
});
|
458
461
|
}
|
459
462
|
|
460
463
|
getSystemState(): { [id: string]: { [property: string]: SystemDeviceState; }; } {
|
package/src/plugin/plugin-api.ts
CHANGED
@@ -168,10 +168,13 @@ export interface PluginRemoteLoadZipOptions {
|
|
168
168
|
*/
|
169
169
|
unzippedPath?: string;
|
170
170
|
fork?: boolean;
|
171
|
+
|
172
|
+
clusterId: string;
|
173
|
+
clusterSecret: string;
|
171
174
|
}
|
172
175
|
|
173
176
|
export interface PluginRemote {
|
174
|
-
loadZip(packageJson: any, zipData: Buffer | string, options
|
177
|
+
loadZip(packageJson: any, zipData: Buffer | string, options: PluginRemoteLoadZipOptions): Promise<any>;
|
175
178
|
setSystemState(state: { [id: string]: { [property: string]: SystemDeviceState } }): Promise<void>;
|
176
179
|
setNativeId(nativeId: ScryptedNativeId, id: string, storage: { [key: string]: any }): Promise<void>;
|
177
180
|
updateDeviceState(id: string, state: { [property: string]: SystemDeviceState }): Promise<void>;
|
@@ -1,10 +1,9 @@
|
|
1
|
-
import { ScryptedNativeId } from '@scrypted/types'
|
2
|
-
import { listenZero } from '../listen-zero';
|
3
|
-
import { Server } from 'net';
|
4
|
-
import { once } from 'events';
|
5
|
-
import net from 'net'
|
6
|
-
import { Readable, PassThrough } from 'stream';
|
1
|
+
import { DeviceManager, ScryptedNativeId, SystemManager } from '@scrypted/types';
|
7
2
|
import { Console } from 'console';
|
3
|
+
import { once } from 'events';
|
4
|
+
import net, { Server } from 'net';
|
5
|
+
import { PassThrough, Readable } from 'stream';
|
6
|
+
import { listenZero } from '../listen-zero';
|
8
7
|
|
9
8
|
export interface ConsoleServer {
|
10
9
|
pluginConsole: Console;
|
@@ -20,6 +19,155 @@ export interface StdPassThroughs {
|
|
20
19
|
buffers: Buffer[];
|
21
20
|
}
|
22
21
|
|
22
|
+
export function getConsole(hook: (stdout: PassThrough, stderr: PassThrough) => Promise<void>,
|
23
|
+
also?: Console, alsoPrefix?: string) {
|
24
|
+
|
25
|
+
const stdout = new PassThrough();
|
26
|
+
const stderr = new PassThrough();
|
27
|
+
|
28
|
+
hook(stdout, stderr);
|
29
|
+
|
30
|
+
const ret = new Console(stdout, stderr);
|
31
|
+
|
32
|
+
const methods = [
|
33
|
+
'log', 'warn',
|
34
|
+
'dir', 'timeLog',
|
35
|
+
'trace', 'assert',
|
36
|
+
'clear', 'count',
|
37
|
+
'countReset', 'group',
|
38
|
+
'groupEnd', 'table',
|
39
|
+
'debug', 'info',
|
40
|
+
'dirxml', 'error',
|
41
|
+
'groupCollapsed',
|
42
|
+
];
|
43
|
+
|
44
|
+
const printers = ['log', 'info', 'debug', 'trace', 'warn', 'error'];
|
45
|
+
for (const m of methods) {
|
46
|
+
const old = (ret as any)[m].bind(ret);
|
47
|
+
(ret as any)[m] = (...args: any[]) => {
|
48
|
+
// prefer the mixin version for local/remote console dump.
|
49
|
+
if (also && alsoPrefix && printers.includes(m)) {
|
50
|
+
(also as any)[m](alsoPrefix, ...args);
|
51
|
+
}
|
52
|
+
else {
|
53
|
+
(console as any)[m](...args);
|
54
|
+
}
|
55
|
+
// call through to old method to ensure it gets written
|
56
|
+
// to log buffer.
|
57
|
+
old(...args);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
return ret;
|
62
|
+
}
|
63
|
+
|
64
|
+
export function prepareConsoles(getConsoleName: () => string, systemManager: () => SystemManager, deviceManager: () => DeviceManager, getPlugins: () => Promise<any>) {
|
65
|
+
const deviceConsoles = new Map<string, Console>();
|
66
|
+
function getDeviceConsole (nativeId?: ScryptedNativeId) {
|
67
|
+
// the the plugin console is simply the default console
|
68
|
+
// and gets read from stderr/stdout.
|
69
|
+
if (!nativeId)
|
70
|
+
return console;
|
71
|
+
|
72
|
+
let ret = deviceConsoles.get(nativeId);
|
73
|
+
if (ret)
|
74
|
+
return ret;
|
75
|
+
|
76
|
+
ret = getConsole(async (stdout, stderr) => {
|
77
|
+
const connect = async () => {
|
78
|
+
const plugins = await getPlugins();
|
79
|
+
const port = await plugins.getRemoteServicePort(getConsoleName(), 'console-writer');
|
80
|
+
const socket = net.connect(port);
|
81
|
+
socket.write(nativeId + '\n');
|
82
|
+
const writer = (data: Buffer) => {
|
83
|
+
socket.write(data);
|
84
|
+
};
|
85
|
+
stdout.on('data', writer);
|
86
|
+
stderr.on('data', writer);
|
87
|
+
socket.on('error', () => {
|
88
|
+
stdout.removeAllListeners();
|
89
|
+
stderr.removeAllListeners();
|
90
|
+
stdout.pause();
|
91
|
+
stderr.pause();
|
92
|
+
setTimeout(connect, 10000);
|
93
|
+
});
|
94
|
+
};
|
95
|
+
connect();
|
96
|
+
}, undefined, undefined);
|
97
|
+
|
98
|
+
deviceConsoles.set(nativeId, ret);
|
99
|
+
return ret;
|
100
|
+
}
|
101
|
+
|
102
|
+
const mixinConsoles = new Map<string, Map<string, Console>>();
|
103
|
+
|
104
|
+
function getMixinConsole(mixinId: string, nativeId: ScryptedNativeId) {
|
105
|
+
let nativeIdConsoles = mixinConsoles.get(nativeId);
|
106
|
+
if (!nativeIdConsoles) {
|
107
|
+
nativeIdConsoles = new Map();
|
108
|
+
mixinConsoles.set(nativeId, nativeIdConsoles);
|
109
|
+
}
|
110
|
+
|
111
|
+
let ret = nativeIdConsoles.get(mixinId);
|
112
|
+
if (ret)
|
113
|
+
return ret;
|
114
|
+
|
115
|
+
ret = getConsole(async (stdout, stderr) => {
|
116
|
+
if (!mixinId) {
|
117
|
+
return;
|
118
|
+
}
|
119
|
+
const reconnect = () => {
|
120
|
+
stdout.removeAllListeners();
|
121
|
+
stderr.removeAllListeners();
|
122
|
+
stdout.pause();
|
123
|
+
stderr.pause();
|
124
|
+
setTimeout(tryConnect, 10000);
|
125
|
+
};
|
126
|
+
|
127
|
+
const connect = async () => {
|
128
|
+
const ds = deviceManager().getDeviceState(nativeId);
|
129
|
+
if (!ds) {
|
130
|
+
// deleted?
|
131
|
+
return;
|
132
|
+
}
|
133
|
+
|
134
|
+
const plugins = await getPlugins();
|
135
|
+
const { pluginId, nativeId: mixinNativeId } = await plugins.getDeviceInfo(mixinId);
|
136
|
+
const port = await plugins.getRemoteServicePort(pluginId, 'console-writer');
|
137
|
+
const socket = net.connect(port);
|
138
|
+
socket.write(mixinNativeId + '\n');
|
139
|
+
const writer = (data: Buffer) => {
|
140
|
+
let str = data.toString().trim();
|
141
|
+
str = str.replaceAll('\n', `\n[${ds.name}]: `);
|
142
|
+
str = `[${ds.name}]: ` + str + '\n';
|
143
|
+
socket.write(str);
|
144
|
+
};
|
145
|
+
stdout.on('data', writer);
|
146
|
+
stderr.on('data', writer);
|
147
|
+
socket.on('close', reconnect);
|
148
|
+
};
|
149
|
+
|
150
|
+
const tryConnect = async () => {
|
151
|
+
try {
|
152
|
+
await connect();
|
153
|
+
}
|
154
|
+
catch (e) {
|
155
|
+
reconnect();
|
156
|
+
}
|
157
|
+
}
|
158
|
+
tryConnect();
|
159
|
+
}, getDeviceConsole(nativeId), `[${systemManager().getDeviceById(mixinId)?.name}]`);
|
160
|
+
|
161
|
+
nativeIdConsoles.set(mixinId, ret);
|
162
|
+
return ret;
|
163
|
+
}
|
164
|
+
|
165
|
+
return {
|
166
|
+
getDeviceConsole,
|
167
|
+
getMixinConsole,
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
23
171
|
export async function createConsoleServer(remoteStdout: Readable, remoteStderr: Readable, header: string) {
|
24
172
|
const outputs = new Map<string, StdPassThroughs>();
|
25
173
|
|
@@ -352,6 +352,9 @@ export class PluginDeviceProxyHandler implements PrimitiveProxyHandler<any>, Scr
|
|
352
352
|
this.scrypted.stateManager.setPluginDeviceState(device, ScryptedInterfaceProperty.type, type);
|
353
353
|
this.scrypted.stateManager.updateDescriptor(device);
|
354
354
|
}
|
355
|
+
async setMixins(mixins: string[]): Promise<void> {
|
356
|
+
|
357
|
+
}
|
355
358
|
|
356
359
|
async probe(): Promise<boolean> {
|
357
360
|
try {
|
@@ -41,6 +41,9 @@ export class PluginHost {
|
|
41
41
|
scrypted: ScryptedRuntime;
|
42
42
|
remote: PluginRemote;
|
43
43
|
io: IOServer = new io.Server({
|
44
|
+
// object detection drag drop 4k can be massive.
|
45
|
+
// streaming support somehow?
|
46
|
+
maxHttpBufferSize: 20000000,
|
44
47
|
pingTimeout: 120000,
|
45
48
|
perMessageDeflate: true,
|
46
49
|
cors: (req, callback) => {
|
@@ -242,6 +245,8 @@ export class PluginHost {
|
|
242
245
|
try {
|
243
246
|
const isPython = runtime === 'python';
|
244
247
|
const loadZipOptions: PluginRemoteLoadZipOptions = {
|
248
|
+
clusterId: scrypted.clusterId,
|
249
|
+
clusterSecret: scrypted.clusterSecret,
|
245
250
|
// if debugging, use a normalized path for sourcemap resolution, otherwise
|
246
251
|
// prefix with module path.
|
247
252
|
filename: isPython
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { NodeThreadWorker } from "./runtime/node-thread-worker";
|
2
|
+
|
3
|
+
export interface PluginStats {
|
4
|
+
type: 'stats',
|
5
|
+
cpu: NodeJS.CpuUsage;
|
6
|
+
memoryUsage: NodeJS.MemoryUsage;
|
7
|
+
}
|
8
|
+
|
9
|
+
export function startStatsUpdater(allMemoryStats: Map<NodeThreadWorker, NodeJS.MemoryUsage>, updateStats: (stats: PluginStats) => void) {
|
10
|
+
setInterval(() => {
|
11
|
+
const cpuUsage = process.cpuUsage();
|
12
|
+
allMemoryStats.set(undefined, process.memoryUsage());
|
13
|
+
|
14
|
+
const memoryUsage: NodeJS.MemoryUsage = {
|
15
|
+
rss: 0,
|
16
|
+
heapTotal: 0,
|
17
|
+
heapUsed: 0,
|
18
|
+
external: 0,
|
19
|
+
arrayBuffers: 0,
|
20
|
+
}
|
21
|
+
|
22
|
+
for (const mu of allMemoryStats.values()) {
|
23
|
+
memoryUsage.rss += mu.rss;
|
24
|
+
memoryUsage.heapTotal += mu.heapTotal;
|
25
|
+
memoryUsage.heapUsed += mu.heapUsed;
|
26
|
+
memoryUsage.external += mu.external;
|
27
|
+
memoryUsage.arrayBuffers += mu.arrayBuffers;
|
28
|
+
}
|
29
|
+
|
30
|
+
updateStats({
|
31
|
+
type: 'stats',
|
32
|
+
cpu: cpuUsage,
|
33
|
+
memoryUsage,
|
34
|
+
});
|
35
|
+
}, 10000);
|
36
|
+
}
|