@peerbit/please 2.0.1 → 2.0.2
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/bin.js +171 -33
- package/lib/esm/bin.js.map +1 -1
- package/lib/esm/io.d.ts +7 -0
- package/lib/esm/io.js +40 -0
- package/lib/esm/io.js.map +1 -0
- package/package.json +4 -4
- package/src/bin.ts +214 -38
- package/src/io.ts +50 -0
package/lib/esm/bin.js
CHANGED
|
@@ -4,9 +4,11 @@ import { Peerbit } from "peerbit";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import * as yargs from "yargs";
|
|
6
6
|
import chalk from "chalk";
|
|
7
|
-
import { waitFor } from "@peerbit/time";
|
|
7
|
+
import { TimeoutError, waitFor } from "@peerbit/time";
|
|
8
8
|
import path from "path";
|
|
9
|
+
import os from "os";
|
|
9
10
|
import { multiaddr } from "@multiformats/multiaddr";
|
|
11
|
+
import { createPathSource, createPathWriter } from "./io.js";
|
|
10
12
|
function ensureDirectoryExistence(filePath) {
|
|
11
13
|
const dirname = path.dirname(filePath);
|
|
12
14
|
if (fs.existsSync(dirname)) {
|
|
@@ -18,6 +20,110 @@ function ensureDirectoryExistence(filePath) {
|
|
|
18
20
|
const coerceAddresses = (addrs) => {
|
|
19
21
|
return (Array.isArray(addrs) ? addrs : [addrs]).map((x) => multiaddr(x));
|
|
20
22
|
};
|
|
23
|
+
const connectToNetwork = async (peerbit, peer) => {
|
|
24
|
+
if (peer) {
|
|
25
|
+
await peerbit.dial(coerceAddresses(peer));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await peerbit.bootstrap();
|
|
29
|
+
};
|
|
30
|
+
const FILE_LOOKUP_TIMEOUT_MS = 2 * 60 * 1000;
|
|
31
|
+
const FILE_LOOKUP_ATTEMPT_TIMEOUT_MS = 2 * 1000;
|
|
32
|
+
const FILE_LOOKUP_POLL_INTERVAL_MS = 1 * 1000;
|
|
33
|
+
const DEFAULT_DIRECTORY_NAME = "peerbit-file-share";
|
|
34
|
+
const CLI_REPLICATION_ARGS = {
|
|
35
|
+
replicate: {
|
|
36
|
+
limits: {
|
|
37
|
+
cpu: {
|
|
38
|
+
max: 1,
|
|
39
|
+
monitor: undefined,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const getDirectoryArg = (args) => {
|
|
45
|
+
for (let i = 0; i < args.length; i++) {
|
|
46
|
+
const arg = args[i];
|
|
47
|
+
if (arg === "--directory" || arg === "--dir") {
|
|
48
|
+
return args[i + 1];
|
|
49
|
+
}
|
|
50
|
+
if (arg.startsWith("--directory=")) {
|
|
51
|
+
return arg.slice("--directory=".length);
|
|
52
|
+
}
|
|
53
|
+
if (arg.startsWith("--dir=")) {
|
|
54
|
+
return arg.slice("--dir=".length);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
};
|
|
59
|
+
const stripDirectoryArgs = (args) => {
|
|
60
|
+
const nextArgs = [];
|
|
61
|
+
for (let i = 0; i < args.length; i++) {
|
|
62
|
+
const arg = args[i];
|
|
63
|
+
if (arg === "--directory" || arg === "--dir") {
|
|
64
|
+
i++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (arg.startsWith("--directory=") ||
|
|
68
|
+
arg.startsWith("--dir=")) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
nextArgs.push(arg);
|
|
72
|
+
}
|
|
73
|
+
return nextArgs;
|
|
74
|
+
};
|
|
75
|
+
const resolveDirectory = (directoryArg) => {
|
|
76
|
+
if (directoryArg === undefined) {
|
|
77
|
+
const directory = path.join(os.homedir(), DEFAULT_DIRECTORY_NAME);
|
|
78
|
+
if (!fs.existsSync(directory)) {
|
|
79
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
return directory;
|
|
82
|
+
}
|
|
83
|
+
if (directoryArg === "" || directoryArg === "null") {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (!fs.existsSync(directoryArg)) {
|
|
87
|
+
fs.mkdirSync(directoryArg, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
return directoryArg;
|
|
90
|
+
};
|
|
91
|
+
const waitForTermination = async (stop) => {
|
|
92
|
+
await new Promise((resolve, reject) => {
|
|
93
|
+
let settled = false;
|
|
94
|
+
const keepAlive = setInterval(() => { }, 1 << 30);
|
|
95
|
+
const finish = async () => {
|
|
96
|
+
if (settled) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
settled = true;
|
|
100
|
+
clearInterval(keepAlive);
|
|
101
|
+
try {
|
|
102
|
+
await stop();
|
|
103
|
+
resolve();
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
reject(error);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
process.once("SIGINT", finish);
|
|
110
|
+
process.once("SIGTERM", finish);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const stopPeerbitForCli = async (peerbit, options) => {
|
|
114
|
+
const timeoutMs = options?.timeoutMs ?? 10_000;
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
console.warn(chalk.yellow(`Peer shutdown exceeded ${Math.round(timeoutMs / 1000)} seconds, forcing CLI exit.`));
|
|
117
|
+
process.exit(process.exitCode ?? 0);
|
|
118
|
+
}, timeoutMs);
|
|
119
|
+
timer.unref?.();
|
|
120
|
+
try {
|
|
121
|
+
await peerbit.stop();
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
21
127
|
// A random ID, but unique for this app
|
|
22
128
|
const ID = new Uint8Array([
|
|
23
129
|
30, 221, 227, 76, 164, 10, 61, 8, 21, 176, 122, 5, 79, 110, 115, 255, 233,
|
|
@@ -28,11 +134,28 @@ const cli = async (args) => {
|
|
|
28
134
|
const { hideBin } = await import("yargs/helpers");
|
|
29
135
|
args = hideBin(process.argv);
|
|
30
136
|
}
|
|
31
|
-
const
|
|
32
|
-
const
|
|
137
|
+
const directory = resolveDirectory(getDirectoryArg(args));
|
|
138
|
+
const parsedArgs = stripDirectoryArgs(args);
|
|
139
|
+
console.log("Starting file-share CLI" +
|
|
140
|
+
(directory ? ` in directory ${directory}` : ""));
|
|
141
|
+
const peerbit = await Peerbit.create({ directory });
|
|
142
|
+
let files;
|
|
143
|
+
const openFiles = async (programArgs = CLI_REPLICATION_ARGS) => {
|
|
144
|
+
if (!files) {
|
|
145
|
+
files = await peerbit.open(new Files({ id: ID }), {
|
|
146
|
+
args: programArgs,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return files;
|
|
150
|
+
};
|
|
33
151
|
// TODO fix types
|
|
34
152
|
return yargs
|
|
35
|
-
.default(
|
|
153
|
+
.default(parsedArgs)
|
|
154
|
+
.option("directory", {
|
|
155
|
+
alias: "dir",
|
|
156
|
+
type: "string",
|
|
157
|
+
describe: "Peerbit persistence directory. Defaults to ~/peerbit-file-share. Pass --directory=null for ephemeral mode.",
|
|
158
|
+
})
|
|
36
159
|
.command({
|
|
37
160
|
command: "put <path>",
|
|
38
161
|
describe: "Put file",
|
|
@@ -42,24 +165,24 @@ const cli = async (args) => {
|
|
|
42
165
|
describe: "Where to save it",
|
|
43
166
|
defaultDescription: "Current directory",
|
|
44
167
|
});
|
|
45
|
-
yargs.option("
|
|
168
|
+
yargs.option("peer", {
|
|
169
|
+
alias: ["bootstrap", "relay"],
|
|
46
170
|
type: "string",
|
|
47
|
-
describe: "
|
|
48
|
-
defaultDescription: "
|
|
171
|
+
describe: "Peer address to dial. Shard roots are discovered automatically after connecting. --bootstrap and --relay remain accepted as aliases.",
|
|
172
|
+
defaultDescription: "Peerbit bootstrap addresses",
|
|
49
173
|
default: undefined,
|
|
50
174
|
});
|
|
51
175
|
return yargs;
|
|
52
176
|
},
|
|
53
177
|
handler: async (args) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
console.log(`Id: ${chalk.green(id)}\n\nFile can now be fetched with:\n\nplease get ${id}`);
|
|
178
|
+
await connectToNetwork(peerbit, args.peer);
|
|
179
|
+
const files = await openFiles();
|
|
180
|
+
const source = await createPathSource(args.path);
|
|
181
|
+
const id = await files.addSource(path.basename(args.path), source);
|
|
182
|
+
console.log(`Id: ${chalk.green(id)}\n\nFile can now be fetched with:\n\nplease get ${id}\n\nThis process will keep seeding until you stop it.`);
|
|
183
|
+
await waitForTermination(async () => {
|
|
184
|
+
await stopPeerbitForCli(peerbit);
|
|
185
|
+
});
|
|
63
186
|
},
|
|
64
187
|
})
|
|
65
188
|
.command({
|
|
@@ -82,45 +205,60 @@ const cli = async (args) => {
|
|
|
82
205
|
type: "boolean",
|
|
83
206
|
default: false,
|
|
84
207
|
});
|
|
85
|
-
yargs.option("
|
|
208
|
+
yargs.option("peer", {
|
|
209
|
+
alias: ["bootstrap", "relay"],
|
|
86
210
|
type: "string",
|
|
87
|
-
describe: "
|
|
88
|
-
defaultDescription: "
|
|
211
|
+
describe: "Peer address to dial. Shard roots are discovered automatically after connecting. --bootstrap and --relay remain accepted as aliases.",
|
|
212
|
+
defaultDescription: "Peerbit bootstrap addresses",
|
|
89
213
|
default: undefined,
|
|
90
214
|
});
|
|
91
215
|
return yargs;
|
|
92
216
|
},
|
|
93
217
|
handler: async (args) => {
|
|
94
|
-
|
|
95
|
-
|
|
218
|
+
await connectToNetwork(peerbit, args.peer);
|
|
219
|
+
const files = await openFiles({ replicate: false });
|
|
220
|
+
console.log("Fetching file with id: " + args.id);
|
|
221
|
+
let file;
|
|
222
|
+
try {
|
|
223
|
+
file = await waitFor(() => files.resolveById(args.id.trim(), {
|
|
224
|
+
replicate: true,
|
|
225
|
+
timeout: FILE_LOOKUP_ATTEMPT_TIMEOUT_MS,
|
|
226
|
+
}), {
|
|
227
|
+
timeout: FILE_LOOKUP_TIMEOUT_MS,
|
|
228
|
+
delayInterval: FILE_LOOKUP_POLL_INTERVAL_MS,
|
|
229
|
+
timeoutMessage: "waiting for the requested file to become discoverable",
|
|
230
|
+
});
|
|
96
231
|
}
|
|
97
|
-
|
|
98
|
-
|
|
232
|
+
catch (error) {
|
|
233
|
+
if (error instanceof TimeoutError) {
|
|
234
|
+
file = undefined;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
99
239
|
}
|
|
100
|
-
console.log("Fetching file with id: " + args.id);
|
|
101
|
-
// wait for at least 1 replicator
|
|
102
|
-
await waitFor(async () => (await files.getReady()).size >= 1);
|
|
103
|
-
const file = await files.getById(args.id.trim());
|
|
104
240
|
if (!file) {
|
|
105
|
-
console.log(chalk.red(
|
|
241
|
+
console.log(chalk.red(`ERROR: File not found after waiting ${Math.round(FILE_LOOKUP_TIMEOUT_MS / 1000)} seconds! Ensure the seeder is still running and that both peers are connected to the same network. If you pass --peer, the CLI now uses Peerbit.dial(...) and discovers shard roots automatically.`));
|
|
106
242
|
}
|
|
107
243
|
else {
|
|
108
244
|
const outPath = path.join(args.path || process.cwd(), file.name);
|
|
109
|
-
if (fs.existsSync(outPath) && args.force) {
|
|
245
|
+
if (fs.existsSync(outPath) && !args.force) {
|
|
110
246
|
console.log(chalk.red(`File path ${outPath} already exist. Please remove this file or use --force argument`));
|
|
111
247
|
}
|
|
112
248
|
else {
|
|
113
249
|
ensureDirectoryExistence(outPath);
|
|
114
|
-
|
|
250
|
+
const writer = await createPathWriter(outPath);
|
|
251
|
+
await file.writeFile(files, writer);
|
|
115
252
|
console.log(chalk.greenBright("File successfully saved at path: " + outPath));
|
|
116
253
|
}
|
|
117
254
|
}
|
|
118
|
-
await peerbit
|
|
255
|
+
await stopPeerbitForCli(peerbit);
|
|
119
256
|
},
|
|
120
257
|
})
|
|
121
258
|
.help()
|
|
122
259
|
.strict()
|
|
123
|
-
.demandCommand()
|
|
260
|
+
.demandCommand()
|
|
261
|
+
.parseAsync();
|
|
124
262
|
};
|
|
125
|
-
cli();
|
|
263
|
+
await cli();
|
|
126
264
|
//# sourceMappingURL=bin.js.map
|
package/lib/esm/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":"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"}
|
package/lib/esm/io.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReReadableChunkSource } from "@peerbit/please-lib";
|
|
2
|
+
export declare const createPathSource: (filePath: string) => Promise<ReReadableChunkSource>;
|
|
3
|
+
export declare const createPathWriter: (filePath: string) => Promise<{
|
|
4
|
+
write: (chunk: Uint8Array) => Promise<void>;
|
|
5
|
+
close: () => Promise<void>;
|
|
6
|
+
abort: () => Promise<void>;
|
|
7
|
+
}>;
|
package/lib/esm/io.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { open as openFile, stat as statFile } from "node:fs/promises";
|
|
3
|
+
export const createPathSource = async (filePath) => {
|
|
4
|
+
const stats = await statFile(filePath);
|
|
5
|
+
return {
|
|
6
|
+
size: BigInt(stats.size),
|
|
7
|
+
async *readChunks(chunkSize) {
|
|
8
|
+
for await (const chunk of fs.createReadStream(filePath, {
|
|
9
|
+
highWaterMark: chunkSize,
|
|
10
|
+
})) {
|
|
11
|
+
yield chunk instanceof Uint8Array
|
|
12
|
+
? chunk
|
|
13
|
+
: new Uint8Array(chunk);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export const createPathWriter = async (filePath) => {
|
|
19
|
+
const handle = await openFile(filePath, "w");
|
|
20
|
+
let position = 0;
|
|
21
|
+
let closed = false;
|
|
22
|
+
const close = async () => {
|
|
23
|
+
if (!closed) {
|
|
24
|
+
closed = true;
|
|
25
|
+
await handle.close();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
write: async (chunk) => {
|
|
30
|
+
const buffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
31
|
+
await handle.write(buffer, 0, buffer.byteLength, position);
|
|
32
|
+
position += buffer.byteLength;
|
|
33
|
+
},
|
|
34
|
+
close,
|
|
35
|
+
abort: async () => {
|
|
36
|
+
await close();
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACjC,QAAgB,EACc,EAAE;IAChC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO;QACH,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QACxB,KAAK,CAAC,CAAC,UAAU,CAAC,SAAiB;YAC/B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE;gBACpD,aAAa,EAAE,SAAS;aAC3B,CAAC,EAAE,CAAC;gBACD,MAAM,KAAK,YAAY,UAAU;oBAC7B,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;QACL,CAAC;KACJ,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,QAAgB,EAAE,EAAE;IACvD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,GAAG,IAAI,CAAC;YACd,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACH,KAAK,EAAE,KAAK,EAAE,KAAiB,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CACtB,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,CACnB,CAAC;YACF,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC3D,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC;QAClC,CAAC;QACD,KAAK;QACL,KAAK,EAAE,KAAK,IAAI,EAAE;YACd,MAAM,KAAK,EAAE,CAAC;QAClB,CAAC;KACJ,CAAC;AACN,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/please",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"author": "dao.xyz",
|
|
5
5
|
"repository": "https://github.com/@dao-xyz/peerbit-examples",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"node": ">=16.15.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@peerbit/test-utils": "^
|
|
32
|
+
"@peerbit/test-utils": "^3.0.15",
|
|
33
33
|
"typescript": "^5.6.3"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"chalk": "^5.3.0",
|
|
37
|
-
"peerbit": "^
|
|
37
|
+
"peerbit": "^5.2.0",
|
|
38
38
|
"yargs": "^17.7.2",
|
|
39
|
-
"@peerbit/please-lib": "2.0.
|
|
39
|
+
"@peerbit/please-lib": "2.0.2"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"clean": "shx rm -rf lib/*",
|
package/src/bin.ts
CHANGED
|
@@ -6,9 +6,11 @@ import fs from "fs";
|
|
|
6
6
|
import * as yargs from "yargs";
|
|
7
7
|
import { Argv } from "yargs";
|
|
8
8
|
import chalk from "chalk";
|
|
9
|
-
import { waitFor } from "@peerbit/time";
|
|
9
|
+
import { TimeoutError, waitFor } from "@peerbit/time";
|
|
10
10
|
import path from "path";
|
|
11
|
+
import os from "os";
|
|
11
12
|
import { multiaddr } from "@multiformats/multiaddr";
|
|
13
|
+
import { createPathSource, createPathWriter } from "./io.js";
|
|
12
14
|
|
|
13
15
|
function ensureDirectoryExistence(filePath) {
|
|
14
16
|
const dirname = path.dirname(filePath);
|
|
@@ -23,6 +25,131 @@ const coerceAddresses = (addrs: string | string[]) => {
|
|
|
23
25
|
return (Array.isArray(addrs) ? addrs : [addrs]).map((x) => multiaddr(x));
|
|
24
26
|
};
|
|
25
27
|
|
|
28
|
+
const connectToNetwork = async (
|
|
29
|
+
peerbit: Peerbit,
|
|
30
|
+
peer?: string | string[]
|
|
31
|
+
) => {
|
|
32
|
+
if (peer) {
|
|
33
|
+
await peerbit.dial(coerceAddresses(peer));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await peerbit.bootstrap();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const FILE_LOOKUP_TIMEOUT_MS = 2 * 60 * 1000;
|
|
40
|
+
const FILE_LOOKUP_ATTEMPT_TIMEOUT_MS = 2 * 1000;
|
|
41
|
+
const FILE_LOOKUP_POLL_INTERVAL_MS = 1 * 1000;
|
|
42
|
+
const DEFAULT_DIRECTORY_NAME = "peerbit-file-share";
|
|
43
|
+
const CLI_REPLICATION_ARGS = {
|
|
44
|
+
replicate: {
|
|
45
|
+
limits: {
|
|
46
|
+
cpu: {
|
|
47
|
+
max: 1,
|
|
48
|
+
monitor: undefined,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
const getDirectoryArg = (args: string[]) => {
|
|
55
|
+
for (let i = 0; i < args.length; i++) {
|
|
56
|
+
const arg = args[i];
|
|
57
|
+
if (arg === "--directory" || arg === "--dir") {
|
|
58
|
+
return args[i + 1];
|
|
59
|
+
}
|
|
60
|
+
if (arg.startsWith("--directory=")) {
|
|
61
|
+
return arg.slice("--directory=".length);
|
|
62
|
+
}
|
|
63
|
+
if (arg.startsWith("--dir=")) {
|
|
64
|
+
return arg.slice("--dir=".length);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const stripDirectoryArgs = (args: string[]) => {
|
|
71
|
+
const nextArgs: string[] = [];
|
|
72
|
+
for (let i = 0; i < args.length; i++) {
|
|
73
|
+
const arg = args[i];
|
|
74
|
+
if (arg === "--directory" || arg === "--dir") {
|
|
75
|
+
i++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (
|
|
79
|
+
arg.startsWith("--directory=") ||
|
|
80
|
+
arg.startsWith("--dir=")
|
|
81
|
+
) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
nextArgs.push(arg);
|
|
85
|
+
}
|
|
86
|
+
return nextArgs;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const resolveDirectory = (directoryArg?: string) => {
|
|
90
|
+
if (directoryArg === undefined) {
|
|
91
|
+
const directory = path.join(os.homedir(), DEFAULT_DIRECTORY_NAME);
|
|
92
|
+
if (!fs.existsSync(directory)) {
|
|
93
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
return directory;
|
|
96
|
+
}
|
|
97
|
+
if (directoryArg === "" || directoryArg === "null") {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (!fs.existsSync(directoryArg)) {
|
|
101
|
+
fs.mkdirSync(directoryArg, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
return directoryArg;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const waitForTermination = async (stop: () => Promise<void>) => {
|
|
107
|
+
await new Promise<void>((resolve, reject) => {
|
|
108
|
+
let settled = false;
|
|
109
|
+
const keepAlive = setInterval(() => {}, 1 << 30);
|
|
110
|
+
const finish = async () => {
|
|
111
|
+
if (settled) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
settled = true;
|
|
115
|
+
clearInterval(keepAlive);
|
|
116
|
+
try {
|
|
117
|
+
await stop();
|
|
118
|
+
resolve();
|
|
119
|
+
} catch (error) {
|
|
120
|
+
reject(error);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
process.once("SIGINT", finish);
|
|
125
|
+
process.once("SIGTERM", finish);
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const stopPeerbitForCli = async (
|
|
130
|
+
peerbit: Peerbit,
|
|
131
|
+
options?: { timeoutMs?: number }
|
|
132
|
+
) => {
|
|
133
|
+
const timeoutMs = options?.timeoutMs ?? 10_000;
|
|
134
|
+
const timer = setTimeout(() => {
|
|
135
|
+
console.warn(
|
|
136
|
+
chalk.yellow(
|
|
137
|
+
`Peer shutdown exceeded ${Math.round(
|
|
138
|
+
timeoutMs / 1000
|
|
139
|
+
)} seconds, forcing CLI exit.`
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
process.exit(process.exitCode ?? 0);
|
|
143
|
+
}, timeoutMs);
|
|
144
|
+
timer.unref?.();
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
await peerbit.stop();
|
|
148
|
+
} finally {
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
26
153
|
// A random ID, but unique for this app
|
|
27
154
|
const ID = new Uint8Array([
|
|
28
155
|
30, 221, 227, 76, 164, 10, 61, 8, 21, 176, 122, 5, 79, 110, 115, 255, 233,
|
|
@@ -35,12 +162,39 @@ const cli = async (args?: string[]) => {
|
|
|
35
162
|
args = hideBin(process.argv);
|
|
36
163
|
}
|
|
37
164
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
165
|
+
const directory = resolveDirectory(getDirectoryArg(args));
|
|
166
|
+
const parsedArgs = stripDirectoryArgs(args);
|
|
167
|
+
console.log(
|
|
168
|
+
"Starting file-share CLI" +
|
|
169
|
+
(directory ? ` in directory ${directory}` : "")
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const peerbit = await Peerbit.create({ directory });
|
|
173
|
+
let files: Files | undefined;
|
|
174
|
+
const openFiles = async (
|
|
175
|
+
programArgs:
|
|
176
|
+
| typeof CLI_REPLICATION_ARGS
|
|
177
|
+
| {
|
|
178
|
+
replicate: false;
|
|
179
|
+
} = CLI_REPLICATION_ARGS
|
|
180
|
+
) => {
|
|
181
|
+
if (!files) {
|
|
182
|
+
files = await peerbit.open(new Files({ id: ID }), {
|
|
183
|
+
args: programArgs,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return files;
|
|
187
|
+
};
|
|
40
188
|
|
|
41
189
|
// TODO fix types
|
|
42
190
|
return yargs
|
|
43
|
-
.default(
|
|
191
|
+
.default(parsedArgs)
|
|
192
|
+
.option("directory", {
|
|
193
|
+
alias: "dir",
|
|
194
|
+
type: "string",
|
|
195
|
+
describe:
|
|
196
|
+
"Peerbit persistence directory. Defaults to ~/peerbit-file-share. Pass --directory=null for ephemeral mode.",
|
|
197
|
+
})
|
|
44
198
|
.command<any>({
|
|
45
199
|
command: "put <path>",
|
|
46
200
|
describe: "Put file",
|
|
@@ -50,31 +204,31 @@ const cli = async (args?: string[]) => {
|
|
|
50
204
|
describe: "Where to save it",
|
|
51
205
|
defaultDescription: "Current directory",
|
|
52
206
|
});
|
|
53
|
-
yargs.option("
|
|
207
|
+
yargs.option("peer", {
|
|
208
|
+
alias: ["bootstrap", "relay"],
|
|
54
209
|
type: "string",
|
|
55
|
-
describe:
|
|
56
|
-
|
|
210
|
+
describe:
|
|
211
|
+
"Peer address to dial. Shard roots are discovered automatically after connecting. --bootstrap and --relay remain accepted as aliases.",
|
|
212
|
+
defaultDescription: "Peerbit bootstrap addresses",
|
|
57
213
|
default: undefined,
|
|
58
214
|
});
|
|
59
215
|
return yargs;
|
|
60
216
|
},
|
|
61
217
|
|
|
62
218
|
handler: async (args) => {
|
|
63
|
-
|
|
64
|
-
await Promise.all(
|
|
65
|
-
coerceAddresses(args.relay).map((x) => peerbit.dial(x))
|
|
66
|
-
);
|
|
67
|
-
} else {
|
|
68
|
-
await peerbit.bootstrap();
|
|
69
|
-
}
|
|
219
|
+
await connectToNetwork(peerbit, args.peer);
|
|
70
220
|
|
|
71
|
-
const
|
|
72
|
-
const
|
|
221
|
+
const files = await openFiles();
|
|
222
|
+
const source = await createPathSource(args.path);
|
|
223
|
+
const id = await files.addSource(path.basename(args.path), source);
|
|
73
224
|
console.log(
|
|
74
225
|
`Id: ${chalk.green(
|
|
75
226
|
id
|
|
76
|
-
)}\n\nFile can now be fetched with:\n\nplease get ${id}
|
|
227
|
+
)}\n\nFile can now be fetched with:\n\nplease get ${id}\n\nThis process will keep seeding until you stop it.`
|
|
77
228
|
);
|
|
229
|
+
await waitForTermination(async () => {
|
|
230
|
+
await stopPeerbitForCli(peerbit);
|
|
231
|
+
});
|
|
78
232
|
},
|
|
79
233
|
})
|
|
80
234
|
.command<any>({
|
|
@@ -97,40 +251,60 @@ const cli = async (args?: string[]) => {
|
|
|
97
251
|
type: "boolean",
|
|
98
252
|
default: false,
|
|
99
253
|
});
|
|
100
|
-
yargs.option("
|
|
254
|
+
yargs.option("peer", {
|
|
255
|
+
alias: ["bootstrap", "relay"],
|
|
101
256
|
type: "string",
|
|
102
|
-
describe:
|
|
257
|
+
describe:
|
|
258
|
+
"Peer address to dial. Shard roots are discovered automatically after connecting. --bootstrap and --relay remain accepted as aliases.",
|
|
103
259
|
defaultDescription:
|
|
104
|
-
"
|
|
260
|
+
"Peerbit bootstrap addresses",
|
|
105
261
|
default: undefined,
|
|
106
262
|
});
|
|
107
263
|
return yargs;
|
|
108
264
|
},
|
|
109
265
|
|
|
110
266
|
handler: async (args) => {
|
|
111
|
-
|
|
112
|
-
await Promise.all(
|
|
113
|
-
coerceAddresses(args.relay).map((x) => peerbit.dial(x))
|
|
114
|
-
);
|
|
115
|
-
} else {
|
|
116
|
-
await peerbit.bootstrap();
|
|
117
|
-
}
|
|
267
|
+
await connectToNetwork(peerbit, args.peer);
|
|
118
268
|
|
|
269
|
+
const files = await openFiles({ replicate: false });
|
|
119
270
|
console.log("Fetching file with id: " + args.id);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
271
|
+
let file;
|
|
272
|
+
try {
|
|
273
|
+
file = await waitFor(
|
|
274
|
+
() =>
|
|
275
|
+
files.resolveById(args.id.trim(), {
|
|
276
|
+
replicate: true,
|
|
277
|
+
timeout: FILE_LOOKUP_ATTEMPT_TIMEOUT_MS,
|
|
278
|
+
}),
|
|
279
|
+
{
|
|
280
|
+
timeout: FILE_LOOKUP_TIMEOUT_MS,
|
|
281
|
+
delayInterval: FILE_LOOKUP_POLL_INTERVAL_MS,
|
|
282
|
+
timeoutMessage:
|
|
283
|
+
"waiting for the requested file to become discoverable",
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (error instanceof TimeoutError) {
|
|
288
|
+
file = undefined;
|
|
289
|
+
} else {
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
125
293
|
|
|
126
294
|
if (!file) {
|
|
127
|
-
console.log(
|
|
295
|
+
console.log(
|
|
296
|
+
chalk.red(
|
|
297
|
+
`ERROR: File not found after waiting ${Math.round(
|
|
298
|
+
FILE_LOOKUP_TIMEOUT_MS / 1000
|
|
299
|
+
)} seconds! Ensure the seeder is still running and that both peers are connected to the same network. If you pass --peer, the CLI now uses Peerbit.dial(...) and discovers shard roots automatically.`
|
|
300
|
+
)
|
|
301
|
+
);
|
|
128
302
|
} else {
|
|
129
303
|
const outPath = path.join(
|
|
130
304
|
args.path || process.cwd(),
|
|
131
305
|
file.name
|
|
132
306
|
);
|
|
133
|
-
if (fs.existsSync(outPath) && args.force) {
|
|
307
|
+
if (fs.existsSync(outPath) && !args.force) {
|
|
134
308
|
console.log(
|
|
135
309
|
chalk.red(
|
|
136
310
|
`File path ${outPath} already exist. Please remove this file or use --force argument`
|
|
@@ -138,7 +312,8 @@ const cli = async (args?: string[]) => {
|
|
|
138
312
|
);
|
|
139
313
|
} else {
|
|
140
314
|
ensureDirectoryExistence(outPath);
|
|
141
|
-
|
|
315
|
+
const writer = await createPathWriter(outPath);
|
|
316
|
+
await file.writeFile(files, writer);
|
|
142
317
|
console.log(
|
|
143
318
|
chalk.greenBright(
|
|
144
319
|
"File successfully saved at path: " + outPath
|
|
@@ -146,12 +321,13 @@ const cli = async (args?: string[]) => {
|
|
|
146
321
|
);
|
|
147
322
|
}
|
|
148
323
|
}
|
|
149
|
-
await peerbit
|
|
324
|
+
await stopPeerbitForCli(peerbit);
|
|
150
325
|
},
|
|
151
326
|
})
|
|
152
327
|
.help()
|
|
153
328
|
.strict()
|
|
154
|
-
.demandCommand()
|
|
329
|
+
.demandCommand()
|
|
330
|
+
.parseAsync();
|
|
155
331
|
};
|
|
156
332
|
|
|
157
|
-
cli();
|
|
333
|
+
await cli();
|
package/src/io.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { open as openFile, stat as statFile } from "node:fs/promises";
|
|
3
|
+
import type { ReReadableChunkSource } from "@peerbit/please-lib";
|
|
4
|
+
|
|
5
|
+
export const createPathSource = async (
|
|
6
|
+
filePath: string
|
|
7
|
+
): Promise<ReReadableChunkSource> => {
|
|
8
|
+
const stats = await statFile(filePath);
|
|
9
|
+
return {
|
|
10
|
+
size: BigInt(stats.size),
|
|
11
|
+
async *readChunks(chunkSize: number) {
|
|
12
|
+
for await (const chunk of fs.createReadStream(filePath, {
|
|
13
|
+
highWaterMark: chunkSize,
|
|
14
|
+
})) {
|
|
15
|
+
yield chunk instanceof Uint8Array
|
|
16
|
+
? chunk
|
|
17
|
+
: new Uint8Array(chunk);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const createPathWriter = async (filePath: string) => {
|
|
24
|
+
const handle = await openFile(filePath, "w");
|
|
25
|
+
let position = 0;
|
|
26
|
+
let closed = false;
|
|
27
|
+
|
|
28
|
+
const close = async () => {
|
|
29
|
+
if (!closed) {
|
|
30
|
+
closed = true;
|
|
31
|
+
await handle.close();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
write: async (chunk: Uint8Array) => {
|
|
37
|
+
const buffer = Buffer.from(
|
|
38
|
+
chunk.buffer,
|
|
39
|
+
chunk.byteOffset,
|
|
40
|
+
chunk.byteLength
|
|
41
|
+
);
|
|
42
|
+
await handle.write(buffer, 0, buffer.byteLength, position);
|
|
43
|
+
position += buffer.byteLength;
|
|
44
|
+
},
|
|
45
|
+
close,
|
|
46
|
+
abort: async () => {
|
|
47
|
+
await close();
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|