feat: add StorageLocationProvider
This commit is contained in:
parent
86522e1ffe
commit
6d19fdb66e
138
src/storage.ts
138
src/storage.ts
|
@ -1,3 +1,7 @@
|
|||
import { S5Node } from "#node.js";
|
||||
import { Multihash } from "#multihash.js";
|
||||
import NodeId from "#nodeId.js";
|
||||
|
||||
export default class StorageLocation {
|
||||
type: number;
|
||||
parts: string[];
|
||||
|
@ -29,3 +33,137 @@ export default class StorageLocation {
|
|||
}, expiry: ${expiryDate.toISOString()})`;
|
||||
}
|
||||
}
|
||||
|
||||
class StorageLocationProvider {
|
||||
private node: S5Node;
|
||||
private hash: Multihash;
|
||||
private types: number[];
|
||||
|
||||
private static readonly storageLocationTypeFull: number = 0; // Example value, adjust as necessary
|
||||
private readonly timeoutDuration: number = 60000; // Duration in milliseconds
|
||||
|
||||
private availableNodes: NodeId[] = [];
|
||||
private uris: Map<NodeId, StorageLocation> = new Map<
|
||||
NodeId,
|
||||
StorageLocation
|
||||
>();
|
||||
|
||||
private timeout?: Date;
|
||||
private isTimedOut: boolean = false;
|
||||
|
||||
constructor(
|
||||
node: S5Node,
|
||||
hash: Multihash,
|
||||
types: number[] = [StorageLocationProvider.storageLocationTypeFull],
|
||||
) {
|
||||
this.node = node;
|
||||
this.hash = hash;
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
this.uris = new Map(
|
||||
await this.node.getCachedStorageLocations(this.hash, this.types),
|
||||
);
|
||||
|
||||
this.availableNodes = Array.from(this.uris.keys());
|
||||
this.node.services.p2p.sortNodesByScore(this.availableNodes);
|
||||
|
||||
this.timeout = new Date(Date.now() + this.timeoutDuration);
|
||||
|
||||
let requestSent = false;
|
||||
|
||||
while (true) {
|
||||
const newUris = new Map(
|
||||
await this.node.getCachedStorageLocations(this.hash, this.types),
|
||||
);
|
||||
|
||||
if (
|
||||
this.availableNodes.length === 0 &&
|
||||
newUris.size < 2 &&
|
||||
!requestSent
|
||||
) {
|
||||
this.node.services.p2p.sendHashRequest(this.hash, this.types);
|
||||
requestSent = true;
|
||||
}
|
||||
|
||||
let hasNewNode = false;
|
||||
|
||||
for (const [key, value] of newUris) {
|
||||
if (!this.uris.has(key) || this.uris.get(key) !== value) {
|
||||
this.uris.set(key, value);
|
||||
if (!this.availableNodes.includes(key)) {
|
||||
this.availableNodes.push(key);
|
||||
hasNewNode = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNewNode) {
|
||||
this.node.services.p2p.sortNodesByScore(this.availableNodes);
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
if (new Date() > this.timeout) {
|
||||
this.isTimedOut = true;
|
||||
return;
|
||||
}
|
||||
|
||||
while (this.availableNodes.length > 0 || !this.isWaitingForUri) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
if (new Date() > this.timeout) {
|
||||
this.isTimedOut = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isWaitingForUri: boolean = false;
|
||||
|
||||
async next(): Promise<SignedStorageLocation> {
|
||||
this.timeout = new Date(Date.now() + this.timeoutDuration);
|
||||
|
||||
while (true) {
|
||||
if (this.availableNodes.length > 0) {
|
||||
this.isWaitingForUri = false;
|
||||
const nodeId = this.availableNodes.shift()!;
|
||||
|
||||
return new SignedStorageLocation(nodeId, this.uris.get(nodeId)!);
|
||||
}
|
||||
|
||||
this.isWaitingForUri = true;
|
||||
|
||||
if (this.isTimedOut) {
|
||||
throw new Error(
|
||||
`Could not download raw file: Timed out after ${this.timeoutDuration}ms ${this.hash}`,
|
||||
);
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
}
|
||||
|
||||
upvote(uri: SignedStorageLocation): void {
|
||||
this.node.services.p2p.upvote(uri.nodeId);
|
||||
}
|
||||
|
||||
downvote(uri: SignedStorageLocation): void {
|
||||
this.node.services.p2p.downvote(uri.nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
class SignedStorageLocation {
|
||||
nodeId: NodeId;
|
||||
location: StorageLocation;
|
||||
|
||||
constructor(nodeId: NodeId, location: StorageLocation) {
|
||||
this.nodeId = nodeId;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `SignedStorageLocation(${this.location}, ${this.nodeId})`;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue