@ethernity-cloud/sdk-js 1.7.7 → 1.7.9
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 +2 -1
- package/localKubo.js +59 -14
- package/nodenithy/run.js +5 -1
- package/nodenithy/src/ec_helloworld_example.js +5 -1
- package/package.json +3 -2
- package/pynithy/run.js +5 -1
- package/pynithy/src/ec_helloworld_example.js +5 -1
- package/run.js +10 -3
package/README.md
CHANGED
|
@@ -50,7 +50,8 @@ The sdk has been tested on the following operating systems:
|
|
|
50
50
|
for the compose and the certificate harvest, takes the trustedzone
|
|
51
51
|
session name from the ImageRegistry, and links the session to the
|
|
52
52
|
published image. `ecld-build` signs the securelock `--production`.
|
|
53
|
-
|
|
53
|
+
The certificate is harvested on an SGX host or, without one, extracted
|
|
54
|
+
by publickey.ethernity.cloud (see "How the image reaches the network").
|
|
54
55
|
- Testnet Unsafe - the unsafe network beside the testnet (see below).
|
|
55
56
|
- Mainnet - to be provided during the following updates
|
|
56
57
|
- LitVM:
|
package/localKubo.js
CHANGED
|
@@ -46,6 +46,14 @@ function freePort() {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// The host port in the first line of `docker port <container> 5001/tcp`
|
|
50
|
+
// (`127.0.0.1:60823`), or null when there is none.
|
|
51
|
+
function apiPortIn(dockerPortOutput) {
|
|
52
|
+
const first = String(dockerPortOutput || '').trim().split('\n')[0] || '';
|
|
53
|
+
const match = /:(\d+)$/.exec(first.trim());
|
|
54
|
+
return match ? Number(match[1]) : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
// Whether the configured endpoint is one of the application's own; the public
|
|
50
58
|
// API and an empty setting both mean "run a Kubo for this publish".
|
|
51
59
|
function ownEndpoint(endpoint) {
|
|
@@ -62,6 +70,10 @@ class LocalKubo {
|
|
|
62
70
|
this.container = `ecld-kubo-${String(name || 'publish').replace(/[^A-Za-z0-9_.-]/g, '-')}`;
|
|
63
71
|
this.peers = (process.env.ECLD_IPFS_PEERS || BOOTNODE_MULTIADDR).split(',').map((p) => p.trim()).filter(Boolean);
|
|
64
72
|
this.apiUrl = null;
|
|
73
|
+
// True while a registered image has this Kubo as its source: from the
|
|
74
|
+
// image's registration on chain until its certificate is on chain. A
|
|
75
|
+
// publish that ends in between leaves the Kubo running (release).
|
|
76
|
+
this.serving = false;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
async api(command, params, timeout) {
|
|
@@ -69,21 +81,40 @@ class LocalKubo {
|
|
|
69
81
|
return response.data;
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
const apiPort = await freePort();
|
|
76
|
-
this.apiUrl = `http://127.0.0.1:${apiPort}`;
|
|
77
|
-
try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* not running */ }
|
|
78
|
-
const args = ['run', '-d', '--name', this.container, '-p', `127.0.0.1:${apiPort}:5001`];
|
|
79
|
-
if (await portFree(SWARM_PORT)) {
|
|
80
|
-
args.push('-p', `${SWARM_PORT}:4001`, '-p', `${SWARM_PORT}:4001/udp`);
|
|
81
|
-
}
|
|
82
|
-
args.push(KUBO_IMAGE, 'daemon', '--init', '--migrate=true');
|
|
84
|
+
// The API port of the container a previous publish of this project left
|
|
85
|
+
// running (release), or null when none runs.
|
|
86
|
+
keptApiPort() {
|
|
83
87
|
try {
|
|
84
|
-
execFileSync('docker',
|
|
88
|
+
return apiPortIn(execFileSync('docker', ['port', this.container, '5001/tcp'], { stdio: ['ignore', 'pipe', 'ignore'] }));
|
|
85
89
|
} catch (e) {
|
|
86
|
-
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Start the container and wait for its API, or take over the one a
|
|
95
|
+
// previous publish of this project left serving its registered image,
|
|
96
|
+
// whose peer id that image's registry entry names; peer it with the
|
|
97
|
+
// bootnode. Throws when docker cannot run it or the API does not come up
|
|
98
|
+
// in time.
|
|
99
|
+
async start() {
|
|
100
|
+
const kept = this.keptApiPort();
|
|
101
|
+
if (kept !== null) {
|
|
102
|
+
this.apiUrl = `http://127.0.0.1:${kept}`;
|
|
103
|
+
console.log(`\t✔ IPFS node of the previous publish kept: ${this.container}`);
|
|
104
|
+
} else {
|
|
105
|
+
const apiPort = await freePort();
|
|
106
|
+
this.apiUrl = `http://127.0.0.1:${apiPort}`;
|
|
107
|
+
try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* not running */ }
|
|
108
|
+
const args = ['run', '-d', '--name', this.container, '-p', `127.0.0.1:${apiPort}:5001`];
|
|
109
|
+
if (await portFree(SWARM_PORT)) {
|
|
110
|
+
args.push('-p', `${SWARM_PORT}:4001`, '-p', `${SWARM_PORT}:4001/udp`);
|
|
111
|
+
}
|
|
112
|
+
args.push(KUBO_IMAGE, 'daemon', '--init', '--migrate=true');
|
|
113
|
+
try {
|
|
114
|
+
execFileSync('docker', args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
115
|
+
} catch (e) {
|
|
116
|
+
throw new Error(`docker could not start ${KUBO_IMAGE}: ${String(e.stderr || e.message).trim()}`);
|
|
117
|
+
}
|
|
87
118
|
}
|
|
88
119
|
const deadline = Date.now() + API_READY_MS;
|
|
89
120
|
for (;;) {
|
|
@@ -155,6 +186,20 @@ class LocalKubo {
|
|
|
155
186
|
stop() {
|
|
156
187
|
try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* already gone */ }
|
|
157
188
|
}
|
|
189
|
+
|
|
190
|
+
// End the publish's use of the Kubo: stop it, unless it is the source of
|
|
191
|
+
// a registered image whose certificate is not on chain yet, which it keeps
|
|
192
|
+
// serving to the extraction service and the bootnode's mirror; the next
|
|
193
|
+
// publish of the project takes it over, `docker rm -f` stops it.
|
|
194
|
+
release() {
|
|
195
|
+
if (!this.serving) {
|
|
196
|
+
this.stop();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
console.log(`\t⚠ The registered image stays available from this publish's IPFS node, the docker`);
|
|
200
|
+
console.log(`\t container ${this.container}, for the extraction service and the bootnode.`);
|
|
201
|
+
console.log(`\t Publish again to retry; \`docker rm -f ${this.container}\` stops it.`);
|
|
202
|
+
}
|
|
158
203
|
}
|
|
159
204
|
|
|
160
|
-
module.exports = { LocalKubo, ownEndpoint, PUBLIC_IPFS_HOST };
|
|
205
|
+
module.exports = { LocalKubo, ownEndpoint, apiPortIn, PUBLIC_IPFS_HOST };
|
package/nodenithy/run.js
CHANGED
|
@@ -137,7 +137,7 @@ const main = async () => {
|
|
|
137
137
|
}
|
|
138
138
|
ipfsApi = localKubo.apiUrl;
|
|
139
139
|
console.log(`\t✔ IPFS node for this publish: ${ipfsApi}`);
|
|
140
|
-
process.on('exit', () => localKubo.
|
|
140
|
+
process.on('exit', () => localKubo.release());
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// The CIDs uploadToIpfs gives, from the same add calls with only-hash: the
|
|
@@ -580,6 +580,9 @@ const main = async () => {
|
|
|
580
580
|
hashForIpfs();
|
|
581
581
|
if (localKubo) ipfsPeer = await localKubo.peerMultiaddr();
|
|
582
582
|
execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "registerImage"`, { stdio: "inherit", env: { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer } });
|
|
583
|
+
// From here the registered image's source is this Kubo, until its
|
|
584
|
+
// certificate is on chain.
|
|
585
|
+
if (localKubo) localKubo.serving = true;
|
|
583
586
|
}
|
|
584
587
|
uploadToIpfs();
|
|
585
588
|
const registryEnv = { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer };
|
|
@@ -711,6 +714,7 @@ const main = async () => {
|
|
|
711
714
|
process.chdir(currentDir);
|
|
712
715
|
console.log(`Registering the certificate of SECURELOCK ${securelock} in the IMAGE REGISTRY smart contract...`);
|
|
713
716
|
execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "setImageCert"`, { stdio: "inherit", env: registryEnv });
|
|
717
|
+
if (localKubo) localKubo.serving = false;
|
|
714
718
|
} else {
|
|
715
719
|
// A V1 registry gets the tree that carries the certificate files,
|
|
716
720
|
// uploaded again, with the certificate, in one addImage call.
|
|
@@ -23,7 +23,11 @@ function App() {
|
|
|
23
23
|
if (UNSAFE_NETWORK) {
|
|
24
24
|
await runner.setNetwork(...UNSAFE_NETWORK);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
// An IPFS API of the dApp's own carries the task's artefacts; without
|
|
27
|
+
// one they go through the bootnode's payload intake (the public API's
|
|
28
|
+
// add is closed to callers without a token).
|
|
29
|
+
if (IPFS_ENDPOINT && !IPFS_ENDPOINT.includes("ipfs.ethernity.cloud")) runner.initializeStorage(IPFS_ENDPOINT);
|
|
30
|
+
else runner.initializePublicIntake();
|
|
27
31
|
|
|
28
32
|
// Events are named by task status; detail is { message, status, progress }.
|
|
29
33
|
runner.addEventListener(ECStatus.DEFAULT, (e) => {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ethernity-cloud/sdk-js",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "A package to run ethernity cloud build scripts",
|
|
5
5
|
"scripts": {
|
|
6
|
+
"test": "node --test \"test/**/*.test.js\"",
|
|
6
7
|
"ecld-build": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/build.js",
|
|
7
8
|
"ecld-publish": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/publish.js",
|
|
8
9
|
"ecld-init": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/init.js",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
"!**/*.pyc"
|
|
39
40
|
],
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"@ethernity-cloud/runner": "^0.6.
|
|
42
|
+
"@ethernity-cloud/runner": "^0.6.4",
|
|
42
43
|
"acorn": "^8.11.0",
|
|
43
44
|
"adm-zip": "^0.5.14",
|
|
44
45
|
"axios": "^1.7.2",
|
package/pynithy/run.js
CHANGED
|
@@ -138,7 +138,7 @@ const main = async () => {
|
|
|
138
138
|
}
|
|
139
139
|
ipfsApi = localKubo.apiUrl;
|
|
140
140
|
console.log(`\t✔ IPFS node for this publish: ${ipfsApi}`);
|
|
141
|
-
process.on('exit', () => localKubo.
|
|
141
|
+
process.on('exit', () => localKubo.release());
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// The CIDs uploadToIpfs gives, from the same add calls with only-hash: the
|
|
@@ -579,6 +579,9 @@ const main = async () => {
|
|
|
579
579
|
hashForIpfs();
|
|
580
580
|
if (localKubo) ipfsPeer = await localKubo.peerMultiaddr();
|
|
581
581
|
execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "registerImage"`, { stdio: "inherit", env: { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer } });
|
|
582
|
+
// From here the registered image's source is this Kubo, until its
|
|
583
|
+
// certificate is on chain.
|
|
584
|
+
if (localKubo) localKubo.serving = true;
|
|
582
585
|
}
|
|
583
586
|
uploadToIpfs();
|
|
584
587
|
const registryEnv = { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer };
|
|
@@ -688,6 +691,7 @@ const main = async () => {
|
|
|
688
691
|
process.chdir(currentDir);
|
|
689
692
|
console.log(`Registering the certificate of SECURELOCK ${securelock} in the IMAGE REGISTRY smart contract...`);
|
|
690
693
|
execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "setImageCert"`, { stdio: "inherit", env: registryEnv });
|
|
694
|
+
if (localKubo) localKubo.serving = false;
|
|
691
695
|
} else {
|
|
692
696
|
// A V1 registry gets the tree that carries the certificate files,
|
|
693
697
|
// uploaded again, with the certificate, in one addImage call.
|
|
@@ -23,7 +23,11 @@ function App() {
|
|
|
23
23
|
if (UNSAFE_NETWORK) {
|
|
24
24
|
await runner.setNetwork(...UNSAFE_NETWORK);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
// An IPFS API of the dApp's own carries the task's artefacts; without
|
|
27
|
+
// one they go through the bootnode's payload intake (the public API's
|
|
28
|
+
// add is closed to callers without a token).
|
|
29
|
+
if (IPFS_ENDPOINT && !IPFS_ENDPOINT.includes("ipfs.ethernity.cloud")) runner.initializeStorage(IPFS_ENDPOINT);
|
|
30
|
+
else runner.initializePublicIntake();
|
|
27
31
|
|
|
28
32
|
// Events are named by task status; detail is { message, status, progress }.
|
|
29
33
|
runner.addEventListener(ECStatus.DEFAULT, (e) => {
|
package/run.js
CHANGED
|
@@ -42,7 +42,12 @@ try { require('dotenv').config(); } catch (e) { /* dotenv optional */ }
|
|
|
42
42
|
const casConfig = require('./cas/config.js');
|
|
43
43
|
const { networkFor, unsafeVariant } = require('./network.js');
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
// `--ipfs intake` (the default): the artefacts' CIDs are computed locally and
|
|
46
|
+
// the bytes delivered to the bootnode's payload intake once the DO request is
|
|
47
|
+
// on chain (runner initializePublicIntake); `--ipfs <url>` uploads and reads
|
|
48
|
+
// through that Kubo RPC API instead. The public API's add is closed to callers
|
|
49
|
+
// without a token.
|
|
50
|
+
const DEFAULT_IPFS = 'intake';
|
|
46
51
|
|
|
47
52
|
function parseArgs(argv) {
|
|
48
53
|
const opts = { ipfs: DEFAULT_IPFS, timeout: 600, taskPrice: 3, cpu: 1, memory: 1, storage: 10, bandwidth: 1, duration: 1, validators: 1, node: '' };
|
|
@@ -86,7 +91,8 @@ enclaves: --securelock <name> (default PROJECT_NAME), --trustedzone <name> (def
|
|
|
86
91
|
on an -unsafe network the default is each one's -unsafe variant
|
|
87
92
|
key: PRIVATE_KEY (a funded 0x key) from .env / env, or ECLD_PRIVATE_KEY
|
|
88
93
|
resources: --task-price 3 --cpu 1 --memory 1 --storage 10 --bandwidth 1 --duration 1 --validators 1
|
|
89
|
-
other: --node <addr> --ipfs
|
|
94
|
+
other: --node <addr> --ipfs intake|<kubo api url> (default intake: the bootnode's payload intake)
|
|
95
|
+
--timeout <sec> --json`;
|
|
90
96
|
|
|
91
97
|
async function main() {
|
|
92
98
|
const { opts, positional } = parseArgs(process.argv.slice(2));
|
|
@@ -173,7 +179,8 @@ async function main() {
|
|
|
173
179
|
console.error('ecld-run: could not initialise the runner: ' + e.message);
|
|
174
180
|
process.exit(1);
|
|
175
181
|
}
|
|
176
|
-
|
|
182
|
+
if (opts.ipfs === 'intake') runner.initializePublicIntake();
|
|
183
|
+
else runner.initializeStorage(opts.ipfs);
|
|
177
184
|
|
|
178
185
|
let lastPhase = null;
|
|
179
186
|
const onProgress = (e) => {
|