dcp-worker 3.3.12-0 → 3.3.12

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/dcp-worker CHANGED
@@ -23,9 +23,11 @@ const chalk = require('chalk');
23
23
  const telnetd = require('../lib/remote-console');
24
24
 
25
25
  const { slicesFetched, debugging, displayMaxDiagInfo } = require('../lib/utils');
26
+ const { a$sleep } = require('dcp/utils');
26
27
 
27
28
  const configName = process.env.DCP_CONFIG || '../etc/dcp-worker-config';
28
29
  const EXIT_UNHANDLED = 5;
30
+ const systemStateInfo = globalThis.systemStateInfo = {};
29
31
 
30
32
  /* Setup the telnet REPL up early to ensure early-failure log messages are captured */
31
33
  const replHelpers = {
@@ -44,6 +46,26 @@ const replHelpers = {
44
46
  };
45
47
  telnetd.init(replHelpers);
46
48
 
49
+ /**
50
+ * regexps of GPUs we cannot use. Properties match device descriptors. More regexps can be added via
51
+ * dcpConfig.bannedGPUs.
52
+ */
53
+ const bannedGPUs =
54
+ {
55
+ device: /llvmpipe/,
56
+ }
57
+
58
+ /**
59
+ * Output startup banner message. Currently a wrapper for console.log, future plans are to make it
60
+ * possible to suppress these messages, and also to send them multiple places (eg tty and syslog)
61
+ */
62
+ function bannerLog()
63
+ {
64
+ console.log.apply(console, arguments);
65
+ bannerLog.cumulative.push(arguments);
66
+ }
67
+ bannerLog.cumulative = [];
68
+
47
69
  /* Initialize dcp-client with local config defaults and run the main function. DCP_CONFIG_COOKIE becomes dcpConfig.cookie.
48
70
  * And dcpConfig is defined as a side effect of initializing dcp-client.
49
71
  */
@@ -138,13 +160,13 @@ function parseCliArgs()
138
160
  leavePublicGroup: {
139
161
  type: 'boolean',
140
162
  hidden: true,
141
- describe: 'Do not fetch slices from public compute group.',
163
+ describe: 'Do not fetch slices from global compute group.',
142
164
  default: undefined,
143
165
  },
144
166
 
145
167
  publicGroupFallback: {
146
168
  hidden: true,
147
- describe: 'If set, worker will prefer private groups but fall back on the public group if no preferred work is available',
169
+ describe: 'If set, worker will prefer private groups but fall back on the global group if no preferred work is available',
148
170
  type: 'boolean',
149
171
  default: undefined,
150
172
  defaultDescription: undefined,
@@ -298,11 +320,11 @@ async function main()
298
320
  require('../lib/startWorkerLogger').init(cliArgs); /* Start remote logger as early as possible */
299
321
  verifyDefaultConfigIntegrity(); /* Bail before TUI & as early as possible if bad conf */
300
322
 
301
- process.on('SIGINT', handleSigDeath);
323
+ process.on('SIGINT', handleSigDeath);
302
324
  process.on('SIGTERM', handleSigDeath);
303
325
  process.on('SIGQUIT', handleSigDeath);
304
326
  process.on('unhandledRejection', handleUnhandled);
305
- process.on('uncaughtException', handleUnhandled);
327
+ process.on('uncaughtException', handleUnhandled);
306
328
 
307
329
  const getOpts = {};
308
330
  if (cliArgs.defaultPaymentAddressToDCP)
@@ -405,14 +427,33 @@ async function main()
405
427
  if (cliArgs.watchdogInterval)
406
428
  dcpWorkerOptions.watchdogInterval = cliArgs.watchdogInterval;
407
429
 
408
- worker = new DCPWorker(identityKeystore, dcpWorkerOptions);
409
- worker.on('warning', (...payload) => console.warn (...payload));
410
- worker.on('job', job => console.log(` . Job: ${job.name} ${job.address.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
411
- worker.on('stop', () => { console.log('Worker is stopping') });
412
- worker.on('end', () => { logClosing('log', 'Worker has stopped') });
430
+ if (dcpConfig.bannedGPUs)
431
+ {
432
+ for (let prop of dcpConfig.bannedGPUs)
433
+ {
434
+ if (!bannedGPUs[prop])
435
+ bannedGPUs[prop] = dcpConfig.bannedGPUs[prop];
436
+ else
437
+ bannedGPUs[prop] = new RegExp(`(${dcpConfig.bannedGPUs[prop].source})|(${bannedGPUs[prop].source})`);
438
+ }
439
+ }
440
+
441
+ const nascentWorker = new DCPWorker(identityKeystore, dcpWorkerOptions);
442
+ bannerLog(` * Starting DCP Worker ${nascentWorker.workerId}`);
443
+ bannerLog(` . Using evaluator at ${dcpConfig.evaluator.location}`);
444
+ bannerLog(` . Configured for scheduler ${dcpConfig.scheduler.location}`);
445
+ bannerLog(` . Bank is ${dcpConfig.bank.location}`);
446
+ bannerLog(` . Earned funds will be deposited in account ${nascentWorker.paymentAddress}`);
447
+ bannerLog(` . Identity is ${nascentWorker.identityKeystore.address}`);
448
+
449
+ nascentWorker.on('warning', (...payload) => console.warn (...payload));
450
+ nascentWorker.on('stop', () => { console.log('Worker is stopping') });
451
+ nascentWorker.on('end', () => { logClosing('log', 'Worker has stopped') });
452
+
413
453
  // Display clean diagnostic when not debugging and env var
414
454
  // DCP_SUPERVISOR_DEBUG_DISPLAY_MAX_INFO isn't set.
415
- worker.on('error', (error) => {
455
+ nascentWorker.on('error', (error) => {
456
+
416
457
  if (displayMaxDiagInfo())
417
458
  console.error(error);
418
459
  else
@@ -424,29 +465,29 @@ async function main()
424
465
  console.error(`Error: ${error.message}`);
425
466
  }
426
467
  });
427
- require('../lib/default-ui-events').hook(worker, cliArgs);
468
+ require('../lib/default-ui-events').hook(nascentWorker, cliArgs);
428
469
 
429
470
  if (cliArgs.outputMode === 'dashboard')
430
- require('../lib/dashboard-tui').init(worker, cliArgs);
471
+ require('../lib/dashboard-tui').init(nascentWorker, cliArgs, bannerLog.cumulative);
431
472
 
432
473
  /* Let incorrect event-loop references keep us alive when linked with a debug library, but
433
474
  * exit quickly/accurately for production code even when the library isn't perfect.
434
475
  */
435
476
  if (require('dcp/build').config.build !== 'debug')
436
- worker.on('end', processExit);
477
+ nascentWorker.on('end', processExit);
437
478
  else
438
- worker.on('end', () => setTimeout(processExit, getCleanupTimeoutMs()).unref());
479
+ nascentWorker.on('end', () => setTimeout(processExit, getCleanupTimeoutMs()).unref());
439
480
 
440
481
  if (dcpWorkerOptions.publicGroupFallback)
441
482
  {
442
483
  if (dcpWorkerOptions.leavePublicGroup)
443
- console.warn(' ! Public Group fallback has been requested, but the public group is blocked by local configuration');
484
+ console.warn(' ! Global Group fallback has been requested, but the global group is blocked by local configuration');
444
485
  else
445
486
  {
446
- /* Enable public group fallback - this currently works by enabling or disabling the public group
487
+ /* Enable global group fallback - this currently works by enabling or disabling the global group
447
488
  * on the next fetch based on whether or not the most recent fetch was an empty task or not.
448
489
  */
449
- worker.on('fetch', fetchEventHandler);
490
+ nascentWorker.on('fetch', fetchEventHandler);
450
491
 
451
492
  function fetchEventHandler(ev)
452
493
  {
@@ -458,14 +499,8 @@ async function main()
458
499
  }
459
500
  }
460
501
 
461
- let introBanner = '';
462
- introBanner += ` * Starting DCP Worker ${worker.workerId}` + '\n';
463
- introBanner += ` . Configured for scheduler ${dcpConfig.scheduler.location}` + '\n';
464
- introBanner += ` . Bank is ${dcpConfig.bank.location}` + '\n';
465
- introBanner += ` . Earned funds will be deposited in account ${worker.paymentAddress}` + '\n';
466
- introBanner += ` . Identity is ${worker.identityKeystore.address}` + '\n';
467
-
468
- function qty(amount, singular, plural) /* XXX i18n */
502
+ /** @todo i18n */
503
+ function qty(amount, singular, plural)
469
504
  {
470
505
  if (Array.isArray(amount))
471
506
  amount = amount.length;
@@ -479,49 +514,70 @@ async function main()
479
514
  }
480
515
 
481
516
  if (dcpWorkerOptions.jobAddresses?.length > 0)
482
- introBanner += ` * Processing only ${qty(dcpWorkerOptions.jobAddresses, 'job')} ` + dcpWorkerOptions.jobAddresses.join(', ') + '\n';
517
+ bannerLog(` * Processing only ${qty(dcpWorkerOptions.jobAddresses, 'job')} ` + dcpWorkerOptions.jobAddresses.join(', '));
483
518
  if (dcpWorkerOptions.computeGroups && Object.keys(dcpWorkerOptions.computeGroups).length > 0)
484
- introBanner += ` . Joining compute ${qty(dcpWorkerOptions.computeGroups, 'group')} ` + dcpWorkerOptions.computeGroups.map(el => el.joinKey).join(', ') + '\n';
519
+ bannerLog(` . Joining compute ${qty(dcpWorkerOptions.computeGroups, 'group')} ` + dcpWorkerOptions.computeGroups.map(el => el.joinKey).join(', '));
485
520
  if (dcpWorkerOptions.publicGroupFallback)
486
- introBanner += ' . Falling back on public group when preferred groups have no work' + '\n';
521
+ bannerLog(' . Falling back on global group when preferred groups have no work');
487
522
  if (dcpWorkerOptions.leavePublicGroup)
488
- introBanner += ' . Leaving the public compute group' + '\n';
523
+ bannerLog(' . Leaving the global compute group');
489
524
  if (dcpWorkerOptions.cores)
490
- introBanner += ` . Configured Cores: ${dcpWorkerOptions.cores.cpu},${dcpWorkerOptions.cores.gpu}\n`
525
+ bannerLog(` . Configured Cores: ${dcpWorkerOptions.cores.cpu},${dcpWorkerOptions.cores.gpu}`);
491
526
  if (typeof dcpWorkerOptions.maxSandboxes !== 'undefined')
492
- introBanner += ` . Maximum Sandboxes: ${dcpWorkerOptions.maxSandboxes}\n`
527
+ bannerLog(` . Maximum Sandboxes: ${dcpWorkerOptions.maxSandboxes}`);
493
528
  if (cliArgs.verbose)
494
- introBanner += ` + Verbosity level: ${cliArgs.verbose}` + '\n';
529
+ bannerLog(` + Verbosity level: ${cliArgs.verbose}`);
495
530
  if (telnetd.hasOwnProperty('port'))
496
- introBanner += ` ! telnetd listening on port ${telnetd.port}\n`;
531
+ bannerLog(` ! telnetd listening on port ${telnetd.port}`);
497
532
 
498
533
  const { worktimes } = require('dcp-client/libexec/sandbox/worktimes');
499
534
  if (Object.keys(worktimes).length > 0)
500
535
  {
501
- introBanner += ' . Worktimes Available:\n';
536
+ bannerLog(' . Worktimes Available:');
502
537
  for (const wt of worktimes)
503
- introBanner += ` -\t${wt.name}@${wt.versions.join(';')}\n`;
538
+ bannerLog(` -\t${wt.name}@${wt.versions.join(';')}`);
539
+ }
540
+
541
+ let webgpuInfo;
542
+ console.throb('log', ' ! Waiting for dcp-evaluator to start...');
543
+ for (let i=0; !webgpuInfo; i++)
544
+ {
545
+ webgpuInfo = await require('../lib/webgpu-info').checkWebGPU();
546
+ if (webgpuInfo)
547
+ break;
548
+ console.throb();
549
+ await a$sleep(Math.max(i + 1, 10) / 4);
550
+ console.throb();
504
551
  }
505
552
 
506
- const webgpuInfo = await require('../lib/webgpu-info').checkWebGPU();
507
553
  if (!webgpuInfo)
508
- introBanner += ' . WebGPU detection failed\n';
554
+ bannerLog(' . WebGPU detection failed');
509
555
  else if (!webgpuInfo.enabled)
510
- introBanner += ' . WebGPU not enabled\n';
556
+ {
557
+ bannerLog(' . WebGPU not enabled');
558
+ systemStateInfo.gpu = false;
559
+ }
511
560
  else
512
561
  {
513
- introBanner += ' . WebGPU available. GPU info:\n';
562
+ bannerLog(' . WebGPU available. GPU info:');
514
563
  for (let descriptor in webgpuInfo.info)
515
- introBanner += ` -\t${descriptor}: ${webgpuInfo.info[descriptor]}\n`;
516
- dcpConfig.evaluator.gpu = webgpuInfo.info.device;
564
+ bannerLog(` -\t${descriptor}: ${webgpuInfo.info[descriptor]}`);
565
+ systemStateInfo.gpu = Object.assign({}, webgpuInfo.info);
566
+ systemStateInfo.gpu.device
567
+ for (let descriptor in bannedGPUs)
568
+ {
569
+ if (bannedGPUs[descriptor].test(webgpuInfo.info[descriptor]))
570
+ {
571
+ console.error(' * This GPU is not supported; disabling');
572
+ dcpWorkerOptions.cores = { cpu: dcpWorkerOptions.cores.cpu, gpu: 0 };
573
+ systemStateInfo.gpu.disabled = true;
574
+ break;
575
+ }
576
+ }
517
577
  }
518
578
 
519
- introBanner += ' . Supervisor version: ' + worker.supervisorVersion + '\n';
520
- introBanner += ' . Output mode: ' + cliArgs.outputMode + '\n';
521
- introBanner += ' * Ready' + '\n';
522
-
523
- console.log(introBanner);
524
- require('../lib/check-scheduler-version').check();
579
+ bannerLog(' . Supervisor version: ' + nascentWorker.supervisorVersion);
580
+ bannerLog(' . Output mode: ' + cliArgs.outputMode);
525
581
 
526
582
  if (parseFloat(cliArgs.reportInterval))
527
583
  {
@@ -531,8 +587,15 @@ async function main()
531
587
  console.warn('Ignoring --reportInterval in dashboard output mode');
532
588
  }
533
589
 
534
- /* Start the worker. Normal process exit happens by virtue of the worker<end> event */
535
- await worker.start();
590
+ /* Start the worker. Normal process exit happens by virtue of the worker<end> event. Move forward one
591
+ * tick in case processExit was called during initialization.
592
+ */
593
+ setImmediate(async function workerStart() {
594
+ bannerLog(' * Ready.\n');
595
+ require('../lib/check-scheduler-version').check();
596
+ worker = nascentWorker;
597
+ await worker.start();
598
+ });
536
599
  }
537
600
 
538
601
  /**
@@ -747,21 +810,25 @@ function handleSigDeath(signalName, signal)
747
810
  }
748
811
 
749
812
  if (!worker)
813
+ {
750
814
  console.warn(`trapped ${signalName}, signal ${signal}`);
815
+ die();
816
+ }
751
817
  else
752
818
  {
753
819
  const immediate = signalName === 'SIGQUIT' || handleSigDeath.count > 1;
754
820
  console.warn(`trapped ${signalName}, signal ${signal} -- stopping worker`,
755
821
  immediate ? 'immediately' : `after ${handleSigDeath.count} slices have finished`);
756
822
  worker.stop(immediate);
823
+ setTimeout(die, getCleanupTimeoutMs()).unref();
757
824
  }
825
+ process.emit('dcpBeforeExit');
758
826
 
759
827
  function die()
760
828
  {
761
829
  processExit(signal - 128);
762
830
  }
763
831
 
764
- setTimeout(die, getCleanupTimeoutMs()).unref();
765
832
  if (handleSigDeath.count === 3)
766
833
  die();
767
834
  }
@@ -818,7 +885,7 @@ function verifyDefaultConfigIntegrity()
818
885
  if (!originalMd5sum.startsWith(actualMd5sum))
819
886
  {
820
887
  console.warn(chalk.yellow(` ! Detected modified ${workerConfPath};`));
821
- console.warn(' . DCP Worker configuration changes should not be made by updating the default');
888
+ console.warn(' ! DCP Worker configuration changes should not be made by updating the default');
822
889
  console.warn(' config, as that file will be overwritten on the next npm update. Instead,');
823
890
  console.warn(' make changes via one of the following locations:');
824
891
  console.warn(' - ~/.dcp/dcp-worker/dcp-config.js');
@@ -40,19 +40,22 @@ class Log extends Box
40
40
 
41
41
  log(...args)
42
42
  {
43
- const str = args.reduce(
44
- (s, arg) => (s += `${typeof arg === 'string'? arg : JSON.stringify(arg, null, 2)} `),
45
- '');
46
-
47
- this.logLines.push(str);
43
+ args = args.map(arg =>`${typeof arg === 'string'? arg : JSON.stringify(arg, null, 2)}`);
44
+ this.logLines.push(args.join(' '));
48
45
 
49
46
  if (this.logLines.length > this.options.bufferLength)
50
47
  this.logLines.shift();
51
48
 
52
- this.setContent(this.logLines.join('\n'));
49
+ this.lastLogContent = this.logLines.join('\n');
50
+ this.setContent(this.lastLogContent);
53
51
  if (!this.paused)
54
52
  this.setScrollPerc(100);
55
53
  }
54
+
55
+ advanceThrob(char)
56
+ {
57
+ this.setContent(this.lastLogContent + char);
58
+ }
56
59
  }
57
60
 
58
61
  Object.assign(exports, {
@@ -18,6 +18,7 @@ const components = require('./blessed-components');
18
18
  const utils = require('../lib/utils');
19
19
 
20
20
  const { replaceWorkerEventHandler, replaceSandboxEventHandler, newSandboxCallbacks } = require('./default-ui-events');
21
+ const systemStateInfo = globalThis.systemStateInfo;
21
22
 
22
23
  const SLICE_FETCH_STATUS = {
23
24
  IDLE: chalk.yellow('Idle'),
@@ -36,7 +37,7 @@ const screenConf = {
36
37
  * @param {Worker} worker Reference to the DCP Worker
37
38
  * @param {object} options Options which may affect behaviour. Not currently used.
38
39
  */
39
- exports.init = function dashboard$$init(worker, options)
40
+ exports.init = function dashboard$$init(worker, options, bannerLogCumulative)
40
41
  {
41
42
  var sliceFetchStatus = SLICE_FETCH_STATUS.IDLE;
42
43
  var totalDCCs = 0;
@@ -51,12 +52,12 @@ exports.init = function dashboard$$init(worker, options)
51
52
  screen.destroy();
52
53
  });
53
54
 
54
- const grid = new contrib.grid({ rows: 3, cols: 5, screen }); // eslint-disable-line new-cap
55
- const workerInfoPane = grid.set(2, 0, 1, 5, components.log, {
55
+ const grid = new contrib.grid({ rows: 3, cols: 6, screen }); // eslint-disable-line new-cap
56
+ const workerInfoPane = grid.set(2, 0, 1, 6, components.log, {
56
57
  label: 'Worker Status',
57
58
  scrollbar: { bg: 'blue' },
58
59
  });
59
- const logPane = grid.set(0, 2, 2, 3, components.log, {
60
+ const logPane = grid.set(0, 2, 2, 4, components.log, {
60
61
  label: 'Worker Log',
61
62
  scrollbar: { bg: 'blue' },
62
63
  });
@@ -115,9 +116,11 @@ exports.init = function dashboard$$init(worker, options)
115
116
  };
116
117
 
117
118
  delete exports.init; /* singleton */
118
-
119
+ console.log(' . Starting dashboard and redirecting logs');
119
120
  if (!usingDebugger)
120
121
  exports.logPane = logPane; /* now dashboard log can find the pane */
122
+ for (let args of bannerLogCumulative) /* re-draw previously-emited log lines as screen has cleared */
123
+ logPane.log(...args);
121
124
  setInterval(() => screen.render(), 2000).unref(); /* ensure we didn't forget to render an important update */
122
125
  updateWorkerInfo();
123
126
 
@@ -130,10 +133,25 @@ exports.init = function dashboard$$init(worker, options)
130
133
  setInterval(updateWorkerInfo, 1000).unref();
131
134
  function updateWorkerInfo(fetchInfo)
132
135
  {
136
+ var gpuInfo = '';
133
137
  const workerOptions = worker.workerOptions;
134
138
  if (fetchInfo)
135
139
  lastTask = fetchInfo;
136
140
 
141
+ if (typeof systemStateInfo.gpu === 'undefined')
142
+ gpuInfo = '';
143
+ else if (systemStateInfo.gpu === false)
144
+ gpuInfo = 'none';
145
+ else if (typeof systemStateInfo.gpu === 'object')
146
+ {
147
+ if (systemStateInfo.gpu.disabled)
148
+ gpuInfo = chalk.red('disabled') + chalk.grey(` (${systemStateInfo.gpu.device})`);
149
+ else
150
+ gpuInfo = chalk.cyan(systemStateInfo.gpu.device);
151
+ }
152
+ else
153
+ gpuInfo = chalk.red(`error detecting`);
154
+
137
155
  workerInfoPane.setLabel(`Worker Status [${sliceFetchStatus}]`);
138
156
  workerInfoPane.setContent([
139
157
  chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))} ⊇`),
@@ -142,7 +160,7 @@ exports.init = function dashboard$$init(worker, options)
142
160
  ` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
143
161
  ` Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
144
162
  ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
145
- ` ${dcpConfig.evaluator.gpu ? `GPU Detected: ${dcpConfig.evaluator.gpu}` : 'GPU Not Detected'}`,
163
+ ` GPU: ${gpuInfo}`,
146
164
  ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
147
165
  ` Compute Groups: ${Object.keys(workerOptions.computeGroups).length + (workerOptions.leavePublicGroup ? 0 : 1)}`,
148
166
  `Global Compute Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
@@ -50,7 +50,7 @@ function getLogger(options)
50
50
  * merely a passthrough shim, this is a "dead end" interceptor - we do not pass the log message through
51
51
  * to the original console method. This implies, for example, that sending console messages to syslogd
52
52
  * quiesces the tty output.
53
- *
53
+ *
54
54
  * @param {object} options - cliArgs from worker
55
55
  */
56
56
  exports.init = function startWorkerLogger$$init(options)
@@ -92,8 +92,16 @@ exports.init = function startWorkerLogger$$init(options)
92
92
  }
93
93
  }
94
94
 
95
+ if (logger.throb)
96
+ console.throb = logger.throb;
97
+ else
98
+ console.throb = function throwFallback(facility, ...args) {
99
+ if (facility && facility !== 'throb')
100
+ console[facility](...args);
101
+ };
102
+
95
103
  require('./remote-console').reintercept();
96
- }
104
+ }
97
105
 
98
106
  /**
99
107
  * Format console.log arguments for use by a non-native logger, eg syslog. All non-string arguments are
@@ -13,6 +13,9 @@ const evaluatorId = 'webgpuCheck';
13
13
 
14
14
  async function eval$$webgpu()
15
15
  {
16
+ if (typeof initWebGPU === 'function')
17
+ await initWebGPU();
18
+
16
19
  if (!(typeof globalThis.navigator?.gpu === 'object'))
17
20
  return { enabled: false };
18
21
 
@@ -67,15 +70,16 @@ function checkEvaluatorWebGPU(evaluatorConfig)
67
70
  noResponse.intr();
68
71
  });
69
72
 
70
- noResponse = a$sleep(1);
71
- noResponse.then(() => { resolve(); });
72
- process.on('dcpExit', () => noResponse.intr());
73
+ noResponse = a$sleep(2);
74
+ noResponse.then(resolve); /* no answer */
75
+ noResponse.finally(() => process.off('dcpBeforeExit', noResponse.intr));
76
+ process.on('dcpBeforeExit', noResponse.intr);
73
77
 
74
78
  evaluatorHandle.onmessage = function onmessage(event)
75
79
  {
76
80
  const reply = kvin.unmarshal(event.data).value;
77
81
  if (reply.request === `evalResult::${evaluatorId}`)
78
- resolve(reply.data);
82
+ resolve(reply.data /* { enabled: false|true } */);
79
83
  }
80
84
 
81
85
  const message = {
@@ -16,6 +16,9 @@ const process = require('process');
16
16
  exports.init = function console$$init(options)
17
17
  {
18
18
  const myConsole = new (require('console').Console)(process);
19
+ var lastWasThrobber = false;
20
+ var i = 0;
21
+ var throbArgsCache = false;
19
22
 
20
23
  delete exports.init; // singleton
21
24
  if (process.env.RAW_CONSOLE)
@@ -24,12 +27,47 @@ exports.init = function console$$init(options)
24
27
  exports.raw = function console$$raw(level, ...args) {
25
28
  myConsole[level](...args);
26
29
  };
30
+ return;
27
31
  }
28
- else
29
- {
30
- /* Log a single string to the console; conceptually very similar to other loggers */
31
- exports.at = function console$$at(level, ...args) {
32
- myConsole[level](args.join(' '));
33
- };
32
+
33
+ /* Log a single string to the console; conceptually very similar to other loggers */
34
+ exports.at = function console$$at(level, ...args) {
35
+ if (lastWasThrobber)
36
+ {
37
+ args.unshift(' \n');
38
+ lastWasThrobber = false;
39
+ }
40
+ myConsole[level](args.join(' '));
41
+ };
42
+
43
+ const throbChars = '/-\\|';
44
+ /**
45
+ * throb API: calls with arguments set facility and message. First call without argument emits the
46
+ * message. All calls without arguments advance the throbber.
47
+ */
48
+ exports.throb = function throb(throbFacility, ...args) {
49
+ if (throbFacility)
50
+ {
51
+ throbArgsCache = { throbFacility, args };
52
+ return;
53
+ }
54
+
55
+ const stream = throbFacility === 'error' || throbFacility === 'warn' ? process.stderr : process.stdout;
56
+
57
+ if (throbArgsCache)
58
+ {
59
+ if (stream.isTTY)
60
+ stream.write(throbArgsCache.args.join(' '));
61
+ else
62
+ console[throbArgsCache.throbFacility](...throbArgsCache.args);
63
+ throbArgsCache = false;
64
+ }
65
+
66
+ if (stream.isTTY)
67
+ {
68
+ i = (i + 1) % throbChars.length;
69
+ stream.write(throbChars[i] + '\u0008');
70
+ lastWasThrobber = true;
71
+ }
34
72
  }
35
73
  }
@@ -2,7 +2,7 @@
2
2
  * @file worker-loggers/dashboard.js
3
3
  * @author Ryan Rossiter, ryan@kingsds.network
4
4
  * @date April 2020
5
- *
5
+ *
6
6
  * This worker logger uses the blessed library to create
7
7
  * a monitoring dashboard for the worker.
8
8
  */
@@ -17,11 +17,13 @@ const chalk = require('chalk');
17
17
  */
18
18
  exports.init = function dashboardLogger$$init(options)
19
19
  {
20
+ const dashboardTui = require('../dashboard-tui');
21
+ const inspect = Symbol.for('nodejs.util.inspect.custom');
22
+ var throbPos = 0;
23
+ var throbArgsCache = false;
24
+
20
25
  function logWrapperFactory(logLevel)
21
26
  {
22
- const inspect = Symbol.for('nodejs.util.inspect.custom');
23
- const dashboardTui = require('../dashboard-tui');
24
-
25
27
  return function wrappedLogFun() {
26
28
  if (!dashboardTui.logPane) /* no logPane => TUI not ready - fallback to console */
27
29
  {
@@ -33,7 +35,7 @@ exports.init = function dashboardLogger$$init(options)
33
35
  logAt(logLevel, ...arguments);
34
36
  return;
35
37
  }
36
-
38
+
37
39
  const argv = Array.from(arguments);
38
40
  for (let i in argv)
39
41
  {
@@ -48,5 +50,26 @@ exports.init = function dashboardLogger$$init(options)
48
50
 
49
51
  for (let level of ['log', 'warn', 'debug', 'info', 'error'])
50
52
  exports[level] = logWrapperFactory(level);
51
- }
52
53
 
54
+ const throbChars = '/-\\|';
55
+ /**
56
+ * throb API: calls with arguments set facility and message. First call without argument emits the
57
+ * message. All calls without arguments advance the throbber.
58
+ */
59
+ exports.throb = function throb(throbFacility, ...args) {
60
+ if (throbFacility)
61
+ {
62
+ throbArgsCache = { throbFacility, args };
63
+ return;
64
+ }
65
+
66
+ if (throbArgsCache)
67
+ {
68
+ exports[throbArgsCache.throbFacility](...throbArgsCache.args);
69
+ throbArgsCache = false;
70
+ }
71
+
72
+ throbPos = (throbPos + 1) % throbChars.length;
73
+ dashboardTui.logPane.advanceThrob(throbChars[throbPos]);
74
+ }
75
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dcp-worker",
3
- "version": "3.3.12-0",
3
+ "version": "3.3.12",
4
4
  "description": "Node.js Worker for Distributive Compute Platform",
5
5
  "main": "bin/dcp-worker",
6
6
  "keywords": [
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+ssh://git@gitlab.com/Distributed-Compute-Protocol/dcp-worker.git"
15
+ "url": "git@github.com:Distributed-Compute-Labs/dcp-worker.git"
16
16
  },
17
17
  "license": "MIT",
18
18
  "author": "Distributive Corp.",
@@ -37,18 +37,18 @@
37
37
  "prepublishOnly": "npm-hooks/prepublish"
38
38
  },
39
39
  "dependencies": {
40
- "blessed": "^0.1.81",
40
+ "blessed": "0.1.81",
41
41
  "blessed-contrib": "4.11.0",
42
- "chalk": "^4.1.0",
43
- "dcp-client": "4.4.11-0",
44
- "kvin": "^1.2.7",
45
- "posix-getopt": "^1.2.1",
46
- "semver": "^7.3.8",
42
+ "chalk": "4.1.2",
43
+ "dcp-client": "4.4.11",
44
+ "kvin": "1.2.14",
45
+ "posix-getopt": "1.2.1",
46
+ "semver": "7.6.3",
47
47
  "syslog-client": "1.1.1"
48
48
  },
49
49
  "optionalDependencies": {
50
- "dbus-next": "^0.10.2",
51
- "telnet-console": "^1.0.5"
50
+ "dbus-next": "0.10.2",
51
+ "telnet-console": "1.0.5"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@distributive/eslint-config": "2.1.4",