dcp-client 4.4.8 → 4.4.9-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/dcp-client-bundle.js +1 -1
- package/dist/dcp-client-bundle.js.map +1 -1
- package/examples/vanilla-web/simple-job.html +61 -0
- package/examples/vanilla-web/simple-worker.html +84 -57
- package/index.js +7 -0
- package/lib/standaloneWorker.js +13 -3
- package/libexec/sandbox/bravojs-env.js +12 -2
- package/libexec/sandbox/event-loop-virtualization.js +5 -9
- package/libexec/sandbox/native-event-loop.js +4 -7
- package/libexec/sandbox/worktimes.js +1 -1
- package/package.json +2 -1
- package/test-helpers/attempt-to-fetch.js +29 -0
- package/test-helpers/autoupdate-check.js +16 -0
- package/test-helpers/config.js +32 -0
- package/test-helpers/etc/dcp-config-2.js +11 -0
- package/test-helpers/etc/dcp-config.js +18 -0
- package/test-helpers/globalPolyfillHelper.js +85 -0
- package/test-helpers/setup-testenv.js +37 -0
- package/examples/bravojs/minimal.html +0 -35
- package/examples/bravojs/simple-worker.html +0 -53
- package/examples/vanilla-web/client-modals.html +0 -174
- package/examples/vanilla-web/events.css +0 -29
- package/examples/vanilla-web/events.html +0 -94
- package/examples/vanilla-web/minimal.html +0 -42
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<!--
|
|
4
|
+
-- @file simple-job.html - Sample web page showing how to deploy a simple DCP job.
|
|
5
|
+
--
|
|
6
|
+
-- @author Wes Garland <wes@distributive.network>
|
|
7
|
+
-- @author Kevin Yu <kevin@distributive.network>
|
|
8
|
+
-- @date Aug 2019, April 2020, July 2024
|
|
9
|
+
--
|
|
10
|
+
-->
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="utf-8"/>
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
14
|
+
|
|
15
|
+
<!-- Load dcp-client into `window.dcp`. -->
|
|
16
|
+
<script src="https://scheduler.distributed.computer/dcp-client/dcp-client.js"></script>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
function addJobEventListeners(job)
|
|
22
|
+
{
|
|
23
|
+
// Log the job's assigned id.
|
|
24
|
+
job.on('accepted', ({ id }) => console.log(`Job accepted with id ${id}`));
|
|
25
|
+
|
|
26
|
+
// Log returned slice results
|
|
27
|
+
job.on('result', (result) => console.log('Received result:', result));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function start()
|
|
31
|
+
{
|
|
32
|
+
const { compute } = window.dcp;
|
|
33
|
+
|
|
34
|
+
// Creates a Job for the distributed computer.
|
|
35
|
+
// https://docs.dcp.dev/specs/compute-api.html#compute-for
|
|
36
|
+
const job = compute.for(
|
|
37
|
+
[1, 2, 3, 4, 5],
|
|
38
|
+
(datum) => {
|
|
39
|
+
// If a progress event is not emitted within 30 seconds,
|
|
40
|
+
// the scheduler will throw an ENOPROGRESS error.
|
|
41
|
+
progress();
|
|
42
|
+
return datum * 2;
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Listen for job emitted events
|
|
47
|
+
addJobEventListeners(job);
|
|
48
|
+
|
|
49
|
+
// Deploy job
|
|
50
|
+
const results = await job.exec(compute.marketRate);
|
|
51
|
+
console.log('Job completed, here are the results: ', Array.from(results));
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
</head>
|
|
55
|
+
<body onload="start()">
|
|
56
|
+
<p
|
|
57
|
+
style="text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24px;">
|
|
58
|
+
This is a simple vanilla web job deployment example. <br />Look in your browser's console for output.
|
|
59
|
+
</p>
|
|
60
|
+
</body>
|
|
61
|
+
</html>
|
|
@@ -1,81 +1,108 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<!--
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
-- @file simple-worker.html - Sample web page showing how to implement a trivial DCP worker.
|
|
5
|
+
--
|
|
6
|
+
-- @author Wes Garland <wes@distributive.network>
|
|
7
|
+
-- @author Bryan Hoang <bryan@distributive.network>
|
|
8
|
+
-- @author Kevin Yu <kevin@distributive.network>
|
|
9
|
+
-- @date Aug. 2019, Sept. 2022, July 2024
|
|
10
|
+
-->
|
|
11
11
|
<head>
|
|
12
12
|
<meta charset="utf-8" />
|
|
13
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
14
14
|
|
|
15
|
+
<!-- Load dcp-client into `window.dcp`. -->
|
|
15
16
|
<script src="https://scheduler.distributed.computer/dcp-client/dcp-client.js"></script>
|
|
16
|
-
<script type="module">
|
|
17
|
-
const {
|
|
18
|
-
wallet,
|
|
19
|
-
worker: { Worker: DCPWorker },
|
|
20
|
-
} = window.dcp;
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
<script>
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
function addWorkerEventListeners(worker)
|
|
22
|
+
{
|
|
23
|
+
// The start event fires after the worker is ready to fetch tasks, but
|
|
24
|
+
// before the first task has been fetched.
|
|
25
|
+
worker.on('start', () => {
|
|
26
|
+
console.log('Worker ready to fetch tasks');
|
|
27
|
+
});
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
// The fetch event is fired when the worker has fetched a task from the
|
|
30
|
+
// task distributor.
|
|
31
|
+
worker.on('fetch', (task) => {
|
|
32
|
+
if (task.slices)
|
|
33
|
+
console.log(`Worker has fetched ${Object.keys(task.slices).length} slices`);
|
|
34
|
+
});
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
// The sandbox event is emitted when a new sandbox is created. The event
|
|
37
|
+
// handler receives as its sole argument an EventEmitter which is used
|
|
38
|
+
// to emit sandbox events
|
|
39
|
+
worker.on('sandbox', (sandbox) => {
|
|
40
|
+
// The progress event is fired to indicate progress throughout a job
|
|
41
|
+
// this is triggered by the progress() call in the work function,
|
|
42
|
+
// however, quickly-repeating calls to progress() may be composited
|
|
43
|
+
// into a single event.
|
|
44
|
+
sandbox.on('progress', (event) => {
|
|
45
|
+
console.log('Sandbox progress', event);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
console.log('
|
|
49
|
+
// After a result is sent to the result-submitter for consideration
|
|
50
|
+
worker.on('payment', (event) => {
|
|
51
|
+
console.log('Work payment', event);
|
|
46
52
|
});
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
`Name: "${name}",`,
|
|
53
|
-
`Description: "${description}", and`,
|
|
54
|
-
`Link: "${link}"`,
|
|
55
|
-
);
|
|
54
|
+
// Result event is fired immediately after the worker sends a result to
|
|
55
|
+
// the the result data sink
|
|
56
|
+
worker.on('result', (event) => {
|
|
57
|
+
console.log('Worker has sent a result back to the scheduler');
|
|
56
58
|
});
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
// Worker has stopped working and no new results will be sent to the
|
|
61
|
+
// result submitter or the result data sink and no more slices will be
|
|
62
|
+
// returned to the scheduler
|
|
63
|
+
worker.on('end', () => {
|
|
64
|
+
console.log('Worker has stopped working');
|
|
60
65
|
});
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
// Log errors
|
|
68
|
+
worker.on('error', console.error);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function start()
|
|
72
|
+
{
|
|
73
|
+
const {
|
|
74
|
+
wallet,
|
|
75
|
+
worker: { Worker: DCPWorker },
|
|
76
|
+
} = window.dcp;
|
|
77
|
+
|
|
78
|
+
// Bank account funds will deposit into
|
|
79
|
+
const paymentAddress = (await wallet.get()).address;
|
|
80
|
+
|
|
81
|
+
// Retrieve auth keystore object
|
|
82
|
+
const identity = await wallet.getId();
|
|
83
|
+
|
|
84
|
+
// Instantiate DCP worker
|
|
85
|
+
const worker = new DCPWorker(
|
|
86
|
+
identity,
|
|
87
|
+
{
|
|
88
|
+
cores: { cpu: 1 },
|
|
89
|
+
paymentAddress,
|
|
90
|
+
}
|
|
91
|
+
);
|
|
64
92
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.log(`You earned ${payment} DCC!`);
|
|
68
|
-
} else {
|
|
69
|
-
console.log('the result you computed was not accepted.');
|
|
70
|
-
}
|
|
71
|
-
});
|
|
93
|
+
// Listen for work emitted events
|
|
94
|
+
addWorkerEventListeners(worker);
|
|
72
95
|
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
// Start the worker
|
|
97
|
+
await worker.start();
|
|
98
|
+
}
|
|
75
99
|
</script>
|
|
76
100
|
</head>
|
|
77
|
-
<body>
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
<body onload="start()">
|
|
102
|
+
<p
|
|
103
|
+
style="text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24px;">
|
|
104
|
+
This is a simple vanilla web DCP Worker example. <br />Look in your browser's
|
|
105
|
+
console for output.
|
|
106
|
+
</p>
|
|
80
107
|
</body>
|
|
81
108
|
</html>
|
package/index.js
CHANGED
|
@@ -908,6 +908,9 @@ function handleInitArgs(initArgv)
|
|
|
908
908
|
* - parseArgv; false => not parse cli for scheduler/wallet
|
|
909
909
|
* - bundleLocation (URL or string)
|
|
910
910
|
* - reportErrors; false => throw, else=>console.log, exit(1)
|
|
911
|
+
* - configName: filename to load as part of default dcpConfig
|
|
912
|
+
* - dcpConfig: object to include as part of default dcpConfig
|
|
913
|
+
* - enableSourceMaps: boolean to activate legible error stack traces
|
|
911
914
|
*/
|
|
912
915
|
/**
|
|
913
916
|
* Form 4
|
|
@@ -922,6 +925,7 @@ function handleInitArgs(initArgv)
|
|
|
922
925
|
* - reportErrors; false => throw, else=>console.log, exit(1)
|
|
923
926
|
* - configName: filename to load as part of default dcpConfig
|
|
924
927
|
* - dcpConfig: object to include as part of default dcpConfig
|
|
928
|
+
* - enableSourceMaps: boolean to activate legible error stack traces
|
|
925
929
|
*/
|
|
926
930
|
exports.init = async function dcpClient$$init() {
|
|
927
931
|
var { initConfig, options } = handleInitArgs(arguments);
|
|
@@ -950,6 +954,9 @@ exports.init = async function dcpClient$$init() {
|
|
|
950
954
|
}
|
|
951
955
|
}
|
|
952
956
|
|
|
957
|
+
if (process.env.DCP_CLIENT_ENABLE_SOURCEMAPS || options.enableSourceMaps)
|
|
958
|
+
require('source-map-support').install();
|
|
959
|
+
|
|
953
960
|
return initTail(configFrags, options, finalBundleCode, finalBundleURL);
|
|
954
961
|
}
|
|
955
962
|
|
package/lib/standaloneWorker.js
CHANGED
|
@@ -100,10 +100,20 @@ function StandaloneWorker(options = {}) {
|
|
|
100
100
|
socket.setNoDelay(dcpConfig.worker ? dcpConfig.worker.nagle : true);
|
|
101
101
|
socket.connect(port, hostname);
|
|
102
102
|
socket.on('connect', beginSession.bind(this));
|
|
103
|
-
|
|
103
|
+
|
|
104
|
+
let alreadySignaled = false;
|
|
105
|
+
const sandboxDeath = () => {
|
|
104
106
|
connected = false;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
if (!alreadySignaled) {
|
|
108
|
+
ee.emit('end');
|
|
109
|
+
alreadySignaled = true;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
// common culprits include ECONNRESET, ECONNREFUSED, ECONNABORTED, ETIMEDOUT
|
|
113
|
+
socket.on('error', sandboxDeath);
|
|
114
|
+
// when the evaluator half closes the connection, the sandbox can't be useful anymore
|
|
115
|
+
socket.on('end', sandboxDeath);
|
|
116
|
+
|
|
107
117
|
socket.on('error', function saWorker$$socket$errorHandler(e) {
|
|
108
118
|
connecting = false;
|
|
109
119
|
if (!dcpConfig.standaloneWorker.quiet)
|
|
@@ -173,7 +173,17 @@ def prepPyodide(args):
|
|
|
173
173
|
image = bytes(image)
|
|
174
174
|
imageFile = io.BytesIO(image)
|
|
175
175
|
tar = tarfile.open(mode='r', fileobj=imageFile)
|
|
176
|
-
|
|
176
|
+
|
|
177
|
+
# Don't overwrite directories which corrupts Pyodide's in memory filesystem
|
|
178
|
+
def safe_extract(tar, path="/"):
|
|
179
|
+
for member in tar.getmembers():
|
|
180
|
+
if member.isdir():
|
|
181
|
+
dir_path = os.path.join(path, member.name)
|
|
182
|
+
if not os.path.exists(dir_path):
|
|
183
|
+
os.makedirs(dir_path)
|
|
184
|
+
else:
|
|
185
|
+
tar.extract(member, path)
|
|
186
|
+
safe_extract(tar)
|
|
177
187
|
|
|
178
188
|
for item, value in args['environmentVariables'].items():
|
|
179
189
|
os.environ[item] = value
|
|
@@ -236,7 +246,7 @@ prepPyodide`);
|
|
|
236
246
|
const sliceHandlerResult = await pythonSliceHandler(pyodide.toPy(datum));
|
|
237
247
|
|
|
238
248
|
// if it is a PyProxy, convert its value to JavaScript
|
|
239
|
-
if (sliceHandlerResult
|
|
249
|
+
if (sliceHandlerResult?.toJs)
|
|
240
250
|
return sliceHandlerResult.toJs();
|
|
241
251
|
|
|
242
252
|
return sliceHandlerResult;
|
|
@@ -176,7 +176,7 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, function eve
|
|
|
176
176
|
const event = events.shift();
|
|
177
177
|
if (event.eventType === 'timer')
|
|
178
178
|
{
|
|
179
|
-
serviceEvents.executingTimeout = realSetTimeout(event.fn, 0
|
|
179
|
+
serviceEvents.executingTimeout = realSetTimeout(event.fn, 0);
|
|
180
180
|
if (event.recur)
|
|
181
181
|
{
|
|
182
182
|
event.when = Date.now() + event.recur;
|
|
@@ -224,14 +224,10 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, function eve
|
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
args = args.slice(2); // slice the first two elements (callback & timeout), leaving an array of user arguments
|
|
232
|
-
let fn = callback;
|
|
233
|
-
callback = () => fn.apply(fn, args); // apply the arguments to the callback function
|
|
234
|
-
}
|
|
227
|
+
args = Array.prototype.slice.call(arguments); // get a plain array from function arguments
|
|
228
|
+
args = args.slice(2); // slice the first two elements (callback & timeout), leaving an array of user arguments
|
|
229
|
+
let fn = callback;
|
|
230
|
+
callback = () => fn.apply(fn, args); // apply the arguments to the callback function
|
|
235
231
|
|
|
236
232
|
events.serial = +events.serial + 1;
|
|
237
233
|
timer = {
|
|
@@ -93,13 +93,10 @@ self.wrapScriptLoading({ scriptName: 'native-event-loop' }, function nativeEvent
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let fn = callback;
|
|
101
|
-
callback = () => fn.apply(fn, args); // apply the arguments to the callback function
|
|
102
|
-
}
|
|
96
|
+
args = Array.prototype.slice.call(arguments); // get a plain array from function arguments
|
|
97
|
+
args = args.slice(2); // slice the first two elements (callback & timeout), leaving an array of user arguments
|
|
98
|
+
let fn = callback;
|
|
99
|
+
callback = () => fn.apply(fn, args); // apply the arguments to the callback function
|
|
103
100
|
|
|
104
101
|
timers.serial = +timers.serial + 1;
|
|
105
102
|
timer = {
|
|
@@ -18,7 +18,7 @@ function worktimes$$fn(protectedStorage, _ring2PostMessage)
|
|
|
18
18
|
|
|
19
19
|
const worktimes = [
|
|
20
20
|
{ name: 'map-basic', versions: ['1.0.0'] },
|
|
21
|
-
{ name: 'pyodide', versions: ['0.24.
|
|
21
|
+
{ name: 'pyodide', versions: ['0.24.1'] },
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
function registerWorktime(name, version)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dcp-client",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.9-0",
|
|
4
4
|
"description": "Core libraries for accessing DCP network",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dcp"
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"regedit": "^3.0.3",
|
|
45
45
|
"semver": "^7.3.5",
|
|
46
46
|
"webpack": "5.92.0",
|
|
47
|
+
"source-map-support": "0.5.21",
|
|
47
48
|
"webpack-cli": "^4.7.2",
|
|
48
49
|
"yargs": "16.2.0"
|
|
49
50
|
},
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file attempt-to-fetch.js
|
|
4
|
+
*
|
|
5
|
+
* Attempt to fetch using nodejs' global fetch. This
|
|
6
|
+
* should have been blocked after access-lists was
|
|
7
|
+
* applied.
|
|
8
|
+
*
|
|
9
|
+
* This test must be called from a bash test so Peter is
|
|
10
|
+
* able to run it properly despite changes to globalThis.
|
|
11
|
+
*
|
|
12
|
+
* @author Will Pringle <will@distributive.network>
|
|
13
|
+
* @date December 2023
|
|
14
|
+
*/
|
|
15
|
+
const sandboxScripts = '../../libexec/sandbox/';
|
|
16
|
+
|
|
17
|
+
const files = [
|
|
18
|
+
require.resolve(sandboxScripts + 'script-load-wrapper.js'),
|
|
19
|
+
require.resolve(sandboxScripts + 'access-lists.js'),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
require('../../test-helpers/globalPolyfillHelper').init(files, ()=>{});
|
|
23
|
+
emitEvent('message', {request: 'applyRequirements', requirements: {environment: {}}});
|
|
24
|
+
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
// let's attempt to use nodejs' fetch to make a request to example.com
|
|
27
|
+
fetch('https://example.com').then(console.log);
|
|
28
|
+
})
|
|
29
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file autoupdate-check.js
|
|
3
|
+
* post-init details for auto update tests
|
|
4
|
+
*
|
|
5
|
+
* @author Wes Garland, wes@distributive.network
|
|
6
|
+
* @date March 2023
|
|
7
|
+
*/
|
|
8
|
+
const assert = require('assert').strict;
|
|
9
|
+
|
|
10
|
+
const runningBundle = require('dcp/build');
|
|
11
|
+
const bootstrapBundle = require('dcp/bootstrap-build');
|
|
12
|
+
|
|
13
|
+
console.log(' running bundle', runningBundle.version, runningBundle.branch);
|
|
14
|
+
console.log('bootstrap bundle', bootstrapBundle.version, bootstrapBundle.branch);
|
|
15
|
+
|
|
16
|
+
assert(runningBundle !== bootstrapBundle);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file config.js
|
|
3
|
+
* This is the actual test called for config-sync.tap and config-async.tap
|
|
4
|
+
*
|
|
5
|
+
* @author KC Erb
|
|
6
|
+
* @date Jul 2020
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
const { test } = require('zora');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const dcpConfig = require('dcp/dcp-config');
|
|
12
|
+
|
|
13
|
+
test('config order', function (t) {
|
|
14
|
+
t.equal(dcpConfig.etcOnly, "in-etc");
|
|
15
|
+
t.equal(dcpConfig.etcProgramName, "in-etc-config-tap");
|
|
16
|
+
t.equal(dcpConfig.homeDir, "in-homedir");
|
|
17
|
+
t.equal(dcpConfig.homeDirProgramName, "in-homedir-config-tap");
|
|
18
|
+
t.equal(dcpConfig.etcOverriden, "in-override");
|
|
19
|
+
t.equal(dcpConfig.etcProgramNameOverridden, "in-override");
|
|
20
|
+
t.equal(dcpConfig.homeDirOverridden, "in-override");
|
|
21
|
+
t.equal(dcpConfig.homeDirProgramNameOverriden, "in-override");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('config language - can call `scheduler` global', function (t) {
|
|
25
|
+
t.ok(dcpConfig.scheduler.canSetProgrammatically);
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (os.platform === 'win32') {
|
|
29
|
+
test('check some of that registry stuff', function (t) {
|
|
30
|
+
t.ok(false) // untested on windows!
|
|
31
|
+
})
|
|
32
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file etc/dcp-config.js
|
|
3
|
+
* DCP Config file fragment for the simple config test
|
|
4
|
+
* @author Wes Garland, wes@distributive.network
|
|
5
|
+
* @date Sep 2022
|
|
6
|
+
*/
|
|
7
|
+
{
|
|
8
|
+
stack: {
|
|
9
|
+
'/etc/dcp/dcp-config': 'should be overridden',
|
|
10
|
+
'./etc/dcp-config.js': 'yes',
|
|
11
|
+
'/home/username/.dcp/dcp-config.js': undefined,
|
|
12
|
+
'/home/username/.dcp/config.simple': undefined,
|
|
13
|
+
'/home/username/.dcp/config-simple-scope': undefined,
|
|
14
|
+
'initConfig': undefined,
|
|
15
|
+
'/etc/dcp/override-dcp-config': undefined,
|
|
16
|
+
'/etc/dcp/config-simple-scope': undefined,
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file globalPolyfillHelper.js
|
|
3
|
+
*
|
|
4
|
+
* Helper file for tests of scripts in libexec/sandbox. Most of the scripts assume
|
|
5
|
+
* some specific global symbols exist, so this script polyfills most of them. Depending on
|
|
6
|
+
* the scripts being tested, more polyfills may be required, which should be implemented
|
|
7
|
+
* in the individual test files. This file also executes the scripts provided in the global scope.
|
|
8
|
+
*
|
|
9
|
+
* @author Ryan Saweczko, ryansaweczko@kingsds.network
|
|
10
|
+
* @date January 2022
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
/**
|
|
16
|
+
* Initializes the global scope by evaluating a list of files. Typically,
|
|
17
|
+
* sandbox initialization files to setup necessary symbols to run test.
|
|
18
|
+
*
|
|
19
|
+
* Accepts a callback to make spying on post messages easier for test
|
|
20
|
+
* assertions.
|
|
21
|
+
*
|
|
22
|
+
* @param {string[]} files - A list of files to execute in the global scope.
|
|
23
|
+
* @param {(message: object) => void} [outputTesting] - Callback that receives post messages.
|
|
24
|
+
*/
|
|
25
|
+
exports.init = function init(files, outputTesting)
|
|
26
|
+
{
|
|
27
|
+
let code = ''
|
|
28
|
+
for (const file of files)
|
|
29
|
+
{
|
|
30
|
+
const fd = fs.openSync(file, 'r');
|
|
31
|
+
code += fs.readFileSync(fd, 'utf-8') + '\n';
|
|
32
|
+
fs.closeSync(fd);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The node worker injects several symbols into the context of the evaluator when it
|
|
36
|
+
// is started. These symbols are expected to exist on the global object within the evaluator.
|
|
37
|
+
// Emulate the expected global symbols that are most commonly used.
|
|
38
|
+
self = global;
|
|
39
|
+
global.KVIN = require('kvin');
|
|
40
|
+
global.performance = { now: Date.now };
|
|
41
|
+
const unmarshal = KVIN.unmarshal;
|
|
42
|
+
|
|
43
|
+
// postMessage is:
|
|
44
|
+
// a) expected to be a symbol in the evaluator
|
|
45
|
+
// b) the method almost always used to get information out of the evaluator.
|
|
46
|
+
// for this purpose, a callback function should be defined in each test to check
|
|
47
|
+
// whatever desired functionality works.
|
|
48
|
+
// eslint-disable-next-line vars-on-top
|
|
49
|
+
global.postMessage = (line) =>
|
|
50
|
+
{
|
|
51
|
+
line = unmarshal(line)
|
|
52
|
+
if (typeof outputTesting === 'function')
|
|
53
|
+
outputTesting(line);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Simulate die with process.exit
|
|
57
|
+
global.die = process.exit
|
|
58
|
+
|
|
59
|
+
// Very, very, very badly created event listener implementation - but suits the needs
|
|
60
|
+
const eventsListening = {}
|
|
61
|
+
global.addEventListener = (event,callback) =>
|
|
62
|
+
{
|
|
63
|
+
if (!eventsListening[event])
|
|
64
|
+
eventsListening[event] = [];
|
|
65
|
+
eventsListening[event].push(callback)
|
|
66
|
+
}
|
|
67
|
+
global.emitEvent = (event, data) =>
|
|
68
|
+
{
|
|
69
|
+
if (eventsListening[event])
|
|
70
|
+
for (let cb of eventsListening[event])
|
|
71
|
+
cb.call(null, data);
|
|
72
|
+
}
|
|
73
|
+
global.removeEventListener = (event, listener) =>
|
|
74
|
+
{
|
|
75
|
+
const listenerIdx = eventsListening[event].indexOf(listener);
|
|
76
|
+
eventsListening[event].splice(listenerIdx, 1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const indirect = eval;
|
|
80
|
+
indirect(code);
|
|
81
|
+
// At this point a very primitive version of the evaluator exists - all global symbols defined in
|
|
82
|
+
// by the supplied evaluator scripts 'files' exist/are overwritten in the global scope.
|
|
83
|
+
// Tests can now use such symbols, or event listeners that would be set up by the files to run tests over them.
|
|
84
|
+
}
|
|
85
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file setup-testenv.js
|
|
3
|
+
* Library code to set up the test environment for Peter .simple tests, so that the tests
|
|
4
|
+
* do not require a running scheduler, and are not influenced by the testing user's personal
|
|
5
|
+
* nor machine-wide configs, nor the scheduler's configs.
|
|
6
|
+
* @author Wes Garland, wes@kingsds.network
|
|
7
|
+
* @date Sep 2020
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
process.env.DCP_HOMEDIR = path.resolve(path.dirname(module.filename), '../test-pseudo-root/home/username');
|
|
14
|
+
process.env.DCP_ETCDIR = path.resolve(path.dirname(module.filename), '../test-pseudo-root/etc');
|
|
15
|
+
if (!process.env.DCP_CONFIG_LOCATION)
|
|
16
|
+
process.env.DCP_CONFIG_LOCATION = '';
|
|
17
|
+
if (process.env.DCP_SCHEDULER_LOCATION)
|
|
18
|
+
process.env.DCP_SCHEDULER_LOCATION = '';
|
|
19
|
+
if (!process.env.DCP_BUNDLE_LOCATION)
|
|
20
|
+
process.env.DCP_BUNDLE_LOCATION = 'https://scheduler.distributed.computer/dcp-client/dist/dcp-client-bundle.js';
|
|
21
|
+
process.env.DCP_REGISTRY_BASEKEY = `Software\\Distributive\\DCP-Client-Tests\\Peter`;
|
|
22
|
+
|
|
23
|
+
if (require('os').platform() === 'win32')
|
|
24
|
+
{
|
|
25
|
+
require('child_process').spawnSync('reg.exe', [ 'delete', 'HKLM\\' + process.env_DCP_REGISTRY_BASEKEY, '-f' ]);
|
|
26
|
+
require('child_process').spawnSync('reg.exe', [ 'delete', 'HKCU\\' + process.env_DCP_REGISTRY_BASEKEY, '-f' ]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Some tests don't load dcp-client */
|
|
30
|
+
var dcpDcp;
|
|
31
|
+
try
|
|
32
|
+
{
|
|
33
|
+
dotDcp = require('dcp/dcp-dot-dir');
|
|
34
|
+
}
|
|
35
|
+
catch(e) {};
|
|
36
|
+
if (dcpDcp)
|
|
37
|
+
dotDcp.setHomeDir(process.env.DCP_HOMEDIR);
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<!-- @file minimal.html
|
|
4
|
-
--
|
|
5
|
-
-- Sample web page showing how to deploy a minimal DCP job with a client written
|
|
6
|
-
-- using BravoJS
|
|
7
|
-
--
|
|
8
|
-
-- @author Wes Garland, wes@kingsds.network
|
|
9
|
-
-- @date Oct 2019
|
|
10
|
-
--
|
|
11
|
-
-->
|
|
12
|
-
<head><meta charset="utf-8">
|
|
13
|
-
<script src="../../../bravojs/bravo.js"></script>
|
|
14
|
-
<script src="https://scheduler.distributed.computer/etc/dcp-config.js"></script>
|
|
15
|
-
</head>
|
|
16
|
-
<body onload="module.main.start()">
|
|
17
|
-
This is a minimal vanilla web dcp-client/BravoJS example. Look in your browser's console for output.
|
|
18
|
-
<script>
|
|
19
|
-
module.declare(['../../dcp-client'], function(require, exports, module) {
|
|
20
|
-
exports.start = async function() {
|
|
21
|
-
await require('../../dcp-client').init()
|
|
22
|
-
const compute = require('dcp/compute')
|
|
23
|
-
let results = await compute.for(1, 10,
|
|
24
|
-
function(i) {
|
|
25
|
-
let result = i*3
|
|
26
|
-
console.log(`Calculated result for slice #${i}`)
|
|
27
|
-
progress(i/10)
|
|
28
|
-
return result
|
|
29
|
-
}).exec(compute.marketValue)
|
|
30
|
-
console.log(results)
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
</script>
|
|
34
|
-
</body>
|
|
35
|
-
</html>
|