dcp-worker 3.2.30-2 → 3.2.30-4

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.
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @file worker-loggers/dashboard.js
3
+ * @author Ryan Rossiter, ryan@kingsds.network
4
+ * @date April 2020
5
+ * @author Wes Garland, wes@distributive.network
6
+ * @date June 2023
7
+ *
8
+ * This module uses the blessed library to create a monitoring dashboard for the worker.
9
+ * A corresponding worker-logger, dashboard.js, knows how to log to this dashboard.
10
+ */
11
+ 'use strict';
12
+
13
+ const dcpConfig = require('dcp/dcp-config');
14
+ const chalk = require('chalk');
15
+ const blessed = require('blessed');
16
+ const contrib = require('blessed-contrib');
17
+ const components = require('./blessed-components');
18
+ const utils = require('../lib/utils');
19
+
20
+ const { replaceWorkerEvent, replaceSandboxEvent } = require('./default-ui-events');
21
+
22
+ const SLICE_FETCH_STATUS = {
23
+ IDLE: chalk.yellow('Idle'),
24
+ FETCHING: chalk.blue('Fetching Work...'),
25
+ WORKING: chalk.green('Working'),
26
+ NO_WORK: chalk.red('No Work Available'),
27
+ }
28
+
29
+ const usingDebugger = require('module')._cache.niim instanceof require('module').Module;
30
+ const screenConf = {
31
+ input: usingDebugger ? new (require('events').EventEmitter) : undefined,
32
+ output: usingDebugger ? new (require('events').EventEmitter) : undefined,
33
+ };
34
+ /**
35
+ */
36
+ exports.init = function dashboard$$init(worker, options)
37
+ {
38
+ var sliceFetchStatus = SLICE_FETCH_STATUS.IDLE;
39
+ var totalDCCs = 0;
40
+ const screen = blessed.screen(screenConf);
41
+ const grid = new contrib.grid({rows: 3, cols: 5, screen});
42
+ const workerInfoPane = grid.set(2, 0, 1, 5, blessed.text);
43
+
44
+ const logPane = grid.set(0, 2, 2, 3, components.log, {
45
+ label: 'Worker Log',
46
+ scrollable: true,
47
+ alwaysScroll: true,
48
+ mouse: true,
49
+ scrollbar: {
50
+ bg: 'blue',
51
+ },
52
+ });
53
+
54
+ const sandboxPane = grid.set(0, 0, 2, 2, components.sandboxes, {
55
+ label: 'Sandboxes',
56
+ defaultProgressBars: 0,
57
+ scrollable: true,
58
+ alwaysScroll: true,
59
+ mouse: true,
60
+ scrollbar: {
61
+ bg: 'blue',
62
+ },
63
+ });
64
+
65
+ delete exports.init; /* singleton */
66
+
67
+ if (!usingDebugger)
68
+ exports.logPane = logPane; /* now dashboard log can find the pane */
69
+ setInterval(() => screen.render(), 50).unref(); /* 50ms = 20 fps */
70
+ updateWorkerInfo();
71
+ screen.render();
72
+
73
+ /* Apply key bindings which mimic canonical input mode */
74
+ screen.key(['C-c'], () => raise('SIGINT'));
75
+ screen.key(['C-z'], () => raise('SIGTSTP'));
76
+ screen.key(['\u001c'], () => raise('SIGQUIT')); /* C-\ */
77
+
78
+ screen.key(['escape'], () => {
79
+ console.log('Stopping worker...');
80
+ worker.stop();
81
+ });
82
+
83
+ function updateWorkerInfo()
84
+ {
85
+ const workerOptions = worker.workerOptions;
86
+
87
+ workerInfoPane.setLabel(`Worker Status [${sliceFetchStatus}]`);
88
+ workerInfoPane.setContent([
89
+ chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))}`),
90
+ '',
91
+ ` Scheduler: ${chalk.yellow(dcpConfig.scheduler.location.href)}`,
92
+ ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
93
+ `Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
94
+ ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
95
+ ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
96
+ ` Priv Groups: ${Object.keys(workerOptions.computeGroups).length}`,
97
+ ` Pub Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
98
+ ].join('\n'));
99
+ }
100
+
101
+ /* Override default event behaviour to work better with the Dashboard. */
102
+
103
+ /** XXXpfr @todo Is this correct? Or should we init progressData inside 'slice' like we used to. */
104
+ replaceSandboxEvent('ready', function dashboard$$job(sandbox, sandboxData, ev) {
105
+ sandboxData.progressData = {
106
+ indeterminate: true,
107
+ progress: 0,
108
+ label: sandbox?.public ? sandbox.public.name: '<no-label>',
109
+ };
110
+ });
111
+
112
+ replaceSandboxEvent('slice', function dashboard$$slice(sandbox, sandboxData, ev) {
113
+ sandboxPane.data.push(sandboxData.progressData);
114
+ sandboxPane.update();
115
+ });
116
+
117
+ replaceSandboxEvent('progress', function dashboard$$progress(sandbox, sandboxData, ev) {
118
+ if (!ev)
119
+ {
120
+ sandboxData.progressData.progress = 100;
121
+ setTimeout(() => {
122
+ if (sandboxData.progressData.indeterminate)
123
+ {
124
+ sandboxData.progressData.progress = 0;
125
+ sandboxPane.update();
126
+ }
127
+ }, 500).unref();
128
+ }
129
+ else
130
+ {
131
+ sandboxData.progressData.progress = ev;
132
+ sandboxData.progressData.indeterminate = false;
133
+ }
134
+
135
+ sandboxPane.update();
136
+ });
137
+
138
+ replaceSandboxEvent('sliceEnd', function dashboard$$sliceEnd(sandbox, sandboxData, ev) {
139
+ sandboxPane.data = sandboxPane.data.filter(d => d != sandboxData.progressData);
140
+ sandboxData.progressData.progress = 0;
141
+ sandboxPane.update();
142
+ });
143
+
144
+ replaceSandboxEvent('end', function dashboard$$end(sandbox, sandboxData, ev) {
145
+ sandboxPane.data = sandboxPane.data.filter(d => d != sandboxData.progressData);
146
+ sandboxPane.deleteProgressBar();
147
+ sandboxData.progressData.progress = 0;
148
+ sandboxPane.update();
149
+ });
150
+
151
+ replaceWorkerEvent('beforeFetch', function dashboard$$beforeFetch(ev) {
152
+ sliceFetchStatus = SLICE_FETCH_STATUS.FETCHING;
153
+ updateWorkerInfo();
154
+ });
155
+
156
+ replaceWorkerEvent('fetch', function dashboard$$fetch(ev) {
157
+ sliceFetchStatus = SLICE_FETCH_STATUS.NO_WORK;
158
+ if (ev instanceof Error)
159
+ console.error('Error fetching slices:', ev);
160
+ else if ( !(utils.slicesFetched(ev) === 0 && sandboxPane.data.length === 0))
161
+ sliceFetchStatus = SLICE_FETCH_STATUS.WORKING;
162
+ updateWorkerInfo();
163
+ });
164
+
165
+ worker.on('end', () => { screen.destroy(); });
166
+
167
+ worker.on('sandbox', function dashboard$$sandbox(ev) {
168
+ sandboxPane.createProgressBar();
169
+ sandboxPane.update();
170
+ });
171
+
172
+ worker.on('payment', function dashboard$$payment(ev) {
173
+ const payment = parseFloat(ev);
174
+
175
+ if (!isNaN(payment))
176
+ totalDCCs += payment;
177
+
178
+ sandboxPane.update();
179
+ updateWorkerInfo();
180
+ });
181
+ };
182
+
183
+ /**
184
+ * Send a signal to the caller
185
+ * @param {number|string} sig the signal to raise
186
+ */
187
+ function raise(sig)
188
+ {
189
+ process.kill(process.pid, sig);
190
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @file default-event.js
3
+ * Default worker/sandbox events, providing default logging behaviours (event handlers)
4
+ * for the dcp-worker.
5
+ *
6
+ * - All event handlers use the *current* global console object to emit messages;
7
+ * enhanced logging subsystems should intercept this object to achieve their desired
8
+ * behaviours.
9
+ *
10
+ * - All event handlers invoke functions which are properties of the eventHandlers return
11
+ * value from the hook function. This means that alternate user interfaces can either
12
+ * hook or intercept the properties of that object to modify the event handlers'
13
+ * behaviour without actually removing/replacing the event handler on the instance of
14
+ * Worker.
15
+ *
16
+ * NOTE: This is just a convenience module. There is no requirement to use this module to
17
+ * hook worker events, this module mainly exists to make it easy for the
18
+ * dashboard-tui to replace event handlers with better ones, but it also makes it
19
+ * easier to sandbox events since we only need to register one event handler here
20
+ * to handle every sandbox.
21
+ *
22
+ * @author Ryan Rossiter, ryan@kingsds.network
23
+ * @date April 2020
24
+ * @author Wes Garland, wes@distributive.network
25
+ * @date June 2023
26
+ */
27
+ 'use strict';
28
+
29
+ const utils = require('../lib/utils');
30
+
31
+ const sandboxEventHandlers = {};
32
+ const workerEventHandlers = {};
33
+
34
+ /**
35
+ * Sandbox 1: Slice Started: slice 1, 0x5b5214D48F0428669c4E: Simple Job
36
+ * Sandbox 1: Slice Completed: slice 1, 0x5b5214D48F0428669c4E: Simple Job: dt 114ms
37
+ */
38
+
39
+ /**
40
+ * @param worker The instance of Worker to hook
41
+ * @param options cliArgs from worker
42
+ */
43
+ exports.hook = function hookWorkerEvents$$hook(worker, options)
44
+ {
45
+ const sliceMap = {}; // jobAddress --> ( sliceNumber, t0 )
46
+ const truncationLength = 22; // Extra 2 for '0x'
47
+
48
+ delete exports.hook;
49
+
50
+ function makeSliceId (sandbox, sliceNumber)
51
+ {
52
+ if (!sandbox.jobAddress)
53
+ return '<no job>';
54
+
55
+ const address = sandbox.jobAddress.slice(0, truncationLength);
56
+ const baseInfo = sandbox?.public ? `${address}: ${sandbox.public.name}` : address;
57
+
58
+ if (!sliceNumber)
59
+ sliceNumber = sandbox.sliceNumber;
60
+ return sliceNumber > 0 ? `slice ${sliceNumber}, ${baseInfo}` : baseInfo;
61
+ }
62
+
63
+ sandboxEventHandlers.ready = function sandboxReadyHandler(sandbox, sandboxData, ev) {
64
+ console.log(` . Sandbox ${sandboxData.shortId}: Initialized`);
65
+ };
66
+
67
+ sandboxEventHandlers.slice = function sliceHandler(sandbox, sandboxData, ev) {
68
+ sliceMap[sandbox.id] = { slice: sandbox.sliceNumber, t0: Date.now() };
69
+ console.log(` . Sandbox ${sandboxData.shortId}: Slice Started: ${makeSliceId(sandbox)}`);
70
+ };
71
+
72
+ sandboxEventHandlers.progress = function progressHandler(sandbox, sandboxdData, ev) {
73
+ // Overridden in dashboard-tui.js
74
+ };
75
+
76
+ sandboxEventHandlers.sliceEnd = function sliceEndHandler(sandbox, sandboxData, ev) {
77
+ const sliceInfo = sliceMap[sandbox.id];
78
+ if (sliceInfo)
79
+ console.log(` * Sandbox ${sandboxData.shortId}: Slice Completed: ${makeSliceId(sandbox, sliceInfo.slice)}: dt ${Date.now() - sliceInfo.t0}ms`);
80
+ else
81
+ console.log(` * Sandbox ${sandboxData.shortId}: Slice Completed: ${makeSliceId(sandbox)}`);
82
+ };
83
+
84
+ sandboxEventHandlers.end = function endHandler(sandbox,sandboxData, ev) {
85
+ const sliceInfo = sliceMap[sandbox.id];
86
+ console.log(` * Sandbox ${sandboxData.shortId}: Terminated: ${makeSliceId(sandbox, sliceInfo?.slice)}`);
87
+ delete sliceMap[sandbox.id];
88
+ };
89
+
90
+ workerEventHandlers.payment = function paymentHandler(ev) {
91
+ const payment = parseFloat(ev);
92
+
93
+ if (isNaN(payment))
94
+ console.error(' ! Failed to parse payment:', payment);
95
+ else
96
+ console.log(` . Payment: ${payment.toFixed(3)} ⊇`);
97
+ };
98
+
99
+ workerEventHandlers.beforeFetch = function beforeFetchHandler() {
100
+ options.verbose && console.log(' * Fetching slices...');
101
+ };
102
+
103
+ workerEventHandlers.fetch = function fetchHandler(ev) {
104
+ if (ev instanceof Error)
105
+ console.error(' ! Failed to fetch slices:', ev);
106
+ else
107
+ options.verbose && console.log(' . Fetched', utils.slicesFetched(ev), 'slices');
108
+ };
109
+
110
+
111
+ workerEventHandlers.beforeResult = function beforeResultHandler() {
112
+ options.verbose >= 2 && console.log(' * Submitting results...');
113
+ };
114
+
115
+ workerEventHandlers.result = function resultHandler() {
116
+ options.verbose >= 2 && console.log(' . Submitted');
117
+ };
118
+
119
+ workerEventHandlers.submitError = function submitErrorHandler(ev) {
120
+ console.log(' ! Failed to submit results:', ev);
121
+ };
122
+
123
+ /* Register the appropriate event handlers on the worker and on each sandbox. The handlers are
124
+ * registered in such a way that mutating the exports object to supply different handlers after
125
+ * registration will work.
126
+ *
127
+ * The handlers registered on each sandbox receive two extra arguments before the usual event
128
+ * arguments; these are the sandbox handle emitted by the Worker<sandbox> event and an object
129
+ * called `sandboxData` which is just arbitrary storage for the eventHandlers' use, eg for memos.
130
+ */
131
+ for (let eventName in workerEventHandlers)
132
+ worker.on(eventName, (...args) => workerEventHandlers[eventName](...args));
133
+
134
+ worker.on('sandbox', function newSandboxHandler(sandbox) {
135
+ const sandboxData = {
136
+ shortId: sandbox.id.toString(10).padStart(3)
137
+ };
138
+ for (let eventName in sandboxEventHandlers)
139
+ sandbox.on(eventName, (...args) => sandboxEventHandlers[eventName](sandbox, sandboxData, ...args));
140
+ });
141
+
142
+ exports.sandboxEventHandlers = sandboxEventHandlers;
143
+ exports. workerEventHandlers = workerEventHandlers;
144
+ };
145
+
146
+ /**
147
+ * Function to replace a worker event handler.
148
+ *
149
+ * @param {string} eventName name of the event to replace
150
+ * @param {function} eventHandler new event handler
151
+ */
152
+ exports.replaceWorkerEvent = function hookWorkerEvents$$replace(eventName, eventHandler)
153
+ {
154
+ if (!workerEventHandlers.hasOwnProperty(eventName))
155
+ throw new Error('unknown worker event: ' + eventName + `(${Object.keys(workerEventHandlers).join(', ')})`);
156
+
157
+ workerEventHandlers[eventName] = eventHandler;
158
+ }
159
+
160
+ /**
161
+ * Function to replace a sandbox event handler.
162
+ *
163
+ * @param {string} eventName name of the event to replace
164
+ * @param {function} eventHandler new event handler
165
+ */
166
+ exports.replaceSandboxEvent = function hookSandboxEvents$$replace(eventName, eventHandler)
167
+ {
168
+ if (!sandboxEventHandlers.hasOwnProperty(eventName))
169
+ throw new Error('unknown sandbox event: ' + eventName + `(${Object.keys(sandboxEventHandlers).join(', ')})`);
170
+
171
+ sandboxEventHandlers[eventName] = eventHandler;
172
+ }
package/lib/pidfile.js CHANGED
@@ -21,7 +21,7 @@ const path = require('path');
21
21
  *
22
22
  * @param {string} filename the location of the pid file
23
23
  */
24
- exports.write = async function pidfile$$write(filename)
24
+ exports.write = function pidfile$$write(filename)
25
25
  {
26
26
  var fd;
27
27
 
@@ -47,7 +47,7 @@ function daemonEval()
47
47
 
48
48
  function callbackTelnet(port, client, registry) {
49
49
  client.unref();
50
- debugging() && console.debug(' ! telnetd - listening on port', port);
50
+ debugging() && console.notice(' ! telnetd - listening on port', port);
51
51
  }
52
52
 
53
53
  /**
@@ -76,8 +76,16 @@ exports.init = function remoteConsole$$init(...commands)
76
76
 
77
77
  console.warn('*** Enabling telnet daemon on port', port, '(security risk) ***');
78
78
 
79
+ if (port !== 0)
80
+ exports.port = port;
81
+ else
82
+ {
83
+ /* telnet-console library does not properly support port 0 so we mostly work-around here */
84
+ exports.port = Math.floor(1023 + (Math.random() * (63 * 1024)));
85
+ }
86
+
79
87
  ci = require('telnet-console').start({
80
- port,
88
+ port: exports.port,
81
89
  callbackTelnet,
82
90
  eval: daemonEval,
83
91
  histfile: edcFilename + '.history',
@@ -1,97 +1,130 @@
1
1
  /**
2
2
  * @file startWorkerLogger.js
3
+ * Start the DCP Worker logging subsystem. Sets console.log (etc) redirection, determine
4
+ * the correct log target (screen, TUI, syslog, windows event log, file) and redirect the
5
+ * output there.
3
6
  * @author Ryan Rossiter, ryan@kingsds.network
4
7
  * @date April 2020
8
+ * @author Wes Garland, wes@distributive.network
5
9
  */
10
+ 'use strict';
6
11
 
7
12
  const process = require('process');
8
13
  const os = require('os');
9
- require('./worker-loggers/common-types');
14
+ const util = require('util');
10
15
 
11
16
  /**
12
17
  * Detects and returns the appropriate logger for the environment
18
+ * @param {object} options - cliArgs from worker
13
19
  * @returns {WorkerLogger}
14
20
  */
15
- function getLogger({ outputMode='detect' }) {
16
- if (outputMode === 'detect') {
17
- if (process.stdout.isTTY && os.platform() !== 'win32' &&
18
- process.env.LANG && process.env.LANG.match(/utf-?8/i)) {
19
- outputMode = 'dashboard';
20
- } else {
21
- outputMode = 'console';
22
- }
21
+ function getLogger(options)
22
+ {
23
+ if (options.outputMode === 'detect')
24
+ {
25
+ options.outputMode = 'console';
26
+ /* have TTY - use dashboard when charset supports line drawing */
27
+ if ((process.env.LANG && process.env.LANG.match(/utf-|latin-|iso-8859-/i)) || os.platform() === 'win32')
28
+ options.outputMode = 'dashboard';
23
29
  }
24
30
 
25
31
  try
26
32
  {
27
- const om = require('path').basename(outputMode);
33
+ const om = require('path').basename(options.outputMode);
28
34
  return require('./worker-loggers/' + om);
29
35
  }
30
36
  catch (error)
31
37
  {
32
- console.error(`032: Failed to load worker logger "${outputMode}":`, error);
33
-
34
38
  if (error.code === 'MODULE_NOT_FOUND')
35
- throw new Error(`Unknown outputMode "${outputMode}"`);
39
+ {
40
+ const errorMessageStart = error.message.replace(/\n.*/g, '');
41
+ error.message = `Unknown outputMode "${options.outputMode} (${errorMessageStart})`;
42
+ }
36
43
  throw error;
37
44
  }
38
45
  }
39
46
 
40
- const workerEvents = {
41
- fetchStart: 'onFetchingSlices',
42
- fetchEnd: 'onFetchedSlices',
43
- fetchError: 'onFetchSlicesFailed',
44
- submit: 'onSubmit',
45
- submitError: 'onSubmitError',
46
- payment: 'onPayment',
47
- }
48
- const supervisorEvents = {
49
- submittingResult: 'onSubmitStart',
50
- }
51
- const sandboxEvents = {
52
- start: 'sandbox$onSliceStart',
53
- sliceProgress: 'sandbox$onSliceProgress',
54
- sliceFinish: 'sandbox$onSliceFinish',
55
- terminated: 'sandbox$onWorkerStop',
56
- }
47
+ /**
48
+ * Start intercepting console.* methods so that log output from the worker goes to the appropriate log
49
+ * target; eg syslog, file, windows event log, etc. Unlike the telnet console log interceptor which is
50
+ * merely a passthrough shim, this is a "dead end" interceptor - we do not pass the log message through
51
+ * to the original console method. This implies, for example, that sending console messages to syslogd
52
+ * quiesces the tty output.
53
+ *
54
+ * @param {object} options - cliArgs from worker
55
+ */
56
+ exports.init = function startWorkerLogger$$init(options)
57
+ {
58
+ const logger = getLogger(options);
57
59
 
58
- Object.assign(exports, {
59
- /**
60
- * This method will attach event listeners from the provided
61
- * worker to a worker logger. The logger to use is
62
- * determined by getLogger based on the environment.
63
- *
64
- * @param {Worker} worker
65
- * @param {object} options
66
- * @param {number} options.verbose
67
- * @param {boolean} options.outputMode - which logger to use (default='detect')
60
+ logger.init(options);
61
+
62
+ /* The logger module's exports are its API. The following functions are supported, in this order
63
+ * of severity:
64
+ * . debug: debug-level message
65
+ * . info: informational message
66
+ * . log: normal, but significant, condition
67
+ * . warn: warning conditions
68
+ * . error: error conditions
69
+ *
70
+ * Additionally, generic functions may be used when one of the above is not defined:
71
+ * . at: write a log message at a specific log level; the level is the first argument
72
+ * . raw: same as at, but arguments are not formatted
73
+ * . any: write a log message without regard to log level
74
+ *
75
+ * All of these functions, with the exception of raw, receive only string arguments.
68
76
  */
69
- startWorkerLogger(worker, options={}) {
70
- const logger = getLogger(options);
71
- logger.init(worker, options);
72
77
 
73
- for (const [ev, handler] of Object.entries(workerEvents))
78
+ for (let level of ['debug', 'error', 'info', 'log', 'warn'])
79
+ {
80
+ if (logger[level])
81
+ console[level] = (...args) => logger[level]( ...format(...args));
82
+ else if (logger.at)
83
+ console[level] = (...args) => logger.at(level, ...format(...args));
84
+ else if (logger.raw)
85
+ console[level] = (...args) => logger.raw(level, ...args);
86
+ else if (logger.any)
87
+ console[level] = (...args) => logger.any(`${level}:`, format(...args));
88
+ else
89
+ {
90
+ require('./remote-console').reintercept();
91
+ throw new Error('logger module missing export for ' + level);
92
+ }
93
+ }
94
+
95
+ require('./remote-console').reintercept();
96
+ }
97
+
98
+ /**
99
+ * Format console.log arguments for use by a non-native logger, eg syslog. All non-string arguments are
100
+ * converted into the best human-readable strings we can muster.
101
+ */
102
+ function format(...argv)
103
+ {
104
+ for (let i in argv)
105
+ {
106
+ try
74
107
  {
75
- if (typeof logger[handler] === 'function')
76
- worker.on(ev, logger[handler].bind(logger));
108
+ if (typeof argv[i] === 'object' && argv[i] instanceof String)
109
+ argv[i] = String(argv[i]);
110
+ if (typeof argv[i] === 'object')
111
+ argv[i] = util.inspect(argv[i], exports.inspectOptions);
112
+ if (typeof argv[i] !== 'string')
113
+ argv[i] = String(argv[i]);
77
114
  }
78
- for (const [ev, handler] of Object.entries(supervisorEvents))
115
+ catch(e)
79
116
  {
80
- if (typeof logger[handler] === 'function')
81
- worker.addSupervisorEventListener(ev, logger[handler].bind(logger));
117
+ if (e instanceof TypeError)
118
+ argv[i] = '[encoding error: ' + e.message + ']';
82
119
  }
83
-
84
- worker.on('sandbox', (sandbox) => {
85
- /**
86
- * logger.onSandboxStart can return a data object that will be provided to
87
- * the other sandbox event handlers
88
- */
89
- const data = logger.onSandboxReady(sandbox) || {};
90
- for (const [ev, handler] of Object.entries(sandboxEvents))
91
- {
92
- if (typeof logger[handler] === 'function')
93
- sandbox.on(ev, logger[handler].bind(logger, sandbox, data));
94
- }
95
- });
96
120
  }
97
- });
121
+
122
+ return argv;
123
+ }
124
+
125
+ /**
126
+ * Options for util.inspect. Loggers which cannot deal with colours should force this false.
127
+ */
128
+ exports.inspectOptions = {
129
+ colors: process.stdout.isTTY && process.stdout.hasColors() || process.env.FORCE_COLOR,
130
+ };
package/lib/utils.js ADDED
@@ -0,0 +1,28 @@
1
+
2
+ /**
3
+ * @file utils.js
4
+ * Shared library code.
5
+ *
6
+ * @author Paul, paul@distributive.network
7
+ * @date August 2023
8
+ */
9
+ 'use strict';
10
+
11
+ /**
12
+ * Figure out #slices fetched from the different forms of the 'fetch' event.
13
+ * @param {*|string|number} task
14
+ * @returns {number}
15
+ */
16
+ function slicesFetched (task)
17
+ {
18
+ if (typeof task === 'number') /* <= June 2023 Worker events: remove ~ Sep 2023 /wg */
19
+ return task;
20
+ if (typeof task === 'string') /* <= June 2023 Worker events: remove ~ Sep 2023 /wg */
21
+ return parseInt(task) || 0;
22
+ let slicesFetched = 0;
23
+ for (const job in task.slices)
24
+ slicesFetched += task.slices[job];
25
+ return slicesFetched;
26
+ }
27
+
28
+ exports.slicesFetched = slicesFetched;