@optimystic/db-p2p 0.0.1
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/index.min.js +52 -0
- package/dist/index.min.js.map +7 -0
- package/dist/src/cluster/client.d.ts +12 -0
- package/dist/src/cluster/client.d.ts.map +1 -0
- package/dist/src/cluster/client.js +65 -0
- package/dist/src/cluster/client.js.map +1 -0
- package/dist/src/cluster/cluster-repo.d.ts +79 -0
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -0
- package/dist/src/cluster/cluster-repo.js +613 -0
- package/dist/src/cluster/cluster-repo.js.map +1 -0
- package/dist/src/cluster/partition-detector.d.ts +59 -0
- package/dist/src/cluster/partition-detector.d.ts.map +1 -0
- package/dist/src/cluster/partition-detector.js +129 -0
- package/dist/src/cluster/partition-detector.js.map +1 -0
- package/dist/src/cluster/service.d.ts +49 -0
- package/dist/src/cluster/service.d.ts.map +1 -0
- package/dist/src/cluster/service.js +107 -0
- package/dist/src/cluster/service.js.map +1 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +29 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/it-utility.d.ts +4 -0
- package/dist/src/it-utility.d.ts.map +1 -0
- package/dist/src/it-utility.js +32 -0
- package/dist/src/it-utility.js.map +1 -0
- package/dist/src/libp2p-key-network.d.ts +59 -0
- package/dist/src/libp2p-key-network.d.ts.map +1 -0
- package/dist/src/libp2p-key-network.js +278 -0
- package/dist/src/libp2p-key-network.js.map +1 -0
- package/dist/src/libp2p-node.d.ts +28 -0
- package/dist/src/libp2p-node.d.ts.map +1 -0
- package/dist/src/libp2p-node.js +270 -0
- package/dist/src/libp2p-node.js.map +1 -0
- package/dist/src/logger.d.ts +3 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +6 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/network/get-network-manager.d.ts +4 -0
- package/dist/src/network/get-network-manager.d.ts.map +1 -0
- package/dist/src/network/get-network-manager.js +17 -0
- package/dist/src/network/get-network-manager.js.map +1 -0
- package/dist/src/network/network-manager-service.d.ts +82 -0
- package/dist/src/network/network-manager-service.d.ts.map +1 -0
- package/dist/src/network/network-manager-service.js +283 -0
- package/dist/src/network/network-manager-service.js.map +1 -0
- package/dist/src/peer-utils.d.ts +2 -0
- package/dist/src/peer-utils.d.ts.map +1 -0
- package/dist/src/peer-utils.js +28 -0
- package/dist/src/peer-utils.js.map +1 -0
- package/dist/src/protocol-client.d.ts +12 -0
- package/dist/src/protocol-client.d.ts.map +1 -0
- package/dist/src/protocol-client.js +34 -0
- package/dist/src/protocol-client.js.map +1 -0
- package/dist/src/repo/client.d.ts +17 -0
- package/dist/src/repo/client.d.ts.map +1 -0
- package/dist/src/repo/client.js +82 -0
- package/dist/src/repo/client.js.map +1 -0
- package/dist/src/repo/cluster-coordinator.d.ts +59 -0
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -0
- package/dist/src/repo/cluster-coordinator.js +539 -0
- package/dist/src/repo/cluster-coordinator.js.map +1 -0
- package/dist/src/repo/coordinator-repo.d.ts +29 -0
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -0
- package/dist/src/repo/coordinator-repo.js +102 -0
- package/dist/src/repo/coordinator-repo.js.map +1 -0
- package/dist/src/repo/redirect.d.ts +14 -0
- package/dist/src/repo/redirect.d.ts.map +1 -0
- package/dist/src/repo/redirect.js +9 -0
- package/dist/src/repo/redirect.js.map +1 -0
- package/dist/src/repo/service.d.ts +52 -0
- package/dist/src/repo/service.d.ts.map +1 -0
- package/dist/src/repo/service.js +181 -0
- package/dist/src/repo/service.js.map +1 -0
- package/dist/src/repo/types.d.ts +7 -0
- package/dist/src/repo/types.d.ts.map +1 -0
- package/dist/src/repo/types.js +2 -0
- package/dist/src/repo/types.js.map +1 -0
- package/dist/src/routing/libp2p-known-peers.d.ts +4 -0
- package/dist/src/routing/libp2p-known-peers.d.ts.map +1 -0
- package/dist/src/routing/libp2p-known-peers.js +19 -0
- package/dist/src/routing/libp2p-known-peers.js.map +1 -0
- package/dist/src/routing/responsibility.d.ts +14 -0
- package/dist/src/routing/responsibility.d.ts.map +1 -0
- package/dist/src/routing/responsibility.js +45 -0
- package/dist/src/routing/responsibility.js.map +1 -0
- package/dist/src/routing/simple-cluster-coordinator.d.ts +23 -0
- package/dist/src/routing/simple-cluster-coordinator.d.ts.map +1 -0
- package/dist/src/routing/simple-cluster-coordinator.js +59 -0
- package/dist/src/routing/simple-cluster-coordinator.js.map +1 -0
- package/dist/src/storage/arachnode-fret-adapter.d.ts +65 -0
- package/dist/src/storage/arachnode-fret-adapter.d.ts.map +1 -0
- package/dist/src/storage/arachnode-fret-adapter.js +93 -0
- package/dist/src/storage/arachnode-fret-adapter.js.map +1 -0
- package/dist/src/storage/block-storage.d.ts +31 -0
- package/dist/src/storage/block-storage.d.ts.map +1 -0
- package/dist/src/storage/block-storage.js +154 -0
- package/dist/src/storage/block-storage.js.map +1 -0
- package/dist/src/storage/file-storage.d.ts +30 -0
- package/dist/src/storage/file-storage.d.ts.map +1 -0
- package/dist/src/storage/file-storage.js +127 -0
- package/dist/src/storage/file-storage.js.map +1 -0
- package/dist/src/storage/helpers.d.ts +3 -0
- package/dist/src/storage/helpers.d.ts.map +1 -0
- package/dist/src/storage/helpers.js +28 -0
- package/dist/src/storage/helpers.js.map +1 -0
- package/dist/src/storage/i-block-storage.d.ts +32 -0
- package/dist/src/storage/i-block-storage.d.ts.map +1 -0
- package/dist/src/storage/i-block-storage.js +2 -0
- package/dist/src/storage/i-block-storage.js.map +1 -0
- package/dist/src/storage/i-raw-storage.d.ts +20 -0
- package/dist/src/storage/i-raw-storage.d.ts.map +1 -0
- package/dist/src/storage/i-raw-storage.js +2 -0
- package/dist/src/storage/i-raw-storage.js.map +1 -0
- package/dist/src/storage/memory-storage.d.ts +27 -0
- package/dist/src/storage/memory-storage.d.ts.map +1 -0
- package/dist/src/storage/memory-storage.js +87 -0
- package/dist/src/storage/memory-storage.js.map +1 -0
- package/dist/src/storage/restoration-coordinator-v2.d.ts +63 -0
- package/dist/src/storage/restoration-coordinator-v2.d.ts.map +1 -0
- package/dist/src/storage/restoration-coordinator-v2.js +157 -0
- package/dist/src/storage/restoration-coordinator-v2.js.map +1 -0
- package/dist/src/storage/ring-selector.d.ts +56 -0
- package/dist/src/storage/ring-selector.d.ts.map +1 -0
- package/dist/src/storage/ring-selector.js +118 -0
- package/dist/src/storage/ring-selector.js.map +1 -0
- package/dist/src/storage/storage-monitor.d.ts +23 -0
- package/dist/src/storage/storage-monitor.d.ts.map +1 -0
- package/dist/src/storage/storage-monitor.js +40 -0
- package/dist/src/storage/storage-monitor.js.map +1 -0
- package/dist/src/storage/storage-repo.d.ts +17 -0
- package/dist/src/storage/storage-repo.d.ts.map +1 -0
- package/dist/src/storage/storage-repo.js +267 -0
- package/dist/src/storage/storage-repo.js.map +1 -0
- package/dist/src/storage/struct.d.ts +29 -0
- package/dist/src/storage/struct.d.ts.map +1 -0
- package/dist/src/storage/struct.js +2 -0
- package/dist/src/storage/struct.js.map +1 -0
- package/dist/src/sync/client.d.ts +27 -0
- package/dist/src/sync/client.d.ts.map +1 -0
- package/dist/src/sync/client.js +32 -0
- package/dist/src/sync/client.js.map +1 -0
- package/dist/src/sync/protocol.d.ts +58 -0
- package/dist/src/sync/protocol.d.ts.map +1 -0
- package/dist/src/sync/protocol.js +12 -0
- package/dist/src/sync/protocol.js.map +1 -0
- package/dist/src/sync/service.d.ts +62 -0
- package/dist/src/sync/service.d.ts.map +1 -0
- package/dist/src/sync/service.js +168 -0
- package/dist/src/sync/service.js.map +1 -0
- package/package.json +73 -0
- package/readme.md +497 -0
- package/src/cluster/client.ts +63 -0
- package/src/cluster/cluster-repo.ts +711 -0
- package/src/cluster/partition-detector.ts +158 -0
- package/src/cluster/service.ts +156 -0
- package/src/index.ts +30 -0
- package/src/it-utility.ts +36 -0
- package/src/libp2p-key-network.ts +334 -0
- package/src/libp2p-node.ts +335 -0
- package/src/logger.ts +9 -0
- package/src/network/get-network-manager.ts +17 -0
- package/src/network/network-manager-service.ts +334 -0
- package/src/peer-utils.ts +24 -0
- package/src/protocol-client.ts +54 -0
- package/src/repo/client.ts +112 -0
- package/src/repo/cluster-coordinator.ts +592 -0
- package/src/repo/coordinator-repo.ts +137 -0
- package/src/repo/redirect.ts +17 -0
- package/src/repo/service.ts +219 -0
- package/src/repo/types.ts +7 -0
- package/src/routing/libp2p-known-peers.ts +26 -0
- package/src/routing/responsibility.ts +63 -0
- package/src/routing/simple-cluster-coordinator.ts +70 -0
- package/src/storage/arachnode-fret-adapter.ts +128 -0
- package/src/storage/block-storage.ts +182 -0
- package/src/storage/file-storage.ts +163 -0
- package/src/storage/helpers.ts +29 -0
- package/src/storage/i-block-storage.ts +40 -0
- package/src/storage/i-raw-storage.ts +30 -0
- package/src/storage/memory-storage.ts +108 -0
- package/src/storage/restoration-coordinator-v2.ts +191 -0
- package/src/storage/ring-selector.ts +155 -0
- package/src/storage/storage-monitor.ts +59 -0
- package/src/storage/storage-repo.ts +320 -0
- package/src/storage/struct.ts +34 -0
- package/src/sync/client.ts +42 -0
- package/src/sync/protocol.ts +71 -0
- package/src/sync/service.ts +229 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createLogger } from '../logger.js';
|
|
2
|
+
const log = createLogger('network:get-manager');
|
|
3
|
+
export function getNetworkManager(node) {
|
|
4
|
+
const svc = node.services?.networkManager;
|
|
5
|
+
if (svc == null) {
|
|
6
|
+
throw new Error('networkManager service is not registered on this libp2p node');
|
|
7
|
+
}
|
|
8
|
+
// Provide libp2p reference early to avoid MissingServiceError from components accessor
|
|
9
|
+
try {
|
|
10
|
+
svc.setLibp2p?.(node);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
log('getNetworkManager setLibp2p failed - %o', err);
|
|
14
|
+
}
|
|
15
|
+
return svc;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=get-network-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-network-manager.js","sourceRoot":"","sources":["../../../src/network/get-network-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,MAAM,GAAG,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAA;AAE/C,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,GAAG,GAAI,IAAY,CAAC,QAAQ,EAAE,cAAc,CAAA;IAClD,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;IACjF,CAAC;IACD,uFAAuF;IACvF,IAAI,CAAC;QAAE,GAAW,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAA;IAAC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAAC,GAAG,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAA;IAAC,CAAC;IAC1G,OAAO,GAA4B,CAAA;AACrC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Startable, Logger, PeerId, Libp2p } from '@libp2p/interface';
|
|
2
|
+
export type NetworkManagerServiceInit = {
|
|
3
|
+
clusterSize?: number;
|
|
4
|
+
seedKeys?: Uint8Array[];
|
|
5
|
+
estimation?: {
|
|
6
|
+
samples: number;
|
|
7
|
+
kth: number;
|
|
8
|
+
timeoutMs: number;
|
|
9
|
+
ttlMs: number;
|
|
10
|
+
};
|
|
11
|
+
readiness?: {
|
|
12
|
+
minPeers: number;
|
|
13
|
+
maxWaitMs: number;
|
|
14
|
+
};
|
|
15
|
+
cacheTTLs?: {
|
|
16
|
+
coordinatorMs: number;
|
|
17
|
+
clusterMs: number;
|
|
18
|
+
};
|
|
19
|
+
expectedRemotes?: boolean;
|
|
20
|
+
allowClusterDownsize?: boolean;
|
|
21
|
+
clusterSizeTolerance?: number;
|
|
22
|
+
};
|
|
23
|
+
type Components = {
|
|
24
|
+
logger: {
|
|
25
|
+
forComponent: (name: string) => Logger;
|
|
26
|
+
};
|
|
27
|
+
registrar: {
|
|
28
|
+
handle: (...args: any[]) => Promise<void>;
|
|
29
|
+
unhandle: (...args: any[]) => Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
libp2p?: Libp2p;
|
|
32
|
+
};
|
|
33
|
+
export declare class NetworkManagerService implements Startable {
|
|
34
|
+
private readonly components;
|
|
35
|
+
private running;
|
|
36
|
+
private readonly log;
|
|
37
|
+
private readonly cfg;
|
|
38
|
+
private readyPromise;
|
|
39
|
+
private readonly coordinatorCache;
|
|
40
|
+
private readonly clusterCache;
|
|
41
|
+
private lastEstimate;
|
|
42
|
+
private readonly blacklist;
|
|
43
|
+
private libp2pRef;
|
|
44
|
+
constructor(components: Components, init?: NetworkManagerServiceInit);
|
|
45
|
+
setLibp2p(libp2p: Libp2p): void;
|
|
46
|
+
private getLibp2p;
|
|
47
|
+
private getFret;
|
|
48
|
+
get [Symbol.toStringTag](): string;
|
|
49
|
+
start(): Promise<void>;
|
|
50
|
+
stop(): Promise<void>;
|
|
51
|
+
ready(): Promise<void>;
|
|
52
|
+
private seedKey;
|
|
53
|
+
private toCacheKey;
|
|
54
|
+
private getKnownPeers;
|
|
55
|
+
getStatus(): {
|
|
56
|
+
mode: 'alone' | 'healthy' | 'degraded';
|
|
57
|
+
connections: number;
|
|
58
|
+
};
|
|
59
|
+
awaitHealthy(minRemotes: number, timeoutMs: number): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Record a misbehaving peer. Higher score means worse reputation.
|
|
62
|
+
* Entries expire to allow eventual forgiveness.
|
|
63
|
+
*/
|
|
64
|
+
reportBadPeer(peerId: PeerId, penalty?: number, ttlMs?: number): void;
|
|
65
|
+
private isBlacklisted;
|
|
66
|
+
recordCoordinator(key: Uint8Array, peerId: PeerId): void;
|
|
67
|
+
/**
|
|
68
|
+
* Find the nearest peer to the provided content key using FRET,
|
|
69
|
+
* falling back to self if FRET is unavailable.
|
|
70
|
+
*/
|
|
71
|
+
private findNearestPeerToKey;
|
|
72
|
+
/**
|
|
73
|
+
* Compute cluster using FRET's assembleCohort for content-addressed peer selection.
|
|
74
|
+
*/
|
|
75
|
+
getCluster(key: Uint8Array): Promise<PeerId[]>;
|
|
76
|
+
getCoordinator(key: Uint8Array): Promise<PeerId>;
|
|
77
|
+
private xor;
|
|
78
|
+
private lexLess;
|
|
79
|
+
}
|
|
80
|
+
export declare function networkManagerService(init?: NetworkManagerServiceInit): (components: Components) => NetworkManagerService;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=network-manager-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-manager-service.d.ts","sourceRoot":"","sources":["../../../src/network/network-manager-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { hashKey } from 'p2p-fret';
|
|
2
|
+
export class NetworkManagerService {
|
|
3
|
+
components;
|
|
4
|
+
running = false;
|
|
5
|
+
log;
|
|
6
|
+
cfg;
|
|
7
|
+
readyPromise = null;
|
|
8
|
+
coordinatorCache = new Map();
|
|
9
|
+
clusterCache = new Map();
|
|
10
|
+
lastEstimate = null;
|
|
11
|
+
// lightweight blacklist (local reputation)
|
|
12
|
+
blacklist = new Map();
|
|
13
|
+
libp2pRef;
|
|
14
|
+
constructor(components, init = {}) {
|
|
15
|
+
this.components = components;
|
|
16
|
+
this.log = components.logger.forComponent('db-p2p:network-manager');
|
|
17
|
+
this.cfg = {
|
|
18
|
+
clusterSize: init.clusterSize ?? 1,
|
|
19
|
+
seedKeys: init.seedKeys ?? [],
|
|
20
|
+
estimation: init.estimation ?? { samples: 8, kth: 5, timeoutMs: 1000, ttlMs: 60_000 },
|
|
21
|
+
readiness: init.readiness ?? { minPeers: 1, maxWaitMs: 2000 },
|
|
22
|
+
cacheTTLs: init.cacheTTLs ?? { coordinatorMs: 30 * 60_000, clusterMs: 5 * 60_000 },
|
|
23
|
+
expectedRemotes: init.expectedRemotes ?? false,
|
|
24
|
+
allowClusterDownsize: init.allowClusterDownsize ?? true,
|
|
25
|
+
clusterSizeTolerance: init.clusterSizeTolerance ?? 0.5
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
setLibp2p(libp2p) {
|
|
29
|
+
this.libp2pRef = libp2p;
|
|
30
|
+
}
|
|
31
|
+
getLibp2p() {
|
|
32
|
+
return this.libp2pRef ?? this.components.libp2p;
|
|
33
|
+
}
|
|
34
|
+
getFret() {
|
|
35
|
+
const libp2p = this.getLibp2p();
|
|
36
|
+
if (!libp2p) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return libp2p.services?.fret;
|
|
40
|
+
}
|
|
41
|
+
get [Symbol.toStringTag]() { return '@libp2p/network-manager'; }
|
|
42
|
+
async start() {
|
|
43
|
+
if (this.running)
|
|
44
|
+
return;
|
|
45
|
+
this.running = true;
|
|
46
|
+
// Do not call ready() here; libp2p components may not be fully set yet.
|
|
47
|
+
// Consumers (e.g., CLI) should invoke ready() after node.start().
|
|
48
|
+
}
|
|
49
|
+
async stop() {
|
|
50
|
+
this.running = false;
|
|
51
|
+
}
|
|
52
|
+
async ready() {
|
|
53
|
+
if (this.readyPromise)
|
|
54
|
+
return this.readyPromise;
|
|
55
|
+
this.readyPromise = (async () => {
|
|
56
|
+
const results = await Promise.allSettled((this.cfg.seedKeys ?? []).map(k => this.seedKey(k)));
|
|
57
|
+
const failures = results.filter(r => r.status === 'rejected');
|
|
58
|
+
if (failures.length > 0) {
|
|
59
|
+
this.log('Failed to seed %d keys', failures.length);
|
|
60
|
+
}
|
|
61
|
+
await new Promise(r => setTimeout(r, 50));
|
|
62
|
+
})();
|
|
63
|
+
return this.readyPromise;
|
|
64
|
+
}
|
|
65
|
+
async seedKey(key) {
|
|
66
|
+
const fret = this.getFret();
|
|
67
|
+
if (!fret) {
|
|
68
|
+
throw new Error('FRET service not available for seeding keys');
|
|
69
|
+
}
|
|
70
|
+
const coord = await hashKey(key);
|
|
71
|
+
const _neighbors = fret.getNeighbors(coord, 'both', 1);
|
|
72
|
+
}
|
|
73
|
+
toCacheKey(key) {
|
|
74
|
+
return Buffer.from(key).toString('base64url');
|
|
75
|
+
}
|
|
76
|
+
getKnownPeers() {
|
|
77
|
+
const libp2p = this.getLibp2p();
|
|
78
|
+
if (!libp2p) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
const selfId = libp2p.peerId;
|
|
82
|
+
const storePeers = libp2p.peerStore?.getPeers?.() ?? [];
|
|
83
|
+
const connPeers = (libp2p.getConnections?.() ?? []).map((c) => c.remotePeer);
|
|
84
|
+
const all = [...storePeers.map(p => p.id), ...connPeers];
|
|
85
|
+
const uniq = all.filter((p, i) => all.findIndex(x => x.toString() === p.toString()) === i);
|
|
86
|
+
return uniq.filter((pid) => pid.toString() !== selfId.toString());
|
|
87
|
+
}
|
|
88
|
+
getStatus() {
|
|
89
|
+
const libp2p = this.getLibp2p();
|
|
90
|
+
if (!libp2p) {
|
|
91
|
+
return { mode: this.cfg.expectedRemotes ? 'degraded' : 'alone', connections: 0 };
|
|
92
|
+
}
|
|
93
|
+
const peers = libp2p.peerStore?.getPeers?.() ?? [];
|
|
94
|
+
const remotes = peers.filter(p => p.id.toString() !== libp2p.peerId.toString()).length;
|
|
95
|
+
if (remotes === 0) {
|
|
96
|
+
return { mode: this.cfg.expectedRemotes ? 'degraded' : 'alone', connections: 0 };
|
|
97
|
+
}
|
|
98
|
+
return { mode: 'healthy', connections: remotes };
|
|
99
|
+
}
|
|
100
|
+
async awaitHealthy(minRemotes, timeoutMs) {
|
|
101
|
+
const start = Date.now();
|
|
102
|
+
while (Date.now() - start < timeoutMs) {
|
|
103
|
+
const libp2p = this.getLibp2p();
|
|
104
|
+
if (libp2p) {
|
|
105
|
+
// Require actual active connections, not just peerStore knowledge
|
|
106
|
+
const connections = libp2p.getConnections?.() ?? [];
|
|
107
|
+
const connectedPeers = new Set(connections.map((c) => c.remotePeer.toString()));
|
|
108
|
+
if (connectedPeers.size >= minRemotes) {
|
|
109
|
+
this.log('awaitHealthy: satisfied with %d connections', connectedPeers.size);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
await new Promise(r => setTimeout(r, 100));
|
|
114
|
+
}
|
|
115
|
+
// Final check
|
|
116
|
+
const libp2p = this.getLibp2p();
|
|
117
|
+
if (libp2p) {
|
|
118
|
+
const connections = libp2p.getConnections?.() ?? [];
|
|
119
|
+
const connectedPeers = new Set(connections.map((c) => c.remotePeer.toString()));
|
|
120
|
+
const satisfied = connectedPeers.size >= minRemotes;
|
|
121
|
+
this.log('awaitHealthy: timeout - %d connections (needed %d)', connectedPeers.size, minRemotes);
|
|
122
|
+
return satisfied;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Record a misbehaving peer. Higher score means worse reputation.
|
|
128
|
+
* Entries expire to allow eventual forgiveness.
|
|
129
|
+
*/
|
|
130
|
+
reportBadPeer(peerId, penalty = 1, ttlMs = 10 * 60_000) {
|
|
131
|
+
const id = peerId.toString();
|
|
132
|
+
const prev = this.blacklist.get(id);
|
|
133
|
+
const score = (prev?.score ?? 0) + Math.max(1, penalty);
|
|
134
|
+
this.blacklist.set(id, { score, expires: Date.now() + ttlMs });
|
|
135
|
+
}
|
|
136
|
+
isBlacklisted(peerId) {
|
|
137
|
+
const id = peerId.toString();
|
|
138
|
+
const rec = this.blacklist.get(id);
|
|
139
|
+
if (!rec)
|
|
140
|
+
return false;
|
|
141
|
+
if (rec.expires <= Date.now()) {
|
|
142
|
+
this.blacklist.delete(id);
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
// simple threshold; can be tuned or exposed later
|
|
146
|
+
return rec.score >= 3;
|
|
147
|
+
}
|
|
148
|
+
recordCoordinator(key, peerId) {
|
|
149
|
+
const k = this.toCacheKey(key);
|
|
150
|
+
this.coordinatorCache.set(k, { id: peerId, expires: Date.now() + this.cfg.cacheTTLs.coordinatorMs });
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Find the nearest peer to the provided content key using FRET,
|
|
154
|
+
* falling back to self if FRET is unavailable.
|
|
155
|
+
*/
|
|
156
|
+
async findNearestPeerToKey(key) {
|
|
157
|
+
const fret = this.getFret();
|
|
158
|
+
const libp2p = this.getLibp2p();
|
|
159
|
+
if (!libp2p) {
|
|
160
|
+
throw new Error('Libp2p not initialized');
|
|
161
|
+
}
|
|
162
|
+
if (fret) {
|
|
163
|
+
const coord = await hashKey(key);
|
|
164
|
+
const neighbors = fret.getNeighbors(coord, 'both', 1);
|
|
165
|
+
if (neighbors.length > 0) {
|
|
166
|
+
const pidStr = neighbors[0];
|
|
167
|
+
if (pidStr) {
|
|
168
|
+
const { peerIdFromString } = await import('@libp2p/peer-id');
|
|
169
|
+
const pid = peerIdFromString(pidStr);
|
|
170
|
+
if (!this.isBlacklisted(pid)) {
|
|
171
|
+
return pid;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Fallback: choose among self + connected peers + known peers by distance to key
|
|
177
|
+
const connected = (libp2p.getConnections?.() ?? []).map((c) => c.remotePeer);
|
|
178
|
+
const candidates = [libp2p.peerId, ...connected, ...this.getKnownPeers()]
|
|
179
|
+
.filter((p, i, arr) => arr.findIndex(x => x.toString() === p.toString()) === i)
|
|
180
|
+
.filter(p => !this.isBlacklisted(p));
|
|
181
|
+
if (candidates.length === 0) {
|
|
182
|
+
return libp2p.peerId;
|
|
183
|
+
}
|
|
184
|
+
const best = candidates.reduce((best, cur) => this.lexLess(this.xor(best.toMultihash().bytes, key), this.xor(cur.toMultihash().bytes, key)) ? best : cur, candidates[0]);
|
|
185
|
+
return best;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Compute cluster using FRET's assembleCohort for content-addressed peer selection.
|
|
189
|
+
*/
|
|
190
|
+
async getCluster(key) {
|
|
191
|
+
const ck = this.toCacheKey(key);
|
|
192
|
+
const cached = this.clusterCache.get(ck);
|
|
193
|
+
if (cached && cached.expires > Date.now()) {
|
|
194
|
+
return cached.ids;
|
|
195
|
+
}
|
|
196
|
+
const fret = this.getFret();
|
|
197
|
+
const libp2p = this.getLibp2p();
|
|
198
|
+
if (!libp2p) {
|
|
199
|
+
throw new Error('Libp2p not initialized');
|
|
200
|
+
}
|
|
201
|
+
if (fret) {
|
|
202
|
+
const coord = await hashKey(key);
|
|
203
|
+
const diag = fret.getDiagnostics?.() ?? {};
|
|
204
|
+
const estimate = typeof diag.estimate === 'number' ? diag.estimate : (typeof diag.n === 'number' ? diag.n : undefined);
|
|
205
|
+
const targetSize = Math.max(1, Math.min(this.cfg.clusterSize, Number.isFinite(estimate) ? estimate : this.cfg.clusterSize));
|
|
206
|
+
const cohortIds = fret.assembleCohort(coord, targetSize);
|
|
207
|
+
const { peerIdFromString } = await import('@libp2p/peer-id');
|
|
208
|
+
const ids = cohortIds
|
|
209
|
+
.map(idStr => {
|
|
210
|
+
try {
|
|
211
|
+
return peerIdFromString(idStr);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
this.log('Invalid peer ID in cohort: %s, %o', idStr, error);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
.filter((pid) => pid !== null && !this.isBlacklisted(pid));
|
|
219
|
+
if (ids.length > 0) {
|
|
220
|
+
this.clusterCache.set(ck, { ids, expires: Date.now() + this.cfg.cacheTTLs.clusterMs });
|
|
221
|
+
this.lastEstimate = estimate != null ? { estimate, samples: diag.samples ?? 0, updated: Date.now() } : this.lastEstimate;
|
|
222
|
+
return ids;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Fallback: peer-centric clustering if FRET unavailable
|
|
226
|
+
const anchor = await this.findNearestPeerToKey(key);
|
|
227
|
+
const anchorMh = anchor.toMultihash().bytes;
|
|
228
|
+
const connected = (libp2p.getConnections?.() ?? []).map((c) => c.remotePeer);
|
|
229
|
+
const candidates = [anchor, libp2p.peerId, ...connected, ...this.getKnownPeers()]
|
|
230
|
+
.filter((p, idx, arr) => !this.isBlacklisted(p) && arr.findIndex(x => x.toString() === p.toString()) === idx);
|
|
231
|
+
const sorted = candidates.sort((a, b) => this.lexLess(this.xor(a.toMultihash().bytes, anchorMh), this.xor(b.toMultihash().bytes, anchorMh)) ? -1 : 1);
|
|
232
|
+
const K = Math.min(this.cfg.clusterSize, sorted.length);
|
|
233
|
+
const ids = sorted.slice(0, K);
|
|
234
|
+
this.clusterCache.set(ck, { ids, expires: Date.now() + this.cfg.cacheTTLs.clusterMs });
|
|
235
|
+
return ids;
|
|
236
|
+
}
|
|
237
|
+
async getCoordinator(key) {
|
|
238
|
+
const ck = this.toCacheKey(key);
|
|
239
|
+
const hit = this.coordinatorCache.get(ck);
|
|
240
|
+
if (hit) {
|
|
241
|
+
if (hit.expires > Date.now()) {
|
|
242
|
+
return hit.id;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
this.coordinatorCache.delete(ck);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const cluster = await this.getCluster(key);
|
|
249
|
+
const libp2p = this.getLibp2p();
|
|
250
|
+
if (!libp2p) {
|
|
251
|
+
throw new Error('Libp2p not initialized');
|
|
252
|
+
}
|
|
253
|
+
const candidate = cluster.find(p => !this.isBlacklisted(p)) ?? libp2p.peerId;
|
|
254
|
+
this.recordCoordinator(key, candidate);
|
|
255
|
+
return candidate;
|
|
256
|
+
}
|
|
257
|
+
xor(a, b) {
|
|
258
|
+
const len = Math.max(a.length, b.length);
|
|
259
|
+
const out = new Uint8Array(len);
|
|
260
|
+
for (let i = 0; i < len; i++) {
|
|
261
|
+
const ai = a[a.length - 1 - i] ?? 0;
|
|
262
|
+
const bi = b[b.length - 1 - i] ?? 0;
|
|
263
|
+
out[len - 1 - i] = ai ^ bi;
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
lexLess(a, b) {
|
|
268
|
+
const len = Math.max(a.length, b.length);
|
|
269
|
+
for (let i = 0; i < len; i++) {
|
|
270
|
+
const av = a[i] ?? 0;
|
|
271
|
+
const bv = b[i] ?? 0;
|
|
272
|
+
if (av < bv)
|
|
273
|
+
return true;
|
|
274
|
+
if (av > bv)
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export function networkManagerService(init = {}) {
|
|
281
|
+
return (components) => new NetworkManagerService(components, init);
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=network-manager-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-manager-service.js","sourceRoot":"","sources":["../../../src/network/network-manager-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-utils.d.ts","sourceRoot":"","sources":["../../src/peer-utils.ts"],"names":[],"mappings":"AAiBA,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAI1D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function toPeerIdString(id) {
|
|
2
|
+
try {
|
|
3
|
+
if (id == null)
|
|
4
|
+
return null;
|
|
5
|
+
// PeerId instance
|
|
6
|
+
if (typeof id?.toString === 'function')
|
|
7
|
+
return id.toString();
|
|
8
|
+
// Wrapped object { id: PeerId | string }
|
|
9
|
+
const inner = id.id;
|
|
10
|
+
if (inner && typeof inner.toString === 'function')
|
|
11
|
+
return inner.toString();
|
|
12
|
+
if (typeof inner === 'string')
|
|
13
|
+
return inner;
|
|
14
|
+
// Raw string
|
|
15
|
+
if (typeof id === 'string')
|
|
16
|
+
return id;
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function peersEqual(a, b) {
|
|
24
|
+
const as = toPeerIdString(a);
|
|
25
|
+
const bs = toPeerIdString(b);
|
|
26
|
+
return as != null && bs != null && as === bs;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=peer-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-utils.js","sourceRoot":"","sources":["../../src/peer-utils.ts"],"names":[],"mappings":"AAAA,SAAS,cAAc,CAAC,EAAW;IAClC,IAAI,CAAC;QACJ,IAAI,EAAE,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;QAC3B,kBAAkB;QAClB,IAAI,OAAQ,EAAU,EAAE,QAAQ,KAAK,UAAU;YAAE,OAAQ,EAAU,CAAC,QAAQ,EAAE,CAAA;QAC9E,yCAAyC;QACzC,MAAM,KAAK,GAAI,EAAU,CAAC,EAAE,CAAA;QAC5B,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAA;QAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QAC3C,aAAa;QACb,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAA;QACrC,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAA;IACZ,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAU,EAAE,CAAU;IAChD,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAAA;IAC5B,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAAA;IAC5B,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,KAAK,EAAE,CAAA;AAC7C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PeerId } from '@libp2p/interface';
|
|
2
|
+
import type { IPeerNetwork } from '@optimystic/db-core';
|
|
3
|
+
/** Base class for clients that communicate via a libp2p protocol */
|
|
4
|
+
export declare class ProtocolClient {
|
|
5
|
+
protected readonly peerId: PeerId;
|
|
6
|
+
protected readonly peerNetwork: IPeerNetwork;
|
|
7
|
+
constructor(peerId: PeerId, peerNetwork: IPeerNetwork);
|
|
8
|
+
protected processMessage<T>(message: unknown, protocol: string, options?: {
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}): Promise<T>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=protocol-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-client.d.ts","sourceRoot":"","sources":["../../src/protocol-client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,oEAAoE;AACpE,qBAAa,cAAc;IAEzB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACjC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY;gBADzB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,YAAY;cAG7B,cAAc,CAAC,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAChC,OAAO,CAAC,CAAC,CAAC;CAmCb"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { pipe } from 'it-pipe';
|
|
2
|
+
import { encode as lpEncode, decode as lpDecode } from 'it-length-prefixed';
|
|
3
|
+
import { pushable } from 'it-pushable';
|
|
4
|
+
import { first } from './it-utility.js';
|
|
5
|
+
/** Base class for clients that communicate via a libp2p protocol */
|
|
6
|
+
export class ProtocolClient {
|
|
7
|
+
peerId;
|
|
8
|
+
peerNetwork;
|
|
9
|
+
constructor(peerId, peerNetwork) {
|
|
10
|
+
this.peerId = peerId;
|
|
11
|
+
this.peerNetwork = peerNetwork;
|
|
12
|
+
}
|
|
13
|
+
async processMessage(message, protocol, options) {
|
|
14
|
+
const stream = await this.peerNetwork.connect(this.peerId, protocol, { signal: options?.signal });
|
|
15
|
+
try {
|
|
16
|
+
const source = pipe(stream.source, lpDecode, async function* (source) {
|
|
17
|
+
for await (const data of source) {
|
|
18
|
+
const decoded = new TextDecoder().decode(data.subarray());
|
|
19
|
+
const parsed = JSON.parse(decoded);
|
|
20
|
+
yield parsed;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const sink = pushable();
|
|
24
|
+
void pipe(sink, lpEncode, stream.sink);
|
|
25
|
+
sink.push(new TextEncoder().encode(JSON.stringify(message)));
|
|
26
|
+
sink.end();
|
|
27
|
+
return await first(() => source, () => { throw new Error('No response received'); });
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
stream.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=protocol-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-client.js","sourceRoot":"","sources":["../../src/protocol-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,oEAAoE;AACpE,MAAM,OAAO,cAAc;IAEN;IACA;IAFpB,YACoB,MAAc,EACd,WAAyB;QADzB,WAAM,GAAN,MAAM,CAAQ;QACd,gBAAW,GAAX,WAAW,CAAc;IACzC,CAAC;IAEK,KAAK,CAAC,cAAc,CAC7B,OAAgB,EAChB,QAAgB,EAChB,OAAkC;QAElC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAC5C,IAAI,CAAC,MAAM,EACX,QAAQ,EACR,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAC3B,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,CAClB,MAAM,CAAC,MAAM,EACb,QAAQ,EACR,KAAK,SAAS,CAAC,EAAE,MAAM;gBACtB,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBACjC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACnC,MAAM,MAAM,CAAC;gBACd,CAAC;YACF,CAAC,CACmB,CAAC;YAEtB,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;YACxB,KAAK,IAAI,CACR,IAAI,EACJ,QAAQ,EACR,MAAM,CAAC,IAAI,CACX,CAAC;YAEF,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7D,IAAI,CAAC,GAAG,EAAE,CAAC;YAEX,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;gBAAS,CAAC;YACV,MAAM,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;IACF,CAAC;CACD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IRepo, GetBlockResults, PendSuccess, StaleFailure, ActionBlocks, MessageOptions, CommitResult, PendRequest, CommitRequest, BlockGets, IPeerNetwork } from "@optimystic/db-core";
|
|
2
|
+
import type { PeerId } from "@libp2p/interface";
|
|
3
|
+
import { ProtocolClient } from "../protocol-client.js";
|
|
4
|
+
export declare class RepoClient extends ProtocolClient implements IRepo {
|
|
5
|
+
readonly protocolPrefix?: string | undefined;
|
|
6
|
+
private constructor();
|
|
7
|
+
/** Create a new client instance */
|
|
8
|
+
static create(peerId: PeerId, peerNetwork: IPeerNetwork, protocolPrefix?: string): RepoClient;
|
|
9
|
+
get(blockGets: BlockGets, options: MessageOptions): Promise<GetBlockResults>;
|
|
10
|
+
pend(request: PendRequest, options: MessageOptions): Promise<PendSuccess | StaleFailure>;
|
|
11
|
+
cancel(actionRef: ActionBlocks, options: MessageOptions): Promise<void>;
|
|
12
|
+
commit(request: CommitRequest, options: MessageOptions): Promise<CommitResult>;
|
|
13
|
+
private processRepoMessage;
|
|
14
|
+
private extractKeyFromOperations;
|
|
15
|
+
private recordCoordinatorForOpsIfSupported;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAC7F,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EACnD,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qBAAa,UAAW,SAAQ,cAAe,YAAW,KAAK;IACC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9F,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAO5E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC;IAOxF,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;YAOtE,kBAAkB;IAwChC,OAAO,CAAC,wBAAwB;IAgBhC,OAAO,CAAC,kCAAkC;CAQ1C"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ProtocolClient } from "../protocol-client.js";
|
|
2
|
+
import { peerIdFromString } from "@libp2p/peer-id";
|
|
3
|
+
export class RepoClient extends ProtocolClient {
|
|
4
|
+
protocolPrefix;
|
|
5
|
+
constructor(peerId, peerNetwork, protocolPrefix) {
|
|
6
|
+
super(peerId, peerNetwork);
|
|
7
|
+
this.protocolPrefix = protocolPrefix;
|
|
8
|
+
}
|
|
9
|
+
/** Create a new client instance */
|
|
10
|
+
static create(peerId, peerNetwork, protocolPrefix) {
|
|
11
|
+
return new RepoClient(peerId, peerNetwork, protocolPrefix);
|
|
12
|
+
}
|
|
13
|
+
async get(blockGets, options) {
|
|
14
|
+
return this.processRepoMessage([{ get: blockGets }], options);
|
|
15
|
+
}
|
|
16
|
+
async pend(request, options) {
|
|
17
|
+
return this.processRepoMessage([{ pend: request }], options);
|
|
18
|
+
}
|
|
19
|
+
async cancel(actionRef, options) {
|
|
20
|
+
return this.processRepoMessage([{ cancel: { actionRef } }], options);
|
|
21
|
+
}
|
|
22
|
+
async commit(request, options) {
|
|
23
|
+
return this.processRepoMessage([{ commit: request }], options);
|
|
24
|
+
}
|
|
25
|
+
async processRepoMessage(operations, options, hop = 0) {
|
|
26
|
+
const message = {
|
|
27
|
+
operations,
|
|
28
|
+
expiration: options.expiration,
|
|
29
|
+
};
|
|
30
|
+
const deadline = options.expiration ?? (Date.now() + 30_000);
|
|
31
|
+
const msLeft = Math.max(1, deadline - Date.now());
|
|
32
|
+
const withTimeout = async (fn) => {
|
|
33
|
+
return await Promise.race([
|
|
34
|
+
fn(),
|
|
35
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('RepoClient timeout')), msLeft))
|
|
36
|
+
]);
|
|
37
|
+
};
|
|
38
|
+
let response;
|
|
39
|
+
const preferred = (this.protocolPrefix ?? '/db-p2p') + '/repo/1.0.0';
|
|
40
|
+
response = await withTimeout(() => super.processMessage(message, preferred, { signal: options?.signal }));
|
|
41
|
+
if (response?.redirect?.peers?.length) {
|
|
42
|
+
if (hop >= 2) {
|
|
43
|
+
throw new Error('Redirect loop detected in RepoClient (max hops reached)');
|
|
44
|
+
}
|
|
45
|
+
const currentIdStr = this.peerId.toString();
|
|
46
|
+
const next = response.redirect.peers.find((p) => p.id !== currentIdStr) ?? response.redirect.peers[0];
|
|
47
|
+
const nextId = peerIdFromString(next.id);
|
|
48
|
+
if (next.id === currentIdStr) {
|
|
49
|
+
throw new Error('Redirect loop detected in RepoClient (same peer)');
|
|
50
|
+
}
|
|
51
|
+
// cache hint
|
|
52
|
+
this.recordCoordinatorForOpsIfSupported(operations, nextId);
|
|
53
|
+
// single-hop retry against target peer using repo protocol
|
|
54
|
+
const nextClient = RepoClient.create(nextId, this.peerNetwork, this.protocolPrefix);
|
|
55
|
+
return await nextClient.processRepoMessage(operations, options, hop + 1);
|
|
56
|
+
}
|
|
57
|
+
return response;
|
|
58
|
+
}
|
|
59
|
+
extractKeyFromOperations(ops) {
|
|
60
|
+
const op = ops[0];
|
|
61
|
+
if ('get' in op) {
|
|
62
|
+
const id = op.get.blockIds[0];
|
|
63
|
+
return id ? new TextEncoder().encode(id) : undefined;
|
|
64
|
+
}
|
|
65
|
+
if ('pend' in op) {
|
|
66
|
+
const id = Object.keys(op.pend.transforms)[0];
|
|
67
|
+
return id ? new TextEncoder().encode(id) : undefined;
|
|
68
|
+
}
|
|
69
|
+
if ('commit' in op) {
|
|
70
|
+
return new TextEncoder().encode(op.commit.tailId);
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
recordCoordinatorForOpsIfSupported(ops, peerId) {
|
|
75
|
+
const keyBytes = this.extractKeyFromOperations(ops);
|
|
76
|
+
const pn = this.peerNetwork;
|
|
77
|
+
if (keyBytes != null && typeof pn?.recordCoordinator === 'function') {
|
|
78
|
+
pn.recordCoordinator(keyBytes, peerId);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"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"}
|