@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,59 @@
|
|
|
1
|
+
export interface PeerStatus {
|
|
2
|
+
peerId: string;
|
|
3
|
+
lastSeen: number;
|
|
4
|
+
lastGoodbye?: number;
|
|
5
|
+
consecutiveFailures: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Detects potential network partitions by tracking peer health,
|
|
9
|
+
* goodbye messages, and sudden mass unreachability events.
|
|
10
|
+
*/
|
|
11
|
+
export declare class PartitionDetector {
|
|
12
|
+
private peerStatuses;
|
|
13
|
+
private readonly unreachableThreshold;
|
|
14
|
+
private readonly rapidChurnThreshold;
|
|
15
|
+
private readonly rapidChurnWindow;
|
|
16
|
+
private readonly peerTimeoutMs;
|
|
17
|
+
/**
|
|
18
|
+
* Record successful communication with a peer
|
|
19
|
+
*/
|
|
20
|
+
recordSuccess(peerId: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Record failed communication attempt with a peer
|
|
23
|
+
*/
|
|
24
|
+
recordFailure(peerId: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Record explicit goodbye message from a peer
|
|
27
|
+
*/
|
|
28
|
+
recordGoodbye(peerId: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Detect if we're likely in a network partition
|
|
31
|
+
* Returns true if sudden mass unreachability or rapid goodbye rate
|
|
32
|
+
*/
|
|
33
|
+
detectPartition(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Get list of currently unreachable peers
|
|
36
|
+
*/
|
|
37
|
+
getUnreachablePeers(): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Get recent goodbye messages within the specified window
|
|
40
|
+
*/
|
|
41
|
+
private getRecentGoodbyes;
|
|
42
|
+
/**
|
|
43
|
+
* Clean up peer records that haven't been seen recently
|
|
44
|
+
*/
|
|
45
|
+
private cleanupOldPeers;
|
|
46
|
+
/**
|
|
47
|
+
* Get statistics for monitoring
|
|
48
|
+
*/
|
|
49
|
+
getStatistics(): {
|
|
50
|
+
totalPeers: number;
|
|
51
|
+
unreachable: number;
|
|
52
|
+
recentGoodbyes: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Reset all tracked peer states (useful for testing)
|
|
56
|
+
*/
|
|
57
|
+
reset(): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=partition-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partition-detector.d.ts","sourceRoot":"","sources":["../../../src/cluster/partition-detector.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,YAAY,CAAsC;IAC1D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAK;IAC1C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAK;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAmBnC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgBnC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiBnC;;;OAGG;IACH,eAAe,IAAI,OAAO;IAkB1B;;OAEG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAM/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,aAAa,IAAI;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACvB;IAWD;;OAEG;IACH,KAAK,IAAI,IAAI;CAGb"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects potential network partitions by tracking peer health,
|
|
3
|
+
* goodbye messages, and sudden mass unreachability events.
|
|
4
|
+
*/
|
|
5
|
+
export class PartitionDetector {
|
|
6
|
+
peerStatuses = new Map();
|
|
7
|
+
unreachableThreshold = 3; // consecutive failures
|
|
8
|
+
rapidChurnThreshold = 5; // peers
|
|
9
|
+
rapidChurnWindow = 10000; // 10 seconds
|
|
10
|
+
peerTimeoutMs = 60000; // 1 minute
|
|
11
|
+
/**
|
|
12
|
+
* Record successful communication with a peer
|
|
13
|
+
*/
|
|
14
|
+
recordSuccess(peerId) {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
const status = this.peerStatuses.get(peerId);
|
|
17
|
+
if (status) {
|
|
18
|
+
status.lastSeen = now;
|
|
19
|
+
status.consecutiveFailures = 0;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this.peerStatuses.set(peerId, {
|
|
23
|
+
peerId,
|
|
24
|
+
lastSeen: now,
|
|
25
|
+
consecutiveFailures: 0
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// Clean up old peer records
|
|
29
|
+
this.cleanupOldPeers();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Record failed communication attempt with a peer
|
|
33
|
+
*/
|
|
34
|
+
recordFailure(peerId) {
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
const status = this.peerStatuses.get(peerId);
|
|
37
|
+
if (status) {
|
|
38
|
+
status.consecutiveFailures++;
|
|
39
|
+
status.lastSeen = now;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.peerStatuses.set(peerId, {
|
|
43
|
+
peerId,
|
|
44
|
+
lastSeen: now,
|
|
45
|
+
consecutiveFailures: 1
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Record explicit goodbye message from a peer
|
|
51
|
+
*/
|
|
52
|
+
recordGoodbye(peerId) {
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
const status = this.peerStatuses.get(peerId);
|
|
55
|
+
if (status) {
|
|
56
|
+
status.lastGoodbye = now;
|
|
57
|
+
status.lastSeen = now;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.peerStatuses.set(peerId, {
|
|
61
|
+
peerId,
|
|
62
|
+
lastSeen: now,
|
|
63
|
+
lastGoodbye: now,
|
|
64
|
+
consecutiveFailures: 0
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Detect if we're likely in a network partition
|
|
70
|
+
* Returns true if sudden mass unreachability or rapid goodbye rate
|
|
71
|
+
*/
|
|
72
|
+
detectPartition() {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
// Count recent goodbyes
|
|
75
|
+
const recentGoodbyes = this.getRecentGoodbyes(this.rapidChurnWindow);
|
|
76
|
+
// Count unreachable peers
|
|
77
|
+
const unreachable = Array.from(this.peerStatuses.values()).filter(s => s.consecutiveFailures >= this.unreachableThreshold
|
|
78
|
+
&& !s.lastGoodbye // Exclude peers that said goodbye
|
|
79
|
+
);
|
|
80
|
+
// Sudden mass unreachability suggests partition
|
|
81
|
+
const totalChurn = recentGoodbyes.length + unreachable.length;
|
|
82
|
+
return totalChurn >= this.rapidChurnThreshold;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get list of currently unreachable peers
|
|
86
|
+
*/
|
|
87
|
+
getUnreachablePeers() {
|
|
88
|
+
return Array.from(this.peerStatuses.values())
|
|
89
|
+
.filter(s => s.consecutiveFailures >= this.unreachableThreshold && !s.lastGoodbye)
|
|
90
|
+
.map(s => s.peerId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get recent goodbye messages within the specified window
|
|
94
|
+
*/
|
|
95
|
+
getRecentGoodbyes(windowMs) {
|
|
96
|
+
const cutoff = Date.now() - windowMs;
|
|
97
|
+
return Array.from(this.peerStatuses.values()).filter(s => s.lastGoodbye && s.lastGoodbye > cutoff);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clean up peer records that haven't been seen recently
|
|
101
|
+
*/
|
|
102
|
+
cleanupOldPeers() {
|
|
103
|
+
const cutoff = Date.now() - this.peerTimeoutMs;
|
|
104
|
+
for (const [peerId, status] of this.peerStatuses.entries()) {
|
|
105
|
+
if (status.lastSeen < cutoff) {
|
|
106
|
+
this.peerStatuses.delete(peerId);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get statistics for monitoring
|
|
112
|
+
*/
|
|
113
|
+
getStatistics() {
|
|
114
|
+
const unreachable = this.getUnreachablePeers().length;
|
|
115
|
+
const recentGoodbyes = this.getRecentGoodbyes(this.rapidChurnWindow).length;
|
|
116
|
+
return {
|
|
117
|
+
totalPeers: this.peerStatuses.size,
|
|
118
|
+
unreachable,
|
|
119
|
+
recentGoodbyes
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Reset all tracked peer states (useful for testing)
|
|
124
|
+
*/
|
|
125
|
+
reset() {
|
|
126
|
+
this.peerStatuses.clear();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=partition-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partition-detector.js","sourceRoot":"","sources":["../../../src/cluster/partition-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Startable, Logger, IncomingStreamData } from '@libp2p/interface';
|
|
2
|
+
import type { ICluster } from '@optimystic/db-core';
|
|
3
|
+
interface BaseComponents {
|
|
4
|
+
logger: {
|
|
5
|
+
forComponent: (name: string) => Logger;
|
|
6
|
+
};
|
|
7
|
+
registrar: {
|
|
8
|
+
handle: (protocol: string, handler: (data: IncomingStreamData) => void, options: any) => Promise<void>;
|
|
9
|
+
unhandle: (protocol: string) => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface ClusterServiceComponents extends BaseComponents {
|
|
13
|
+
cluster: ICluster;
|
|
14
|
+
}
|
|
15
|
+
export interface ClusterServiceInit {
|
|
16
|
+
protocol?: string;
|
|
17
|
+
protocolPrefix?: string;
|
|
18
|
+
maxInboundStreams?: number;
|
|
19
|
+
maxOutboundStreams?: number;
|
|
20
|
+
logPrefix?: string;
|
|
21
|
+
kBucketSize?: number;
|
|
22
|
+
configuredClusterSize?: number;
|
|
23
|
+
allowClusterDownsize?: boolean;
|
|
24
|
+
clusterSizeTolerance?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function clusterService(init?: ClusterServiceInit): (components: ClusterServiceComponents) => ClusterService;
|
|
27
|
+
/**
|
|
28
|
+
* A libp2p service that handles cluster protocol messages
|
|
29
|
+
*/
|
|
30
|
+
export declare class ClusterService implements Startable {
|
|
31
|
+
private readonly protocol;
|
|
32
|
+
private readonly maxInboundStreams;
|
|
33
|
+
private readonly maxOutboundStreams;
|
|
34
|
+
private readonly log;
|
|
35
|
+
private readonly cluster;
|
|
36
|
+
private readonly components;
|
|
37
|
+
private running;
|
|
38
|
+
private readonly k;
|
|
39
|
+
private readonly configuredClusterSize;
|
|
40
|
+
private readonly allowDownsize;
|
|
41
|
+
private readonly sizeTolerance;
|
|
42
|
+
constructor(components: ClusterServiceComponents, init?: ClusterServiceInit);
|
|
43
|
+
readonly [Symbol.toStringTag] = "@libp2p/cluster";
|
|
44
|
+
start(): Promise<void>;
|
|
45
|
+
stop(): Promise<void>;
|
|
46
|
+
private handleIncomingStream;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/cluster/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,qBAAqB,CAAC;AAOnE,UAAU,cAAc;IACvB,MAAM,EAAE;QAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,CAAC;IACnD,SAAS,EAAE;QACV,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACvG,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAC7C,CAAA;CACD;AAED,MAAM,WAAW,wBAAyB,SAAQ,cAAc;IAC/D,OAAO,EAAE,QAAQ,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,IAAI,GAAE,kBAAuB,GAAG,CAAC,UAAU,EAAE,wBAAwB,KAAK,cAAc,CAEtH;AAED;;GAEG;AACH,qBAAa,cAAe,YAAW,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,OAAO,CAAU;IACxB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE5B,UAAU,EAAE,wBAAwB,EAAE,IAAI,GAAE,kBAAuB;IAc/E,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,qBAAqB;IAE5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,oBAAoB;CA+D5B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { pipe } from 'it-pipe';
|
|
2
|
+
import { decode as lpDecode, encode as lpEncode } from 'it-length-prefixed';
|
|
3
|
+
export function clusterService(init = {}) {
|
|
4
|
+
return (components) => new ClusterService(components, init);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A libp2p service that handles cluster protocol messages
|
|
8
|
+
*/
|
|
9
|
+
export class ClusterService {
|
|
10
|
+
protocol;
|
|
11
|
+
maxInboundStreams;
|
|
12
|
+
maxOutboundStreams;
|
|
13
|
+
log;
|
|
14
|
+
cluster;
|
|
15
|
+
components;
|
|
16
|
+
running;
|
|
17
|
+
k;
|
|
18
|
+
configuredClusterSize;
|
|
19
|
+
allowDownsize;
|
|
20
|
+
sizeTolerance;
|
|
21
|
+
constructor(components, init = {}) {
|
|
22
|
+
this.components = components;
|
|
23
|
+
this.protocol = init.protocol ?? (init.protocolPrefix ?? '/db-p2p') + '/cluster/1.0.0';
|
|
24
|
+
this.maxInboundStreams = init.maxInboundStreams ?? 32;
|
|
25
|
+
this.maxOutboundStreams = init.maxOutboundStreams ?? 64;
|
|
26
|
+
this.log = components.logger.forComponent(init.logPrefix ?? 'db-p2p:cluster');
|
|
27
|
+
this.cluster = components.cluster;
|
|
28
|
+
this.running = false;
|
|
29
|
+
this.k = init.kBucketSize ?? 10;
|
|
30
|
+
this.configuredClusterSize = init.configuredClusterSize ?? 10;
|
|
31
|
+
this.allowDownsize = init.allowClusterDownsize ?? true;
|
|
32
|
+
this.sizeTolerance = init.clusterSizeTolerance ?? 0.5;
|
|
33
|
+
}
|
|
34
|
+
[Symbol.toStringTag] = '@libp2p/cluster';
|
|
35
|
+
async start() {
|
|
36
|
+
if (this.running) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await this.components.registrar.handle(this.protocol, this.handleIncomingStream.bind(this), {
|
|
40
|
+
maxInboundStreams: this.maxInboundStreams,
|
|
41
|
+
maxOutboundStreams: this.maxOutboundStreams
|
|
42
|
+
});
|
|
43
|
+
this.running = true;
|
|
44
|
+
}
|
|
45
|
+
async stop() {
|
|
46
|
+
if (!this.running) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
await this.components.registrar.unhandle(this.protocol);
|
|
50
|
+
this.running = false;
|
|
51
|
+
}
|
|
52
|
+
handleIncomingStream(data) {
|
|
53
|
+
const { stream, connection } = data;
|
|
54
|
+
const peerId = connection.remotePeer;
|
|
55
|
+
const processStream = async function* (source) {
|
|
56
|
+
for await (const msg of source) {
|
|
57
|
+
// Decode the message
|
|
58
|
+
const decoded = new TextDecoder().decode(msg.subarray());
|
|
59
|
+
const message = JSON.parse(decoded);
|
|
60
|
+
// Process the operation
|
|
61
|
+
let response;
|
|
62
|
+
if (message.operation === 'update') {
|
|
63
|
+
// Use message.record.message as key source; this is RepoMessage carrying block IDs
|
|
64
|
+
const tailId = (message.record?.message?.commit?.tailId ?? message.record?.message?.pend) ? Object.keys(message.record.message.pend.transforms)[0] : undefined;
|
|
65
|
+
// TEMPORARY: Disable cluster membership check to fix empty promises issue
|
|
66
|
+
// The membership check was causing peers to return redirect responses
|
|
67
|
+
// instead of processing cluster updates, leading to empty promise arrays.
|
|
68
|
+
// TODO: Re-enable and fix cluster membership logic for proper DHT routing
|
|
69
|
+
response = await this.cluster.update(message.record);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error(`Unknown operation: ${message.operation}`);
|
|
73
|
+
}
|
|
74
|
+
// Encode and yield the response
|
|
75
|
+
if (message.operation === 'update') {
|
|
76
|
+
const rec = response;
|
|
77
|
+
this.log('cluster-service:pre-serialize', {
|
|
78
|
+
messageHash: rec?.messageHash,
|
|
79
|
+
responseType: typeof response,
|
|
80
|
+
hasPromises: 'promises' in (rec ?? {}),
|
|
81
|
+
hasCommits: 'commits' in (rec ?? {}),
|
|
82
|
+
promiseKeys: Object.keys(rec?.promises ?? {}),
|
|
83
|
+
commitKeys: Object.keys(rec?.commits ?? {}),
|
|
84
|
+
promiseValues: rec?.promises,
|
|
85
|
+
commitValues: rec?.commits
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const serialized = JSON.stringify(response);
|
|
89
|
+
if (message.operation === 'update') {
|
|
90
|
+
const deserialized = JSON.parse(serialized);
|
|
91
|
+
this.log('cluster-service:post-serialize', {
|
|
92
|
+
messageHash: deserialized?.messageHash,
|
|
93
|
+
promiseKeys: Object.keys(deserialized?.promises ?? {}),
|
|
94
|
+
commitKeys: Object.keys(deserialized?.commits ?? {})
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
yield new TextEncoder().encode(serialized);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
Promise.resolve().then(async () => {
|
|
101
|
+
await pipe(stream, (source) => lpDecode(source), processStream.bind(this), (source) => lpEncode(source), stream);
|
|
102
|
+
}).catch((err) => {
|
|
103
|
+
this.log.error('error handling cluster protocol message from %p - %e', peerId, err);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/cluster/service.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;AAiC5E,MAAM,UAAU,cAAc,CAAC,OAA2B,EAAE;IAC3D,OAAO,CAAC,UAAoC,EAAE,EAAE,CAAC,IAAI,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACvF,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,QAAQ,CAAS;IACjB,iBAAiB,CAAS;IAC1B,kBAAkB,CAAS;IAC3B,GAAG,CAAS;IACZ,OAAO,CAAW;IAClB,UAAU,CAA2B;IAC9C,OAAO,CAAU;IACP,CAAC,CAAS;IACV,qBAAqB,CAAS;IAC9B,aAAa,CAAU;IACvB,aAAa,CAAS;IAExC,YAAY,UAAoC,EAAE,OAA2B,EAAE;QAC9E,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,GAAG,gBAAgB,CAAC;QACvF,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC;QACxD,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC,CAAC;QAC9E,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,IAAI,EAAE,CAAC;QAC9D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC;QACvD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC;IACzD,CAAC;IAEQ,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,iBAAiB,CAAC;IAElD,KAAK,CAAC,KAAK;QACV,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO;QACR,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC3F,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC3C,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,IAAI;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO;QACR,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEO,oBAAoB,CAAC,IAAwB;QACpD,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QACpC,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC;QAErC,MAAM,aAAa,GAAG,KAAK,SAAS,CAAC,EAAwB,MAAqC;YACjG,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;gBAChC,qBAAqB;gBACrB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACzD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiD,CAAC;gBAEpF,wBAAwB;gBACxB,IAAI,QAAa,CAAC;gBACjB,IAAI,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;oBAChC,mFAAmF;oBACnF,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAe,EAAE,MAAM,EAAE,MAAM,IAAK,OAAO,CAAC,MAAM,EAAE,OAAe,EAAE,IAAI,EAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAE,OAAO,CAAC,MAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;oBACvL,0EAA0E;oBAC1E,sEAAsE;oBACtE,0EAA0E;oBAC1E,0EAA0E;oBAC1E,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;gBAC1D,CAAC;qBAAM,CAAC;oBACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC5D,CAAC;gBAED,gCAAgC;gBAChC,IAAI,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACpC,MAAM,GAAG,GAAG,QAAe,CAAC;oBAC5B,IAAI,CAAC,GAAG,CAAC,+BAA+B,EAAE;wBACzC,WAAW,EAAE,GAAG,EAAE,WAAW;wBAC7B,YAAY,EAAE,OAAO,QAAQ;wBAC7B,WAAW,EAAE,UAAU,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;wBACtC,UAAU,EAAE,SAAS,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;wBACpC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,IAAI,EAAE,CAAC;wBAC7C,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI,EAAE,CAAC;wBAC3C,aAAa,EAAE,GAAG,EAAE,QAAQ;wBAC5B,YAAY,EAAE,GAAG,EAAE,OAAO;qBAC1B,CAAC,CAAC;gBACJ,CAAC;gBACD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBAC5C,IAAI,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACpC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;oBAC5C,IAAI,CAAC,GAAG,CAAC,gCAAgC,EAAE;wBAC1C,WAAW,EAAG,YAAoB,EAAE,WAAW;wBAC/C,WAAW,EAAE,MAAM,CAAC,IAAI,CAAE,YAAoB,EAAE,QAAQ,IAAI,EAAE,CAAC;wBAC/D,UAAU,EAAE,MAAM,CAAC,IAAI,CAAE,YAAoB,EAAE,OAAO,IAAI,EAAE,CAAC;qBAC7D,CAAC,CAAC;gBACJ,CAAC;gBACD,MAAM,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC5C,CAAC;QACF,CAAC,CAAC;QAEF,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YACjC,MAAM,IAAI,CACT,MAAM,EACN,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC5B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EACxB,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC5B,MAAM,CACN,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;YACvB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,sDAAsD,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from "./cluster/client.js";
|
|
2
|
+
export * from "./cluster/cluster-repo.js";
|
|
3
|
+
export * from "./cluster/service.js";
|
|
4
|
+
export * from "./protocol-client.js";
|
|
5
|
+
export * from "./repo/client.js";
|
|
6
|
+
export * from "./repo/cluster-coordinator.js";
|
|
7
|
+
export * from "./repo/coordinator-repo.js";
|
|
8
|
+
export * from "./repo/service.js";
|
|
9
|
+
export * from "./storage/block-storage.js";
|
|
10
|
+
export * from "./storage/file-storage.js";
|
|
11
|
+
export * from "./storage/memory-storage.js";
|
|
12
|
+
export * from "./storage/i-block-storage.js";
|
|
13
|
+
export * from "./storage/i-raw-storage.js";
|
|
14
|
+
export * from "./storage/storage-repo.js";
|
|
15
|
+
export * from "./storage/restoration-coordinator-v2.js";
|
|
16
|
+
export * from "./storage/ring-selector.js";
|
|
17
|
+
export * from "./storage/storage-monitor.js";
|
|
18
|
+
export * from "./storage/arachnode-fret-adapter.js";
|
|
19
|
+
export * from "./sync/protocol.js";
|
|
20
|
+
export * from "./sync/client.js";
|
|
21
|
+
export * from "./sync/service.js";
|
|
22
|
+
export * from "./it-utility.js";
|
|
23
|
+
export * from "./libp2p-key-network.js";
|
|
24
|
+
export * from "./libp2p-node.js";
|
|
25
|
+
export * from "./routing/responsibility.js";
|
|
26
|
+
export * from "./routing/libp2p-known-peers.js";
|
|
27
|
+
export * from "./network/network-manager-service.js";
|
|
28
|
+
export * from "./network/get-network-manager.js";
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AACrD,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from "./cluster/client.js";
|
|
2
|
+
export * from "./cluster/cluster-repo.js";
|
|
3
|
+
export * from "./cluster/service.js";
|
|
4
|
+
export * from "./protocol-client.js";
|
|
5
|
+
export * from "./repo/client.js";
|
|
6
|
+
export * from "./repo/cluster-coordinator.js";
|
|
7
|
+
export * from "./repo/coordinator-repo.js";
|
|
8
|
+
export * from "./repo/service.js";
|
|
9
|
+
export * from "./storage/block-storage.js";
|
|
10
|
+
export * from "./storage/file-storage.js";
|
|
11
|
+
export * from "./storage/memory-storage.js";
|
|
12
|
+
export * from "./storage/i-block-storage.js";
|
|
13
|
+
export * from "./storage/i-raw-storage.js";
|
|
14
|
+
export * from "./storage/storage-repo.js";
|
|
15
|
+
export * from "./storage/restoration-coordinator-v2.js";
|
|
16
|
+
export * from "./storage/ring-selector.js";
|
|
17
|
+
export * from "./storage/storage-monitor.js";
|
|
18
|
+
export * from "./storage/arachnode-fret-adapter.js";
|
|
19
|
+
export * from "./sync/protocol.js";
|
|
20
|
+
export * from "./sync/client.js";
|
|
21
|
+
export * from "./sync/service.js";
|
|
22
|
+
export * from "./it-utility.js";
|
|
23
|
+
export * from "./libp2p-key-network.js";
|
|
24
|
+
export * from "./libp2p-node.js";
|
|
25
|
+
export * from "./routing/responsibility.js";
|
|
26
|
+
export * from "./routing/libp2p-known-peers.js";
|
|
27
|
+
export * from "./network/network-manager-service.js";
|
|
28
|
+
export * from "./network/get-network-manager.js";
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AACrD,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function first<T>(createIterable: (signal: AbortSignal) => AsyncIterable<T>, onEmpty?: () => T, timeoutMs?: number): Promise<T>;
|
|
2
|
+
export declare function asyncIteratorToArray<T>(iterator: AsyncIterable<T>): Promise<T[]>;
|
|
3
|
+
export declare function reduce<TP, TC>(iter: IterableIterator<TC>, each: (prior: TP, current: TC, index: number) => TP, start: TP): TP;
|
|
4
|
+
//# sourceMappingURL=it-utility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"it-utility.d.ts","sourceRoot":"","sources":["../../src/it-utility.ts"],"names":[],"mappings":"AAAA,wBAAsB,KAAK,CAAC,CAAC,EAC5B,cAAc,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,aAAa,CAAC,CAAC,CAAC,EACzD,OAAO,GAAE,MAAM,CAA+C,EAC9D,SAAS,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,CAAC,CAAC,CAYZ;AAED,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAMtF;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAQxH"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export async function first(createIterable, onEmpty = () => { throw new Error('No items found'); }, timeoutMs) {
|
|
2
|
+
const controller = new AbortController();
|
|
3
|
+
const timer = typeof timeoutMs === 'number' ? setTimeout(() => controller.abort(), timeoutMs) : undefined;
|
|
4
|
+
try {
|
|
5
|
+
for await (const item of createIterable(controller.signal)) {
|
|
6
|
+
return item;
|
|
7
|
+
}
|
|
8
|
+
return onEmpty();
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
if (timer !== undefined)
|
|
12
|
+
clearTimeout(timer);
|
|
13
|
+
controller.abort();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function asyncIteratorToArray(iterator) {
|
|
17
|
+
const result = [];
|
|
18
|
+
for await (const item of iterator) {
|
|
19
|
+
result.push(item);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
export function reduce(iter, each, start) {
|
|
24
|
+
let prior = start;
|
|
25
|
+
let i = 0;
|
|
26
|
+
for (let current of iter) {
|
|
27
|
+
prior = each(prior, current, i);
|
|
28
|
+
++i;
|
|
29
|
+
}
|
|
30
|
+
return prior;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=it-utility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"it-utility.js","sourceRoot":"","sources":["../../src/it-utility.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,KAAK,CAC1B,cAAyD,EACzD,UAAmB,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAA,CAAC,CAAC,EAC9D,SAAkB;IAElB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1G,IAAI,CAAC;QACJ,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,OAAO,EAAE,CAAC;IAClB,CAAC;YAAS,CAAC;QACV,IAAI,KAAK,KAAK,SAAS;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7C,UAAU,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAI,QAA0B;IACvE,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,UAAU,MAAM,CAAS,IAA0B,EAAE,IAAmD,EAAE,KAAS;IACxH,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QAC1B,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAChC,EAAE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AbortOptions, Libp2p, PeerId, Stream } from "@libp2p/interface";
|
|
2
|
+
import type { ClusterPeers, FindCoordinatorOptions, IKeyNetwork, IPeerNetwork } from "@optimystic/db-core";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for self-coordination behavior
|
|
5
|
+
*/
|
|
6
|
+
export interface SelfCoordinationConfig {
|
|
7
|
+
/** Time (ms) after last connection before allowing self-coordination. Default: 30000 */
|
|
8
|
+
gracePeriodMs?: number;
|
|
9
|
+
/** Threshold for suspicious network shrinkage (0-1). >50% drop is suspicious. Default: 0.5 */
|
|
10
|
+
shrinkageThreshold?: number;
|
|
11
|
+
/** Allow self-coordination at all. Default: true (for testing). Set false in production. */
|
|
12
|
+
allowSelfCoordination?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Decision result from self-coordination guard
|
|
16
|
+
*/
|
|
17
|
+
export interface SelfCoordinationDecision {
|
|
18
|
+
allow: boolean;
|
|
19
|
+
reason: 'bootstrap-node' | 'partition-detected' | 'suspicious-shrinkage' | 'grace-period-not-elapsed' | 'extended-isolation' | 'disabled';
|
|
20
|
+
warn?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare class Libp2pKeyPeerNetwork implements IKeyNetwork, IPeerNetwork {
|
|
23
|
+
private readonly libp2p;
|
|
24
|
+
private readonly clusterSize;
|
|
25
|
+
private readonly selfCoordinationConfig;
|
|
26
|
+
private networkHighWaterMark;
|
|
27
|
+
private lastConnectedTime;
|
|
28
|
+
constructor(libp2p: Libp2p, clusterSize?: number, selfCoordinationConfig?: SelfCoordinationConfig);
|
|
29
|
+
private readonly coordinatorCache;
|
|
30
|
+
private static readonly MAX_CACHE_ENTRIES;
|
|
31
|
+
private readonly log;
|
|
32
|
+
private toCacheKey;
|
|
33
|
+
/**
|
|
34
|
+
* Set up connection event tracking to update high water mark and last connected time.
|
|
35
|
+
*/
|
|
36
|
+
private setupConnectionTracking;
|
|
37
|
+
/**
|
|
38
|
+
* Update network high water mark and last connected time.
|
|
39
|
+
* Called on new connections.
|
|
40
|
+
*/
|
|
41
|
+
private updateNetworkObservations;
|
|
42
|
+
/**
|
|
43
|
+
* Determine if self-coordination should be allowed based on network observations.
|
|
44
|
+
*
|
|
45
|
+
* Principle: If we've ever seen a larger network, assume our connectivity is the problem,
|
|
46
|
+
* not the network shrinking.
|
|
47
|
+
*/
|
|
48
|
+
shouldAllowSelfCoordination(): SelfCoordinationDecision;
|
|
49
|
+
recordCoordinator(key: Uint8Array, peerId: PeerId, ttlMs?: number): void;
|
|
50
|
+
private getCachedCoordinator;
|
|
51
|
+
connect(peerId: PeerId, protocol: string, _options?: AbortOptions): Promise<Stream>;
|
|
52
|
+
private getFret;
|
|
53
|
+
private getNeighborIdsForKey;
|
|
54
|
+
findCoordinator(key: Uint8Array, _options?: Partial<FindCoordinatorOptions>): Promise<PeerId>;
|
|
55
|
+
private getConnectedAddrsByPeer;
|
|
56
|
+
private parseMultiaddrs;
|
|
57
|
+
findCluster(key: Uint8Array): Promise<ClusterPeers>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=libp2p-key-network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"libp2p-key-network.d.ts","sourceRoot":"","sources":["../../src/libp2p-key-network.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAS3G;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,sBAAsB,GAAG,0BAA0B,GAAG,oBAAoB,GAAG,UAAU,CAAC;IAC1I,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,oBAAqB,YAAW,WAAW,EAAE,YAAY;IAMpE,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAN7B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAmC;IAC1E,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,iBAAiB,CAAc;gBAGrB,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAAW,EACzC,sBAAsB,CAAC,EAAE,sBAAsB;IAWhD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqD;IACtF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAO;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqC;IAEzD,OAAO,CAAC,UAAU;IAElB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAwBjC;;;;;OAKG;IACH,2BAA2B,IAAI,wBAAwB;IAwDhD,iBAAiB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,SAAiB,GAAG,IAAI;IAcvF,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IASnF,OAAO,CAAC,OAAO;YAMD,oBAAoB;IAO5B,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAiFnG,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,eAAe;IAQjB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CAiCzD"}
|