@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 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 peerbit = await Peerbit.create();
32
- const files = await peerbit.open(new Files({ id: ID }));
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(args)
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("relay", {
168
+ yargs.option("peer", {
169
+ alias: ["bootstrap", "relay"],
46
170
  type: "string",
47
- describe: "Relay address",
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
- if (args.relay) {
55
- await Promise.all(coerceAddresses(args.relay).map((x) => peerbit.dial(x)));
56
- }
57
- else {
58
- await peerbit.bootstrap();
59
- }
60
- const file = fs.readFileSync(args.path);
61
- const id = await files.add(path.basename(args.path), file);
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("relay", {
208
+ yargs.option("peer", {
209
+ alias: ["bootstrap", "relay"],
86
210
  type: "string",
87
- describe: "Relay address",
88
- defaultDescription: "Bootstrap addresses for testing purposes",
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
- if (args.relay) {
95
- await Promise.all(coerceAddresses(args.relay).map((x) => peerbit.dial(x)));
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
- else {
98
- await peerbit.bootstrap();
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("ERROR: File not found!"));
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
- fs.writeFileSync(outPath, file.bytes);
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.stop();
255
+ await stopPeerbitForCli(peerbit);
119
256
  },
120
257
  })
121
258
  .help()
122
259
  .strict()
123
- .demandCommand().argv;
260
+ .demandCommand()
261
+ .parseAsync();
124
262
  };
125
- cli();
263
+ await cli();
126
264
  //# sourceMappingURL=bin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":"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"}
@@ -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.1",
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": "^2.3.2",
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": "^4",
37
+ "peerbit": "^5.2.0",
38
38
  "yargs": "^17.7.2",
39
- "@peerbit/please-lib": "2.0.1"
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 peerbit = await Peerbit.create();
39
- const files = await peerbit.open(new Files({ id: ID }));
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(args)
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("relay", {
207
+ yargs.option("peer", {
208
+ alias: ["bootstrap", "relay"],
54
209
  type: "string",
55
- describe: "Relay address",
56
- defaultDescription: "?",
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
- if (args.relay) {
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 file = fs.readFileSync(args.path) as Uint8Array;
72
- const id = await files.add(path.basename(args.path), file);
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("relay", {
254
+ yargs.option("peer", {
255
+ alias: ["bootstrap", "relay"],
101
256
  type: "string",
102
- describe: "Relay address",
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
- "Bootstrap addresses for testing purposes",
260
+ "Peerbit bootstrap addresses",
105
261
  default: undefined,
106
262
  });
107
263
  return yargs;
108
264
  },
109
265
 
110
266
  handler: async (args) => {
111
- if (args.relay) {
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
- // wait for at least 1 replicator
122
- await waitFor(async () => (await files.getReady()).size >= 1);
123
-
124
- const file = await files.getById(args.id.trim());
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(chalk.red("ERROR: File not found!"));
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
- fs.writeFileSync(outPath, file.bytes);
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.stop();
324
+ await stopPeerbitForCli(peerbit);
150
325
  },
151
326
  })
152
327
  .help()
153
328
  .strict()
154
- .demandCommand().argv;
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
+ };