@gethashd/bytecave-browser 1.0.40 → 1.0.42
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/dist/{chunk-IXGM3WHR.js → chunk-P7BUV66R.js} +63 -40
- package/dist/client.d.ts +1 -1
- package/dist/index.cjs +63 -40
- package/dist/index.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.js +1 -1
- package/dist/storage-websocket.d.ts +6 -0
- package/package.json +1 -1
- package/src/client.ts +21 -50
- package/src/react/useHashdUrl.ts +1 -1
- package/src/storage-websocket.ts +68 -2
|
@@ -6120,6 +6120,22 @@ var StorageWebSocketClient = class {
|
|
|
6120
6120
|
pending.resolve({ success: false, error: message2.error || "Storage failed" });
|
|
6121
6121
|
}
|
|
6122
6122
|
}
|
|
6123
|
+
} else if (message2.type === "retrieve-response") {
|
|
6124
|
+
const pending = this.pendingRequests.get(message2.requestId);
|
|
6125
|
+
if (pending) {
|
|
6126
|
+
clearTimeout(pending.timeout);
|
|
6127
|
+
this.pendingRequests.delete(message2.requestId);
|
|
6128
|
+
if (message2.success && message2.data) {
|
|
6129
|
+
const binaryString = atob(message2.data);
|
|
6130
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
6131
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
6132
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
6133
|
+
}
|
|
6134
|
+
pending.resolve({ success: true, data: bytes, mimeType: message2.mimeType });
|
|
6135
|
+
} else {
|
|
6136
|
+
pending.resolve({ success: false, error: message2.error || "Retrieval failed" });
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
6123
6139
|
}
|
|
6124
6140
|
}
|
|
6125
6141
|
async store(options) {
|
|
@@ -6163,6 +6179,32 @@ var StorageWebSocketClient = class {
|
|
|
6163
6179
|
}
|
|
6164
6180
|
this.pendingRequests.clear();
|
|
6165
6181
|
}
|
|
6182
|
+
async retrieve(cid, timeout = 3e4) {
|
|
6183
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
6184
|
+
await this.connect();
|
|
6185
|
+
}
|
|
6186
|
+
const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
6187
|
+
const request = {
|
|
6188
|
+
type: "retrieve-request",
|
|
6189
|
+
requestId,
|
|
6190
|
+
cid
|
|
6191
|
+
};
|
|
6192
|
+
return new Promise((resolve, reject) => {
|
|
6193
|
+
const timeoutHandle = setTimeout(() => {
|
|
6194
|
+
this.pendingRequests.delete(requestId);
|
|
6195
|
+
reject(new Error("Retrieval request timeout"));
|
|
6196
|
+
}, timeout);
|
|
6197
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
|
|
6198
|
+
try {
|
|
6199
|
+
this.ws.send(JSON.stringify(request));
|
|
6200
|
+
console.log("[Storage WS] Sent retrieval request:", requestId, "CID:", cid);
|
|
6201
|
+
} catch (error) {
|
|
6202
|
+
clearTimeout(timeoutHandle);
|
|
6203
|
+
this.pendingRequests.delete(requestId);
|
|
6204
|
+
reject(error);
|
|
6205
|
+
}
|
|
6206
|
+
});
|
|
6207
|
+
}
|
|
6166
6208
|
isConnected() {
|
|
6167
6209
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
6168
6210
|
}
|
|
@@ -6573,51 +6615,32 @@ Nonce: ${nonce}`;
|
|
|
6573
6615
|
}
|
|
6574
6616
|
}
|
|
6575
6617
|
/**
|
|
6576
|
-
* Retrieve ciphertext from a node via
|
|
6618
|
+
* Retrieve ciphertext from a node via WebSocket relay
|
|
6577
6619
|
*/
|
|
6578
6620
|
async retrieve(cid) {
|
|
6579
|
-
if (!this.
|
|
6580
|
-
|
|
6581
|
-
return { success: false, error: "P2P node not initialized" };
|
|
6621
|
+
if (!this.config.relayWsUrl) {
|
|
6622
|
+
return { success: false, error: "WebSocket relay URL not configured" };
|
|
6582
6623
|
}
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
if (libp2pPeers.length === 0) {
|
|
6588
|
-
console.warn("[ByteCave] Retrieve failed: No libp2p peers connected, but have", this.knownPeers.size, "known peers");
|
|
6589
|
-
return { success: false, error: "No connected peers available" };
|
|
6590
|
-
}
|
|
6591
|
-
const peersWithCid = [];
|
|
6592
|
-
for (const peerId of libp2pPeers) {
|
|
6593
|
-
const peerIdStr = peerId.toString();
|
|
6594
|
-
try {
|
|
6595
|
-
const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
|
|
6596
|
-
if (hasCid) {
|
|
6597
|
-
peersWithCid.push(peerIdStr);
|
|
6598
|
-
}
|
|
6599
|
-
} catch (error) {
|
|
6624
|
+
console.log("[ByteCave] Retrieving via WebSocket relay, CID:", cid);
|
|
6625
|
+
try {
|
|
6626
|
+
if (!this.storageWsClient) {
|
|
6627
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
6600
6628
|
}
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
);
|
|
6610
|
-
const result = await Promise.race([
|
|
6611
|
-
p2pProtocolClient.retrieveFromPeer(peerId, cid),
|
|
6612
|
-
timeoutPromise
|
|
6613
|
-
]);
|
|
6614
|
-
if (result) {
|
|
6615
|
-
return { success: true, data: result.data, peerId };
|
|
6616
|
-
}
|
|
6617
|
-
} catch (error) {
|
|
6629
|
+
const result = await this.storageWsClient.retrieve(cid, 3e4);
|
|
6630
|
+
if (result.success && result.data) {
|
|
6631
|
+
console.log("[ByteCave] \u2713 WebSocket retrieval successful:", cid);
|
|
6632
|
+
return {
|
|
6633
|
+
success: true,
|
|
6634
|
+
data: result.data,
|
|
6635
|
+
peerId: "relay-ws"
|
|
6636
|
+
};
|
|
6618
6637
|
}
|
|
6638
|
+
console.warn("[ByteCave] WebSocket retrieval failed:", result.error);
|
|
6639
|
+
return { success: false, error: result.error || "Retrieval failed" };
|
|
6640
|
+
} catch (err) {
|
|
6641
|
+
console.error("[ByteCave] WebSocket retrieval exception:", err.message);
|
|
6642
|
+
return { success: false, error: err.message };
|
|
6619
6643
|
}
|
|
6620
|
-
return { success: false, error: "Failed to retrieve blob from peers that have it" };
|
|
6621
6644
|
}
|
|
6622
6645
|
/**
|
|
6623
6646
|
* Register content in ContentRegistry contract (on-chain)
|
|
@@ -7362,7 +7385,7 @@ function useHashdUrl(hashdUrl) {
|
|
|
7362
7385
|
URL.revokeObjectURL(blobUrl);
|
|
7363
7386
|
}
|
|
7364
7387
|
};
|
|
7365
|
-
}, [hashdUrl
|
|
7388
|
+
}, [hashdUrl]);
|
|
7366
7389
|
return { blobUrl, loading, error };
|
|
7367
7390
|
}
|
|
7368
7391
|
|
package/dist/client.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export declare class ByteCaveClient {
|
|
|
39
39
|
*/
|
|
40
40
|
store(data: Uint8Array | ArrayBuffer, mimeType?: string, signer?: any, hashIdToken?: number): Promise<StoreResult>;
|
|
41
41
|
/**
|
|
42
|
-
* Retrieve ciphertext from a node via
|
|
42
|
+
* Retrieve ciphertext from a node via WebSocket relay
|
|
43
43
|
*/
|
|
44
44
|
retrieve(cid: string): Promise<RetrieveResult>;
|
|
45
45
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -6173,6 +6173,22 @@ var StorageWebSocketClient = class {
|
|
|
6173
6173
|
pending.resolve({ success: false, error: message2.error || "Storage failed" });
|
|
6174
6174
|
}
|
|
6175
6175
|
}
|
|
6176
|
+
} else if (message2.type === "retrieve-response") {
|
|
6177
|
+
const pending = this.pendingRequests.get(message2.requestId);
|
|
6178
|
+
if (pending) {
|
|
6179
|
+
clearTimeout(pending.timeout);
|
|
6180
|
+
this.pendingRequests.delete(message2.requestId);
|
|
6181
|
+
if (message2.success && message2.data) {
|
|
6182
|
+
const binaryString = atob(message2.data);
|
|
6183
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
6184
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
6185
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
6186
|
+
}
|
|
6187
|
+
pending.resolve({ success: true, data: bytes, mimeType: message2.mimeType });
|
|
6188
|
+
} else {
|
|
6189
|
+
pending.resolve({ success: false, error: message2.error || "Retrieval failed" });
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6176
6192
|
}
|
|
6177
6193
|
}
|
|
6178
6194
|
async store(options) {
|
|
@@ -6216,6 +6232,32 @@ var StorageWebSocketClient = class {
|
|
|
6216
6232
|
}
|
|
6217
6233
|
this.pendingRequests.clear();
|
|
6218
6234
|
}
|
|
6235
|
+
async retrieve(cid, timeout = 3e4) {
|
|
6236
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
6237
|
+
await this.connect();
|
|
6238
|
+
}
|
|
6239
|
+
const requestId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
6240
|
+
const request = {
|
|
6241
|
+
type: "retrieve-request",
|
|
6242
|
+
requestId,
|
|
6243
|
+
cid
|
|
6244
|
+
};
|
|
6245
|
+
return new Promise((resolve, reject) => {
|
|
6246
|
+
const timeoutHandle = setTimeout(() => {
|
|
6247
|
+
this.pendingRequests.delete(requestId);
|
|
6248
|
+
reject(new Error("Retrieval request timeout"));
|
|
6249
|
+
}, timeout);
|
|
6250
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
|
|
6251
|
+
try {
|
|
6252
|
+
this.ws.send(JSON.stringify(request));
|
|
6253
|
+
console.log("[Storage WS] Sent retrieval request:", requestId, "CID:", cid);
|
|
6254
|
+
} catch (error) {
|
|
6255
|
+
clearTimeout(timeoutHandle);
|
|
6256
|
+
this.pendingRequests.delete(requestId);
|
|
6257
|
+
reject(error);
|
|
6258
|
+
}
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6219
6261
|
isConnected() {
|
|
6220
6262
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
6221
6263
|
}
|
|
@@ -6626,51 +6668,32 @@ Nonce: ${nonce}`;
|
|
|
6626
6668
|
}
|
|
6627
6669
|
}
|
|
6628
6670
|
/**
|
|
6629
|
-
* Retrieve ciphertext from a node via
|
|
6671
|
+
* Retrieve ciphertext from a node via WebSocket relay
|
|
6630
6672
|
*/
|
|
6631
6673
|
async retrieve(cid) {
|
|
6632
|
-
if (!this.
|
|
6633
|
-
|
|
6634
|
-
return { success: false, error: "P2P node not initialized" };
|
|
6674
|
+
if (!this.config.relayWsUrl) {
|
|
6675
|
+
return { success: false, error: "WebSocket relay URL not configured" };
|
|
6635
6676
|
}
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
if (libp2pPeers.length === 0) {
|
|
6641
|
-
console.warn("[ByteCave] Retrieve failed: No libp2p peers connected, but have", this.knownPeers.size, "known peers");
|
|
6642
|
-
return { success: false, error: "No connected peers available" };
|
|
6643
|
-
}
|
|
6644
|
-
const peersWithCid = [];
|
|
6645
|
-
for (const peerId of libp2pPeers) {
|
|
6646
|
-
const peerIdStr = peerId.toString();
|
|
6647
|
-
try {
|
|
6648
|
-
const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
|
|
6649
|
-
if (hasCid) {
|
|
6650
|
-
peersWithCid.push(peerIdStr);
|
|
6651
|
-
}
|
|
6652
|
-
} catch (error) {
|
|
6677
|
+
console.log("[ByteCave] Retrieving via WebSocket relay, CID:", cid);
|
|
6678
|
+
try {
|
|
6679
|
+
if (!this.storageWsClient) {
|
|
6680
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
6653
6681
|
}
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
);
|
|
6663
|
-
const result = await Promise.race([
|
|
6664
|
-
p2pProtocolClient.retrieveFromPeer(peerId, cid),
|
|
6665
|
-
timeoutPromise
|
|
6666
|
-
]);
|
|
6667
|
-
if (result) {
|
|
6668
|
-
return { success: true, data: result.data, peerId };
|
|
6669
|
-
}
|
|
6670
|
-
} catch (error) {
|
|
6682
|
+
const result = await this.storageWsClient.retrieve(cid, 3e4);
|
|
6683
|
+
if (result.success && result.data) {
|
|
6684
|
+
console.log("[ByteCave] \u2713 WebSocket retrieval successful:", cid);
|
|
6685
|
+
return {
|
|
6686
|
+
success: true,
|
|
6687
|
+
data: result.data,
|
|
6688
|
+
peerId: "relay-ws"
|
|
6689
|
+
};
|
|
6671
6690
|
}
|
|
6691
|
+
console.warn("[ByteCave] WebSocket retrieval failed:", result.error);
|
|
6692
|
+
return { success: false, error: result.error || "Retrieval failed" };
|
|
6693
|
+
} catch (err) {
|
|
6694
|
+
console.error("[ByteCave] WebSocket retrieval exception:", err.message);
|
|
6695
|
+
return { success: false, error: err.message };
|
|
6672
6696
|
}
|
|
6673
|
-
return { success: false, error: "Failed to retrieve blob from peers that have it" };
|
|
6674
6697
|
}
|
|
6675
6698
|
/**
|
|
6676
6699
|
* Register content in ContentRegistry contract (on-chain)
|
|
@@ -7557,7 +7580,7 @@ function useHashdUrl(hashdUrl) {
|
|
|
7557
7580
|
URL.revokeObjectURL(blobUrl);
|
|
7558
7581
|
}
|
|
7559
7582
|
};
|
|
7560
|
-
}, [hashdUrl
|
|
7583
|
+
}, [hashdUrl]);
|
|
7561
7584
|
return { blobUrl, loading, error };
|
|
7562
7585
|
}
|
|
7563
7586
|
|
package/dist/index.js
CHANGED
package/dist/react/index.cjs
CHANGED
|
@@ -6426,7 +6426,7 @@ function useHashdUrl(hashdUrl) {
|
|
|
6426
6426
|
URL.revokeObjectURL(blobUrl);
|
|
6427
6427
|
}
|
|
6428
6428
|
};
|
|
6429
|
-
}, [hashdUrl
|
|
6429
|
+
}, [hashdUrl]);
|
|
6430
6430
|
return { blobUrl, loading, error };
|
|
6431
6431
|
}
|
|
6432
6432
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/react/index.js
CHANGED
|
@@ -29,5 +29,11 @@ export declare class StorageWebSocketClient {
|
|
|
29
29
|
error?: string;
|
|
30
30
|
}>;
|
|
31
31
|
disconnect(): void;
|
|
32
|
+
retrieve(cid: string, timeout?: number): Promise<{
|
|
33
|
+
success: boolean;
|
|
34
|
+
data?: Uint8Array;
|
|
35
|
+
mimeType?: string;
|
|
36
|
+
error?: string;
|
|
37
|
+
}>;
|
|
32
38
|
isConnected(): boolean;
|
|
33
39
|
}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -523,66 +523,37 @@ Nonce: ${nonce}`;
|
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
/**
|
|
526
|
-
* Retrieve ciphertext from a node via
|
|
526
|
+
* Retrieve ciphertext from a node via WebSocket relay
|
|
527
527
|
*/
|
|
528
528
|
async retrieve(cid: string): Promise<RetrieveResult> {
|
|
529
|
-
if (!this.
|
|
530
|
-
|
|
531
|
-
return { success: false, error: 'P2P node not initialized' };
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const libp2pPeers = this.node.getPeers();
|
|
535
|
-
console.log('[ByteCave] Retrieve - libp2p peers:', libp2pPeers.length);
|
|
536
|
-
console.log('[ByteCave] Retrieve - known peers:', this.knownPeers.size);
|
|
537
|
-
console.log('[ByteCave] Retrieve - node status:', this.node.status);
|
|
538
|
-
|
|
539
|
-
if (libp2pPeers.length === 0) {
|
|
540
|
-
console.warn('[ByteCave] Retrieve failed: No libp2p peers connected, but have', this.knownPeers.size, 'known peers');
|
|
541
|
-
return { success: false, error: 'No connected peers available' };
|
|
529
|
+
if (!this.config.relayWsUrl) {
|
|
530
|
+
return { success: false, error: 'WebSocket relay URL not configured' };
|
|
542
531
|
}
|
|
543
532
|
|
|
544
|
-
|
|
545
|
-
const peersWithCid: string[] = [];
|
|
533
|
+
console.log('[ByteCave] Retrieving via WebSocket relay, CID:', cid);
|
|
546
534
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
try {
|
|
551
|
-
const hasCid = await p2pProtocolClient.peerHasCid(peerIdStr, cid);
|
|
552
|
-
|
|
553
|
-
if (hasCid) {
|
|
554
|
-
peersWithCid.push(peerIdStr);
|
|
555
|
-
}
|
|
556
|
-
} catch (error: any) {
|
|
557
|
-
// Skip peers that don't support the protocol
|
|
535
|
+
try {
|
|
536
|
+
if (!this.storageWsClient) {
|
|
537
|
+
this.storageWsClient = new StorageWebSocketClient(this.config.relayWsUrl);
|
|
558
538
|
}
|
|
559
|
-
}
|
|
560
539
|
|
|
561
|
-
|
|
562
|
-
return { success: false, error: 'Blob not found on any connected peer' };
|
|
563
|
-
}
|
|
540
|
+
const result = await this.storageWsClient.retrieve(cid, 30000);
|
|
564
541
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const result = await Promise.race([
|
|
573
|
-
p2pProtocolClient.retrieveFromPeer(peerId, cid),
|
|
574
|
-
timeoutPromise
|
|
575
|
-
]);
|
|
576
|
-
|
|
577
|
-
if (result) {
|
|
578
|
-
return { success: true, data: result.data, peerId };
|
|
579
|
-
}
|
|
580
|
-
} catch (error: any) {
|
|
581
|
-
// Continue to next peer
|
|
542
|
+
if (result.success && result.data) {
|
|
543
|
+
console.log('[ByteCave] ✓ WebSocket retrieval successful:', cid);
|
|
544
|
+
return {
|
|
545
|
+
success: true,
|
|
546
|
+
data: result.data,
|
|
547
|
+
peerId: 'relay-ws'
|
|
548
|
+
};
|
|
582
549
|
}
|
|
583
|
-
}
|
|
584
550
|
|
|
585
|
-
|
|
551
|
+
console.warn('[ByteCave] WebSocket retrieval failed:', result.error);
|
|
552
|
+
return { success: false, error: result.error || 'Retrieval failed' };
|
|
553
|
+
} catch (err: any) {
|
|
554
|
+
console.error('[ByteCave] WebSocket retrieval exception:', err.message);
|
|
555
|
+
return { success: false, error: err.message };
|
|
556
|
+
}
|
|
586
557
|
}
|
|
587
558
|
|
|
588
559
|
/**
|
package/src/react/useHashdUrl.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function useHashdUrl(hashdUrl: string | null | undefined): UseHashdUrlRes
|
|
|
62
62
|
URL.revokeObjectURL(blobUrl);
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
|
-
}, [hashdUrl
|
|
65
|
+
}, [hashdUrl]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
66
66
|
|
|
67
67
|
return { blobUrl, loading, error };
|
|
68
68
|
}
|
package/src/storage-websocket.ts
CHANGED
|
@@ -27,7 +27,22 @@ interface StorageResponseMessage {
|
|
|
27
27
|
error?: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
interface RetrieveRequestMessage {
|
|
31
|
+
type: 'retrieve-request';
|
|
32
|
+
requestId: string;
|
|
33
|
+
cid: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface RetrieveResponseMessage {
|
|
37
|
+
type: 'retrieve-response';
|
|
38
|
+
requestId: string;
|
|
39
|
+
success: boolean;
|
|
40
|
+
data?: string; // base64
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type Message = StorageRequestMessage | StorageResponseMessage | RetrieveRequestMessage | RetrieveResponseMessage;
|
|
31
46
|
|
|
32
47
|
export interface StoreViaWebSocketOptions {
|
|
33
48
|
data: Uint8Array;
|
|
@@ -47,7 +62,7 @@ export interface StoreViaWebSocketOptions {
|
|
|
47
62
|
export class StorageWebSocketClient {
|
|
48
63
|
private ws: WebSocket | null = null;
|
|
49
64
|
private pendingRequests: Map<string, {
|
|
50
|
-
resolve: (result:
|
|
65
|
+
resolve: (result: any) => void;
|
|
51
66
|
reject: (error: Error) => void;
|
|
52
67
|
timeout: NodeJS.Timeout;
|
|
53
68
|
}> = new Map();
|
|
@@ -107,6 +122,24 @@ export class StorageWebSocketClient {
|
|
|
107
122
|
pending.resolve({ success: false, error: message.error || 'Storage failed' });
|
|
108
123
|
}
|
|
109
124
|
}
|
|
125
|
+
} else if (message.type === 'retrieve-response') {
|
|
126
|
+
const pending = this.pendingRequests.get(message.requestId);
|
|
127
|
+
if (pending) {
|
|
128
|
+
clearTimeout(pending.timeout);
|
|
129
|
+
this.pendingRequests.delete(message.requestId);
|
|
130
|
+
|
|
131
|
+
if (message.success && message.data) {
|
|
132
|
+
// Convert base64 to Uint8Array
|
|
133
|
+
const binaryString = atob(message.data);
|
|
134
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
135
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
136
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
137
|
+
}
|
|
138
|
+
pending.resolve({ success: true, data: bytes, mimeType: message.mimeType });
|
|
139
|
+
} else {
|
|
140
|
+
pending.resolve({ success: false, error: message.error || 'Retrieval failed' });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
110
143
|
}
|
|
111
144
|
}
|
|
112
145
|
|
|
@@ -163,6 +196,39 @@ export class StorageWebSocketClient {
|
|
|
163
196
|
this.pendingRequests.clear();
|
|
164
197
|
}
|
|
165
198
|
|
|
199
|
+
async retrieve(cid: string, timeout: number = 30000): Promise<{ success: boolean; data?: Uint8Array; mimeType?: string; error?: string }> {
|
|
200
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
201
|
+
await this.connect();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const requestId = Math.random().toString(36).substring(2, 15) +
|
|
205
|
+
Math.random().toString(36).substring(2, 15);
|
|
206
|
+
|
|
207
|
+
const request: RetrieveRequestMessage = {
|
|
208
|
+
type: 'retrieve-request',
|
|
209
|
+
requestId,
|
|
210
|
+
cid
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return new Promise((resolve, reject) => {
|
|
214
|
+
const timeoutHandle = setTimeout(() => {
|
|
215
|
+
this.pendingRequests.delete(requestId);
|
|
216
|
+
reject(new Error('Retrieval request timeout'));
|
|
217
|
+
}, timeout);
|
|
218
|
+
|
|
219
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle });
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
this.ws!.send(JSON.stringify(request));
|
|
223
|
+
console.log('[Storage WS] Sent retrieval request:', requestId, 'CID:', cid);
|
|
224
|
+
} catch (error: any) {
|
|
225
|
+
clearTimeout(timeoutHandle);
|
|
226
|
+
this.pendingRequests.delete(requestId);
|
|
227
|
+
reject(error);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
166
232
|
isConnected(): boolean {
|
|
167
233
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
168
234
|
}
|