@peerbit/server 1.1.1 → 2.0.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/lib/esm/cli.js +471 -144
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/client.d.ts +5 -3
- package/lib/esm/client.js +25 -8
- package/lib/esm/client.js.map +1 -1
- package/lib/esm/config.d.ts +7 -4
- package/lib/esm/config.js +34 -17
- package/lib/esm/config.js.map +1 -1
- package/lib/esm/peerbit.d.ts +2 -0
- package/lib/esm/peerbit.js +17 -3
- package/lib/esm/peerbit.js.map +1 -1
- package/lib/esm/remotes.browser.d.ts +0 -0
- package/lib/esm/remotes.browser.js +3 -0
- package/lib/esm/remotes.browser.js.map +1 -0
- package/lib/esm/remotes.d.ts +17 -0
- package/lib/esm/remotes.js +52 -0
- package/lib/esm/remotes.js.map +1 -0
- package/lib/esm/routes.d.ts +2 -0
- package/lib/esm/routes.js +2 -0
- package/lib/esm/routes.js.map +1 -1
- package/lib/esm/server.d.ts +17 -3
- package/lib/esm/server.js +217 -45
- package/lib/esm/server.js.map +1 -1
- package/lib/esm/session.d.ts +19 -0
- package/lib/esm/session.js +49 -0
- package/lib/esm/session.js.map +1 -0
- package/lib/esm/types.d.ts +10 -0
- package/lib/ui/assets/{index-a8188422.js → index-73eaa3bc.js} +10 -10
- package/lib/ui/index.html +1 -1
- package/package.json +7 -3
- package/src/cli.ts +649 -271
- package/src/client.ts +43 -10
- package/src/config.ts +44 -21
- package/src/peerbit.ts +27 -4
- package/src/remotes.browser.ts +1 -0
- package/src/remotes.ts +65 -0
- package/src/routes.ts +2 -0
- package/src/server.ts +284 -51
- package/src/session.ts +69 -0
- package/src/types.ts +13 -0
- package/lib/ui/assets/config.browser-4ed993c7.js +0 -1
package/src/cli.ts
CHANGED
|
@@ -6,10 +6,29 @@ import {
|
|
|
6
6
|
} from "./domain.js";
|
|
7
7
|
import { startServerWithNode } from "./server.js";
|
|
8
8
|
import { createRecord } from "./aws.js";
|
|
9
|
-
import {
|
|
9
|
+
import { getHomeConfigDir, getPackageName, getRemotesPath } from "./config.js";
|
|
10
10
|
import chalk from "chalk";
|
|
11
11
|
import { client } from "./client.js";
|
|
12
|
-
import { StartProgram } from "./types.js";
|
|
12
|
+
import { InstallDependency, StartProgram } from "./types.js";
|
|
13
|
+
import { exit } from "process";
|
|
14
|
+
import yargs from "yargs";
|
|
15
|
+
import readline from "readline";
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
import { toBase64 } from "@peerbit/crypto";
|
|
19
|
+
import { Remotes } from "./remotes.js";
|
|
20
|
+
|
|
21
|
+
const padString = function (string: string, padding: number, padChar = " ") {
|
|
22
|
+
const val = string.valueOf();
|
|
23
|
+
if (Math.abs(padding) <= val.length) {
|
|
24
|
+
return val;
|
|
25
|
+
}
|
|
26
|
+
const m = Math.max(Math.abs(padding) - string.length || 0, 0);
|
|
27
|
+
const pad = Array(m + 1).join(String(padChar).charAt(0));
|
|
28
|
+
// var pad = String(c || ' ').charAt(0).repeat(Math.abs(n) - this.length);
|
|
29
|
+
return padding < 0 ? pad + val : val + pad;
|
|
30
|
+
// return (n < 0) ? val + pad : pad + val;
|
|
31
|
+
};
|
|
13
32
|
|
|
14
33
|
export const cli = async (args?: string[]) => {
|
|
15
34
|
const yargs = await import("yargs");
|
|
@@ -24,19 +43,48 @@ export const cli = async (args?: string[]) => {
|
|
|
24
43
|
.command({
|
|
25
44
|
command: "start",
|
|
26
45
|
describe: "Start node",
|
|
27
|
-
builder: {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
builder: (yargs: yargs.Argv) => {
|
|
47
|
+
yargs
|
|
48
|
+
.option("directory", {
|
|
49
|
+
describe: "Peerbit directory",
|
|
50
|
+
defaultDescription: "~.peerbit",
|
|
51
|
+
type: "string",
|
|
52
|
+
alias: "d",
|
|
53
|
+
default: getHomeConfigDir(),
|
|
54
|
+
})
|
|
55
|
+
.option("bootstrap", {
|
|
56
|
+
describe: "Whether to connect to bootstap nodes on startup",
|
|
57
|
+
type: "boolean",
|
|
58
|
+
default: false,
|
|
59
|
+
})
|
|
60
|
+
.option("reset", {
|
|
61
|
+
describe:
|
|
62
|
+
"If true, then programs opened during last session will not be opened",
|
|
63
|
+
type: "boolean",
|
|
64
|
+
default: false,
|
|
65
|
+
alias: "r",
|
|
66
|
+
})
|
|
67
|
+
.option("password", {
|
|
68
|
+
describe:
|
|
69
|
+
"Setup password so you can interact with the node remotely",
|
|
70
|
+
type: "string",
|
|
71
|
+
defaultDescription:
|
|
72
|
+
"The password from the last session will be used or a password will be generated",
|
|
73
|
+
default: undefined,
|
|
74
|
+
})
|
|
75
|
+
.option("port-api", {
|
|
76
|
+
describe:
|
|
77
|
+
"Set API server port. Only modify this when testing locally, since NGINX config depends on the default value",
|
|
78
|
+
type: "number",
|
|
79
|
+
default: undefined,
|
|
80
|
+
})
|
|
81
|
+
.option("port-node", {
|
|
82
|
+
describe:
|
|
83
|
+
"Set Libp2p listen port. Only modify this when testing locally, since NGINX config depends on the default value",
|
|
84
|
+
type: "number",
|
|
85
|
+
default: undefined,
|
|
86
|
+
});
|
|
87
|
+
return yargs;
|
|
40
88
|
},
|
|
41
89
|
handler: async (args) => {
|
|
42
90
|
await startServerWithNode({
|
|
@@ -44,306 +92,636 @@ export const cli = async (args?: string[]) => {
|
|
|
44
92
|
domain: await loadConfig().then((config) =>
|
|
45
93
|
config ? getDomainFromConfig(config) : undefined
|
|
46
94
|
),
|
|
95
|
+
ports: { api: args["port-api"], node: args["port-node"] },
|
|
47
96
|
bootstrap: args.bootstrap,
|
|
97
|
+
password: args.password,
|
|
98
|
+
newSession: args.reset,
|
|
48
99
|
});
|
|
49
100
|
},
|
|
50
101
|
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const { exit } = await import("process");
|
|
79
|
-
exit();
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
.command({
|
|
83
|
-
command: "aws",
|
|
84
|
-
describe:
|
|
85
|
-
"Setup a domain with an AWS account. You either have to setup you AWS credentials in the .aws folder, or pass the credentials in the cli",
|
|
86
|
-
builder: {
|
|
87
|
-
domain: {
|
|
88
|
-
describe: "domain, e.g. abc.example.com, example.com",
|
|
89
|
-
alias: "d",
|
|
90
|
-
type: "string",
|
|
91
|
-
demandOption: true,
|
|
92
|
-
},
|
|
93
|
-
hostedZoneId: {
|
|
94
|
-
describe: 'The id of the hosted zone "HostedZoneId"',
|
|
95
|
-
alias: "hz",
|
|
96
|
-
type: "string",
|
|
97
|
-
require: true,
|
|
98
|
-
},
|
|
99
|
-
accessKeyId: {
|
|
100
|
-
describe: "Access key id of the AWS user",
|
|
101
|
-
alias: "ak",
|
|
102
|
-
type: "string",
|
|
103
|
-
},
|
|
104
|
-
region: {
|
|
105
|
-
describe: "AWS region",
|
|
106
|
-
alias: "r",
|
|
107
|
-
type: "string",
|
|
108
|
-
},
|
|
109
|
-
secretAccessKey: {
|
|
110
|
-
describe: "Secret key id of the AWS user",
|
|
111
|
-
alias: "sk",
|
|
112
|
-
type: "string",
|
|
113
|
-
},
|
|
114
|
-
email: {
|
|
115
|
-
describe: "Email for Lets encrypt auto-renewal messages",
|
|
116
|
-
type: "string",
|
|
117
|
-
demandOption: true,
|
|
102
|
+
|
|
103
|
+
.command(
|
|
104
|
+
"domain",
|
|
105
|
+
"Setup a domain and certificate for this node",
|
|
106
|
+
(yargs) => {
|
|
107
|
+
yargs
|
|
108
|
+
.command({
|
|
109
|
+
command: "test",
|
|
110
|
+
describe:
|
|
111
|
+
"Setup a testing domain with SSL (no guarantess on how long the domain will be available)",
|
|
112
|
+
builder: {
|
|
113
|
+
email: {
|
|
114
|
+
describe: "Email for Lets encrypt autorenewal messages",
|
|
115
|
+
type: "string",
|
|
116
|
+
demandOption: true,
|
|
117
|
+
},
|
|
118
|
+
outdir: {
|
|
119
|
+
describe: "Output path for Nginx config",
|
|
120
|
+
type: "string",
|
|
121
|
+
alias: "o",
|
|
122
|
+
},
|
|
123
|
+
wait: {
|
|
124
|
+
alias: "w",
|
|
125
|
+
describe: "Wait for setup to succeed (or fail)",
|
|
126
|
+
type: "boolean",
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
118
129
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
handler: async (args) => {
|
|
131
|
+
const domain = await createTestDomain();
|
|
132
|
+
await startCertbot(domain, args.email, args.outdir, args.wait);
|
|
133
|
+
exit();
|
|
123
134
|
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
})
|
|
136
|
+
.command({
|
|
137
|
+
command: "aws",
|
|
138
|
+
describe:
|
|
139
|
+
"Setup a domain with an AWS account. You either have to setup you AWS credentials in the .aws folder, or pass the credentials in the cli",
|
|
140
|
+
builder: {
|
|
141
|
+
domain: {
|
|
142
|
+
describe: "domain, e.g. abc.example.com, example.com",
|
|
143
|
+
alias: "d",
|
|
144
|
+
type: "string",
|
|
145
|
+
demandOption: true,
|
|
146
|
+
},
|
|
147
|
+
hostedZoneId: {
|
|
148
|
+
describe: 'The id of the hosted zone "HostedZoneId"',
|
|
149
|
+
alias: "hz",
|
|
150
|
+
type: "string",
|
|
151
|
+
require: true,
|
|
152
|
+
},
|
|
153
|
+
accessKeyId: {
|
|
154
|
+
describe: "Access key id of the AWS user",
|
|
155
|
+
alias: "ak",
|
|
156
|
+
type: "string",
|
|
157
|
+
},
|
|
158
|
+
region: {
|
|
159
|
+
describe: "AWS region",
|
|
160
|
+
alias: "r",
|
|
161
|
+
type: "string",
|
|
162
|
+
},
|
|
163
|
+
secretAccessKey: {
|
|
164
|
+
describe: "Secret key id of the AWS user",
|
|
165
|
+
alias: "sk",
|
|
166
|
+
type: "string",
|
|
167
|
+
},
|
|
168
|
+
email: {
|
|
169
|
+
describe: "Email for Lets encrypt auto-renewal messages",
|
|
170
|
+
type: "string",
|
|
171
|
+
demandOption: true,
|
|
172
|
+
},
|
|
173
|
+
outdir: {
|
|
174
|
+
describe: "Output path for Nginx config",
|
|
175
|
+
type: "string",
|
|
176
|
+
alias: "o",
|
|
177
|
+
},
|
|
178
|
+
wait: {
|
|
179
|
+
alias: "w",
|
|
180
|
+
describe: "Wait for setup to succeed (or fail)",
|
|
181
|
+
type: "boolean",
|
|
182
|
+
default: false,
|
|
183
|
+
},
|
|
129
184
|
},
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
185
|
+
handler: async (args) => {
|
|
186
|
+
if (
|
|
187
|
+
!!args.accessKeyId !== !!args.secretAccessKey ||
|
|
188
|
+
!!args.region !== !!args.secretAccessKey
|
|
189
|
+
) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
"Expecting either all 'accessKeyId', 'region' and 'secretAccessKey' to be provided or none"
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
await createRecord({
|
|
195
|
+
domain: args.domain,
|
|
196
|
+
hostedZoneId: args.hostedZoneId,
|
|
197
|
+
region: args.region,
|
|
198
|
+
credentials: args.accessKeyId
|
|
199
|
+
? {
|
|
200
|
+
accessKeyId: args.accessKeyId,
|
|
201
|
+
secretAccessKey: args.secretAccessKey,
|
|
202
|
+
}
|
|
203
|
+
: undefined,
|
|
204
|
+
});
|
|
205
|
+
await startCertbot(
|
|
206
|
+
args.domain,
|
|
207
|
+
args.email,
|
|
208
|
+
args.outdir,
|
|
209
|
+
args.wait
|
|
138
210
|
);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
: undefined,
|
|
150
|
-
});
|
|
151
|
-
await startCertbot(args.domain, args.email, args.outdir, args.wait);
|
|
152
|
-
const { exit } = await import("process");
|
|
153
|
-
exit();
|
|
154
|
-
},
|
|
155
|
-
})
|
|
156
|
-
.strict()
|
|
157
|
-
.demandCommand();
|
|
158
|
-
})
|
|
159
|
-
.command("network", "Manage network", (yargs) => {
|
|
160
|
-
yargs
|
|
161
|
-
.command({
|
|
162
|
-
command: "bootstrap",
|
|
163
|
-
describe: "Connect to bootstrap nodes",
|
|
164
|
-
handler: async () => {
|
|
165
|
-
const c = await client();
|
|
166
|
-
await c.network.bootstrap();
|
|
167
|
-
},
|
|
168
|
-
})
|
|
169
|
-
.strict()
|
|
170
|
-
.demandCommand();
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
.command("topic", "Manage topics the node is listening to", (yargs) => {
|
|
174
|
-
yargs
|
|
211
|
+
exit();
|
|
212
|
+
},
|
|
213
|
+
})
|
|
214
|
+
.strict()
|
|
215
|
+
.demandCommand();
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
.command("remote", "Handle remote nodes", (innerYargs) => {
|
|
219
|
+
innerYargs
|
|
175
220
|
.command({
|
|
176
221
|
command: "list",
|
|
177
222
|
aliases: "ls",
|
|
178
|
-
describe: "List
|
|
179
|
-
builder: (yargs:
|
|
180
|
-
yargs.option("
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
223
|
+
describe: "List remotes",
|
|
224
|
+
builder: (yargs: yargs.Argv) => {
|
|
225
|
+
yargs.option("directory", {
|
|
226
|
+
describe: "Peerbit directory",
|
|
227
|
+
defaultDescription: "~.peerbit",
|
|
228
|
+
type: "string",
|
|
229
|
+
alias: "d",
|
|
230
|
+
default: getHomeConfigDir(),
|
|
185
231
|
});
|
|
232
|
+
|
|
186
233
|
return yargs;
|
|
187
234
|
},
|
|
188
235
|
handler: async (args) => {
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
236
|
+
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
237
|
+
const allRemotes = await remotes.all();
|
|
238
|
+
const maxNameLength = allRemotes
|
|
239
|
+
.map((x) => x.name.length)
|
|
240
|
+
.reduce((prev, c, i) => {
|
|
241
|
+
return Math.max(prev, c);
|
|
242
|
+
}, 0);
|
|
243
|
+
const all = await remotes.all();
|
|
244
|
+
if (all.length > 0) {
|
|
245
|
+
for (const remote of all) {
|
|
246
|
+
console.log(
|
|
247
|
+
padString(remote.name, maxNameLength + 10),
|
|
248
|
+
remote.address
|
|
249
|
+
);
|
|
195
250
|
}
|
|
196
251
|
} else {
|
|
197
|
-
console.log("
|
|
198
|
-
}
|
|
199
|
-
console.error("Not implemented");
|
|
252
|
+
console.log("No remotes found!");
|
|
253
|
+
}
|
|
200
254
|
},
|
|
201
255
|
})
|
|
202
|
-
.strict()
|
|
203
|
-
.demandCommand();
|
|
204
|
-
return yargs;
|
|
205
|
-
})
|
|
206
|
-
.command("program", "Manage programs", (yargs) => {
|
|
207
|
-
yargs
|
|
208
256
|
.command({
|
|
209
|
-
command: "
|
|
210
|
-
describe: "
|
|
211
|
-
builder: (yargs:
|
|
212
|
-
yargs
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
257
|
+
command: "add <name> <address> <password>",
|
|
258
|
+
describe: "Add remote",
|
|
259
|
+
builder: (yargs: yargs.Argv) => {
|
|
260
|
+
yargs
|
|
261
|
+
.positional("address", {
|
|
262
|
+
type: "string",
|
|
263
|
+
describe: "Remote name",
|
|
264
|
+
demandOption: true,
|
|
265
|
+
})
|
|
266
|
+
.positional("name", {
|
|
267
|
+
type: "string",
|
|
268
|
+
describe: "Remote address",
|
|
269
|
+
demandOption: true,
|
|
270
|
+
})
|
|
271
|
+
.positional("password", {
|
|
272
|
+
type: "string",
|
|
273
|
+
describe: "Password",
|
|
274
|
+
demandOption: true,
|
|
275
|
+
})
|
|
276
|
+
.option("directory", {
|
|
277
|
+
describe: "Peerbit directory",
|
|
278
|
+
defaultDescription: "~.peerbit",
|
|
279
|
+
type: "string",
|
|
280
|
+
alias: "d",
|
|
281
|
+
default: getHomeConfigDir(),
|
|
282
|
+
});
|
|
283
|
+
|
|
217
284
|
return yargs;
|
|
218
285
|
},
|
|
219
|
-
|
|
220
286
|
handler: async (args) => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (!program) {
|
|
224
|
-
console.log(chalk.red("Closed"));
|
|
225
|
-
} else {
|
|
226
|
-
console.log(chalk.green("Open"));
|
|
287
|
+
if (args.name === "localhost") {
|
|
288
|
+
throw new Error("Remote can not be named 'localhost'");
|
|
227
289
|
}
|
|
290
|
+
const api = await client(args.password, args.address);
|
|
291
|
+
try {
|
|
292
|
+
await api.program.list();
|
|
293
|
+
} catch (error) {
|
|
294
|
+
throw new Error("Failed to add remote: " + error?.toString());
|
|
295
|
+
}
|
|
296
|
+
if (!fs.existsSync(args.directory)) {
|
|
297
|
+
fs.mkdirSync(args.directory, { recursive: true });
|
|
298
|
+
}
|
|
299
|
+
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
300
|
+
remotes.add(args.name, args.address, args.password);
|
|
228
301
|
},
|
|
229
302
|
})
|
|
230
303
|
.command({
|
|
231
|
-
command: "
|
|
232
|
-
describe: "
|
|
233
|
-
builder: (yargs:
|
|
234
|
-
yargs
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
304
|
+
command: "remove <name>",
|
|
305
|
+
describe: "Remove a remote",
|
|
306
|
+
builder: (yargs: yargs.Argv) => {
|
|
307
|
+
yargs
|
|
308
|
+
|
|
309
|
+
.positional("name", {
|
|
310
|
+
type: "string",
|
|
311
|
+
describe: "Remote address",
|
|
312
|
+
demandOption: true,
|
|
313
|
+
})
|
|
314
|
+
.option("directory", {
|
|
315
|
+
describe: "Peerbit directory",
|
|
316
|
+
defaultDescription: "~.peerbit",
|
|
317
|
+
type: "string",
|
|
318
|
+
alias: "d",
|
|
319
|
+
default: getHomeConfigDir(),
|
|
320
|
+
});
|
|
321
|
+
|
|
239
322
|
return yargs;
|
|
240
323
|
},
|
|
241
|
-
|
|
242
324
|
handler: async (args) => {
|
|
243
|
-
const
|
|
244
|
-
|
|
325
|
+
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
326
|
+
if (remotes.remove(args.name)) {
|
|
327
|
+
console.log(
|
|
328
|
+
chalk.green("Removed remote with name: " + args.name)
|
|
329
|
+
);
|
|
330
|
+
} else {
|
|
331
|
+
console.log(
|
|
332
|
+
chalk.red("Did not find any remote with name: " + args.name)
|
|
333
|
+
);
|
|
334
|
+
}
|
|
245
335
|
},
|
|
246
336
|
})
|
|
247
337
|
.command({
|
|
248
|
-
command: "
|
|
249
|
-
describe: "
|
|
250
|
-
builder: (yargs:
|
|
251
|
-
yargs
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
338
|
+
command: "connect [name...]",
|
|
339
|
+
describe: "Connect to remote(s)",
|
|
340
|
+
builder: (yargs: yargs.Argv) => {
|
|
341
|
+
yargs
|
|
342
|
+
.positional("name", {
|
|
343
|
+
type: "string",
|
|
344
|
+
describe: "Remote name",
|
|
345
|
+
default: "localhost",
|
|
346
|
+
demandOption: false,
|
|
347
|
+
array: true,
|
|
348
|
+
})
|
|
349
|
+
.option("directory", {
|
|
350
|
+
describe: "Peerbit directory",
|
|
351
|
+
defaultDescription: "~.peerbit",
|
|
352
|
+
type: "string",
|
|
353
|
+
alias: "d",
|
|
354
|
+
default: getHomeConfigDir(),
|
|
355
|
+
});
|
|
256
356
|
return yargs;
|
|
257
357
|
},
|
|
358
|
+
handler: async (connectArgs) => {
|
|
359
|
+
const names = connectArgs.name;
|
|
360
|
+
const apis: {
|
|
361
|
+
log: (string: string) => void;
|
|
362
|
+
name: string;
|
|
363
|
+
api: Awaited<ReturnType<typeof client>>;
|
|
364
|
+
}[] = [];
|
|
365
|
+
console.log(getRemotesPath(connectArgs.directory));
|
|
366
|
+
if (names.length > 0) {
|
|
367
|
+
const remotes = new Remotes(
|
|
368
|
+
getRemotesPath(connectArgs.directory)
|
|
369
|
+
);
|
|
370
|
+
for (const name of names) {
|
|
371
|
+
if (name === "localhost") {
|
|
372
|
+
const config = await import("./config.js");
|
|
373
|
+
const adminPassword = await config.loadPassword(
|
|
374
|
+
config.getServerConfigPath(connectArgs.directory)
|
|
375
|
+
);
|
|
376
|
+
apis.push({
|
|
377
|
+
log: (string) => console.log("localhost: " + string),
|
|
378
|
+
name: "localhost",
|
|
379
|
+
api: await client(adminPassword),
|
|
380
|
+
});
|
|
381
|
+
} else {
|
|
382
|
+
const remote = remotes.getByName(name);
|
|
383
|
+
if (!remote) {
|
|
384
|
+
throw new Error("Missing remote with name: " + name);
|
|
385
|
+
}
|
|
386
|
+
let logFn: (name: string) => void;
|
|
387
|
+
if (names.length > 0) {
|
|
388
|
+
logFn = (string) => console.log(name + ": " + string);
|
|
389
|
+
} else {
|
|
390
|
+
logFn = (string) => console.log(string);
|
|
391
|
+
}
|
|
392
|
+
apis.push({
|
|
393
|
+
log: logFn,
|
|
394
|
+
name,
|
|
395
|
+
api: await client(remote.password, remote.address),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
258
400
|
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
|
|
401
|
+
// try if authenticated
|
|
402
|
+
for (const api of apis) {
|
|
403
|
+
try {
|
|
404
|
+
await api.api.program.list();
|
|
405
|
+
} catch (error) {
|
|
406
|
+
throw new Error(
|
|
407
|
+
`Failed to connect to '${api.name}': ${error?.toString()}`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const capi = () =>
|
|
412
|
+
yargs
|
|
413
|
+
.default()
|
|
414
|
+
.command("peer", "Peer info", (yargs) => {
|
|
415
|
+
yargs
|
|
416
|
+
.command({
|
|
417
|
+
command: "id",
|
|
418
|
+
describe: "Get peer id",
|
|
419
|
+
handler: async (args) => {
|
|
420
|
+
for (const api of apis) {
|
|
421
|
+
api.log((await api.api.peer.id.get()).toString());
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
})
|
|
425
|
+
.command({
|
|
426
|
+
command: "address",
|
|
427
|
+
describe: "Get addresses",
|
|
428
|
+
handler: async (args) => {
|
|
429
|
+
for (const api of apis) {
|
|
430
|
+
(await api.api.peer.addresses.get()).forEach((x) =>
|
|
431
|
+
api.log(x.toString())
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
})
|
|
436
|
+
.strict()
|
|
437
|
+
.demandCommand();
|
|
438
|
+
return yargs;
|
|
439
|
+
})
|
|
440
|
+
.command("network", "Manage network", (yargs) => {
|
|
441
|
+
yargs
|
|
442
|
+
.command({
|
|
443
|
+
command: "bootstrap",
|
|
444
|
+
describe: "Connect to bootstrap nodes",
|
|
445
|
+
handler: async () => {
|
|
446
|
+
for (const api of apis) {
|
|
447
|
+
await api.api.network.bootstrap();
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
})
|
|
451
|
+
.strict()
|
|
452
|
+
.demandCommand();
|
|
453
|
+
})
|
|
271
454
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
455
|
+
.command(
|
|
456
|
+
"topic",
|
|
457
|
+
"Manage topics the node is listening to",
|
|
458
|
+
(yargs) => {
|
|
459
|
+
yargs
|
|
460
|
+
.command({
|
|
461
|
+
command: "list",
|
|
462
|
+
aliases: "ls",
|
|
463
|
+
describe: "List all topics",
|
|
464
|
+
builder: (yargs: any) => {
|
|
465
|
+
yargs.option("replicate", {
|
|
466
|
+
type: "boolean",
|
|
467
|
+
describe: "Replicate data on this topic",
|
|
468
|
+
aliases: "r",
|
|
469
|
+
default: false,
|
|
470
|
+
});
|
|
471
|
+
return yargs;
|
|
472
|
+
},
|
|
473
|
+
handler: async (args) => {
|
|
474
|
+
/* const c = await client();
|
|
475
|
+
const topics = await c.topics.get(args.replicate);
|
|
476
|
+
if (topics?.length > 0) {
|
|
477
|
+
console.log("Topic (" + topics.length + "):");
|
|
478
|
+
for (const t of topics) {
|
|
479
|
+
console.log(t);
|
|
480
|
+
}
|
|
481
|
+
} else {
|
|
482
|
+
console.log("Not subscribed to any topics");
|
|
483
|
+
} */
|
|
484
|
+
console.error("Not implemented");
|
|
485
|
+
},
|
|
486
|
+
})
|
|
487
|
+
.strict()
|
|
488
|
+
.demandCommand();
|
|
489
|
+
return yargs;
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
.command("program", "Manage programs", (yargs) => {
|
|
493
|
+
yargs
|
|
494
|
+
.command({
|
|
495
|
+
command: "status <address>",
|
|
496
|
+
describe: "Is a program open",
|
|
497
|
+
builder: (yargs: any) => {
|
|
498
|
+
yargs.positional("address", {
|
|
499
|
+
type: "string",
|
|
500
|
+
describe: "Program address",
|
|
501
|
+
demandOption: true,
|
|
502
|
+
});
|
|
503
|
+
return yargs;
|
|
504
|
+
},
|
|
278
505
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
506
|
+
handler: async (args) => {
|
|
507
|
+
for (const api of apis) {
|
|
508
|
+
const program = await api.api.program.has(
|
|
509
|
+
args.address
|
|
510
|
+
);
|
|
511
|
+
if (!program) {
|
|
512
|
+
api.log(chalk.red("Closed"));
|
|
513
|
+
} else {
|
|
514
|
+
api.log(chalk.green("Open"));
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
})
|
|
519
|
+
.command({
|
|
520
|
+
command: "drop <address>",
|
|
521
|
+
describe: "Drop a program",
|
|
522
|
+
builder: (yargs: any) => {
|
|
523
|
+
yargs.positional("address", {
|
|
524
|
+
type: "string",
|
|
525
|
+
describe: "Program address",
|
|
526
|
+
demandOption: true,
|
|
527
|
+
});
|
|
528
|
+
return yargs;
|
|
529
|
+
},
|
|
530
|
+
|
|
531
|
+
handler: async (args) => {
|
|
532
|
+
for (const api of apis) {
|
|
533
|
+
try {
|
|
534
|
+
await api.api.program.drop(args.address);
|
|
535
|
+
} catch (error: any) {
|
|
536
|
+
api.log(
|
|
537
|
+
chalk.red(
|
|
538
|
+
`Failed to drop ${
|
|
539
|
+
args.address
|
|
540
|
+
}: ${error.toString()}`
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
})
|
|
547
|
+
.command({
|
|
548
|
+
command: "close <address>",
|
|
549
|
+
describe: "Close a program",
|
|
550
|
+
builder: (yargs: any) => {
|
|
551
|
+
yargs.positional("address", {
|
|
552
|
+
type: "string",
|
|
553
|
+
describe: "Program address",
|
|
554
|
+
demandOption: true,
|
|
555
|
+
});
|
|
556
|
+
return yargs;
|
|
557
|
+
},
|
|
558
|
+
|
|
559
|
+
handler: async (args) => {
|
|
560
|
+
for (const api of apis) {
|
|
561
|
+
await api.api.program.close(args.address);
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
})
|
|
565
|
+
.command({
|
|
566
|
+
command: "list",
|
|
567
|
+
describe: "List all running programs",
|
|
568
|
+
aliases: "ls",
|
|
569
|
+
handler: async (args) => {
|
|
570
|
+
for (const api of apis) {
|
|
571
|
+
const list = await api.api.program.list();
|
|
572
|
+
api.log(`Running programs (${list.length}):`);
|
|
573
|
+
list.forEach((p) => {
|
|
574
|
+
api.log(chalk.green(p));
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
})
|
|
579
|
+
|
|
580
|
+
.command({
|
|
581
|
+
command: "open [program]",
|
|
582
|
+
describe: "Open program",
|
|
583
|
+
builder: (yargs: any) => {
|
|
584
|
+
yargs.positional("program", {
|
|
585
|
+
type: "string",
|
|
586
|
+
describe: "Identifier",
|
|
587
|
+
demandOption: true,
|
|
588
|
+
});
|
|
589
|
+
yargs.option("base64", {
|
|
590
|
+
type: "string",
|
|
591
|
+
describe: "Base64 encoded serialized",
|
|
592
|
+
aliases: "b",
|
|
593
|
+
});
|
|
594
|
+
yargs.option("variant", {
|
|
595
|
+
type: "string",
|
|
596
|
+
describe: "Variant name",
|
|
597
|
+
aliases: "v",
|
|
598
|
+
});
|
|
599
|
+
return yargs;
|
|
600
|
+
},
|
|
601
|
+
handler: async (args) => {
|
|
602
|
+
if (!args.base64 && !args.variant) {
|
|
603
|
+
throw new Error(
|
|
604
|
+
"Either base64 or variant argument needs to be provided"
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
let startArg: StartProgram;
|
|
608
|
+
if (args.base64) {
|
|
609
|
+
startArg = {
|
|
610
|
+
base64: args.base64,
|
|
611
|
+
};
|
|
612
|
+
} else {
|
|
613
|
+
startArg = {
|
|
614
|
+
variant: args.variant,
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
for (const api of apis) {
|
|
618
|
+
const address = await api.api.program.open(startArg);
|
|
619
|
+
api.log("Started program with address: ");
|
|
620
|
+
api.log(chalk.green(address.toString()));
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
})
|
|
624
|
+
.strict()
|
|
625
|
+
.demandCommand();
|
|
626
|
+
return yargs;
|
|
627
|
+
})
|
|
628
|
+
.command({
|
|
629
|
+
command: "install <package-spec>",
|
|
630
|
+
describe: "install and import a dependency",
|
|
631
|
+
builder: (yargs: any) => {
|
|
632
|
+
yargs.positional("package-spec", {
|
|
633
|
+
type: "string",
|
|
634
|
+
describe:
|
|
635
|
+
"Installed dependency will be loaded with js import(...)",
|
|
636
|
+
demandOption: true,
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
return yargs;
|
|
640
|
+
},
|
|
641
|
+
handler: async (args) => {
|
|
642
|
+
// if ends with .tgz assume it is a file
|
|
643
|
+
|
|
644
|
+
let installCommand: InstallDependency;
|
|
645
|
+
const packageName: string = args["package-spec"];
|
|
646
|
+
if (packageName.endsWith(".tgz")) {
|
|
647
|
+
const packagePath = path.isAbsolute(packageName)
|
|
648
|
+
? packageName
|
|
649
|
+
: path.join(process.cwd(), packageName);
|
|
650
|
+
|
|
651
|
+
const buffer = fs.readFileSync(packagePath);
|
|
652
|
+
const base64 = toBase64(buffer);
|
|
653
|
+
installCommand = {
|
|
654
|
+
type: "tgz",
|
|
655
|
+
name: await getPackageName(packageName),
|
|
656
|
+
base64,
|
|
657
|
+
};
|
|
658
|
+
} else {
|
|
659
|
+
installCommand = { type: "npm", name: packageName };
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
for (const api of apis) {
|
|
663
|
+
const newPrograms = await api.api.dependency.install(
|
|
664
|
+
installCommand
|
|
665
|
+
);
|
|
666
|
+
api.log(
|
|
667
|
+
`New programs available (${newPrograms.length}):`
|
|
668
|
+
);
|
|
669
|
+
newPrograms.forEach((p) => {
|
|
670
|
+
api.log(chalk.green(p));
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
})
|
|
675
|
+
.command({
|
|
676
|
+
command: "restart",
|
|
677
|
+
describe: "Restart the server",
|
|
678
|
+
handler: async () => {
|
|
679
|
+
for (const api of apis) {
|
|
680
|
+
await api.api.restart();
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
})
|
|
684
|
+
.command({
|
|
685
|
+
command: "terminate",
|
|
686
|
+
describe: "Terminate the server",
|
|
687
|
+
handler: async () => {
|
|
688
|
+
for (const api of apis) {
|
|
689
|
+
await api.api.terminate();
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
})
|
|
693
|
+
.help()
|
|
694
|
+
.strict()
|
|
695
|
+
.scriptName("")
|
|
696
|
+
.demandCommand()
|
|
697
|
+
.showHelpOnFail(true)
|
|
698
|
+
.exitProcess(false);
|
|
699
|
+
const rl = readline.createInterface({
|
|
700
|
+
input: process.stdin,
|
|
701
|
+
output: process.stdout,
|
|
702
|
+
terminal: true,
|
|
703
|
+
historySize: 100,
|
|
292
704
|
});
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
705
|
+
console.log(chalk.green("Connected"));
|
|
706
|
+
console.log("Write 'help' to show commands.\n");
|
|
707
|
+
const first = true;
|
|
708
|
+
rl.prompt(false);
|
|
709
|
+
rl.on("line", async (cargs) => {
|
|
710
|
+
const cmds = capi();
|
|
711
|
+
try {
|
|
712
|
+
await cmds.parse(cargs);
|
|
713
|
+
} catch (error: any) {
|
|
714
|
+
/* console.log(chalk.red("Error parsing command: " + cargs))*/
|
|
715
|
+
}
|
|
716
|
+
rl.prompt(true);
|
|
297
717
|
});
|
|
298
|
-
return yargs;
|
|
299
|
-
},
|
|
300
|
-
handler: async (args) => {
|
|
301
|
-
const c = await client();
|
|
302
|
-
if (!args.base64 && !args.variant) {
|
|
303
|
-
throw new Error(
|
|
304
|
-
"Either base64 or variant argument needs to be provided"
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
let startArg: StartProgram;
|
|
308
|
-
if (args.base64) {
|
|
309
|
-
startArg = {
|
|
310
|
-
base64: args.base64,
|
|
311
|
-
};
|
|
312
|
-
} else {
|
|
313
|
-
startArg = {
|
|
314
|
-
variant: args.variant,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
const address = await c.program.open(startArg);
|
|
318
|
-
console.log("Started program with address: ");
|
|
319
|
-
console.log(chalk.green(address.toString()));
|
|
320
718
|
},
|
|
321
719
|
})
|
|
720
|
+
|
|
721
|
+
.help()
|
|
322
722
|
.strict()
|
|
323
723
|
.demandCommand();
|
|
324
|
-
return
|
|
325
|
-
})
|
|
326
|
-
.command({
|
|
327
|
-
command: "install <package-spec>",
|
|
328
|
-
describe: "install and import a dependency",
|
|
329
|
-
builder: (yargs: any) => {
|
|
330
|
-
yargs.positional("package-spec", {
|
|
331
|
-
type: "string",
|
|
332
|
-
describe: "Installed dependency will be loaded with js import(...)",
|
|
333
|
-
demandOption: true,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
return yargs;
|
|
337
|
-
},
|
|
338
|
-
handler: async (args) => {
|
|
339
|
-
const c = await client();
|
|
340
|
-
const newPrograms = await c.dependency.install(args["package-spec"]);
|
|
341
|
-
|
|
342
|
-
console.log(`New programs available (${newPrograms.length}):`);
|
|
343
|
-
newPrograms.forEach((p) => {
|
|
344
|
-
console.log(chalk.green(p));
|
|
345
|
-
});
|
|
346
|
-
},
|
|
724
|
+
return innerYargs;
|
|
347
725
|
})
|
|
348
726
|
.help()
|
|
349
727
|
.strict()
|