@olane/o-node 0.7.13-alpha.0 → 0.7.13-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +1 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.d.ts +0 -1
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +0 -8
- package/dist/src/connection/o-node-connection.manager.d.ts +41 -4
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +187 -45
- package/dist/src/connection/stream-handler.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.js +0 -2
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.js +15 -1
- package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
- package/dist/src/managers/o-reconnection.manager.js +12 -7
- package/dist/src/o-node.d.ts +19 -0
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +89 -11
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +5 -0
- package/dist/src/router/o-node.router.d.ts.map +1 -1
- package/dist/src/router/o-node.router.js +16 -6
- package/dist/src/router/o-node.routing-policy.d.ts.map +1 -1
- package/dist/src/router/o-node.routing-policy.js +4 -0
- package/dist/test/connection-management.spec.d.ts +2 -0
- package/dist/test/connection-management.spec.d.ts.map +1 -0
- package/dist/test/connection-management.spec.js +370 -0
- package/dist/test/helpers/connection-spy.d.ts +124 -0
- package/dist/test/helpers/connection-spy.d.ts.map +1 -0
- package/dist/test/helpers/connection-spy.js +229 -0
- package/dist/test/helpers/index.d.ts +6 -0
- package/dist/test/helpers/index.d.ts.map +1 -0
- package/dist/test/helpers/index.js +12 -0
- package/dist/test/helpers/network-builder.d.ts +109 -0
- package/dist/test/helpers/network-builder.d.ts.map +1 -0
- package/dist/test/helpers/network-builder.js +309 -0
- package/dist/test/helpers/simple-node-builder.d.ts +50 -0
- package/dist/test/helpers/simple-node-builder.d.ts.map +1 -0
- package/dist/test/helpers/simple-node-builder.js +66 -0
- package/dist/test/helpers/test-environment.d.ts +140 -0
- package/dist/test/helpers/test-environment.d.ts.map +1 -0
- package/dist/test/helpers/test-environment.js +184 -0
- package/dist/test/helpers/test-node.tool.d.ts +31 -0
- package/dist/test/helpers/test-node.tool.d.ts.map +1 -1
- package/dist/test/helpers/test-node.tool.js +49 -0
- package/dist/test/leader-transport-validation.spec.d.ts +2 -0
- package/dist/test/leader-transport-validation.spec.d.ts.map +1 -0
- package/dist/test/leader-transport-validation.spec.js +177 -0
- package/dist/test/network-communication.spec.d.ts +2 -0
- package/dist/test/network-communication.spec.d.ts.map +1 -0
- package/dist/test/network-communication.spec.js +256 -0
- package/dist/test/o-node.spec.d.ts +2 -0
- package/dist/test/o-node.spec.d.ts.map +1 -0
- package/dist/test/o-node.spec.js +247 -0
- package/dist/test/parent-child-registration.spec.d.ts +2 -0
- package/dist/test/parent-child-registration.spec.d.ts.map +1 -0
- package/dist/test/parent-child-registration.spec.js +177 -0
- package/dist/test/search-resolver.spec.d.ts +2 -0
- package/dist/test/search-resolver.spec.d.ts.map +1 -0
- package/dist/test/search-resolver.spec.js +648 -0
- package/package.json +12 -7
|
@@ -3,5 +3,6 @@ import { Libp2p } from '@olane/o-config';
|
|
|
3
3
|
export interface oNodeConnectionManagerConfig extends oConnectionManagerConfig {
|
|
4
4
|
p2pNode: Libp2p;
|
|
5
5
|
runOnLimitedConnection?: boolean;
|
|
6
|
+
originAddress?: string;
|
|
6
7
|
}
|
|
7
8
|
//# sourceMappingURL=o-node-connection-manager.config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -7,7 +7,6 @@ export declare class oNodeConnection extends oConnection {
|
|
|
7
7
|
p2pConnection: Connection;
|
|
8
8
|
protected streamHandler: StreamHandler;
|
|
9
9
|
constructor(config: oNodeConnectionConfig);
|
|
10
|
-
setupConnectionListeners(): void;
|
|
11
10
|
validate(stream?: Stream): void;
|
|
12
11
|
getOrCreateStream(): Promise<Stream>;
|
|
13
12
|
transmit(request: oRequest): Promise<oResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;
|
|
1
|
+
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;IAM5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IA0C/C,YAAY,CAAC,MAAM,EAAE,MAAM;IAQ3B,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAKZ"}
|
|
@@ -6,14 +6,6 @@ export class oNodeConnection extends oConnection {
|
|
|
6
6
|
this.config = config;
|
|
7
7
|
this.p2pConnection = config.p2pConnection;
|
|
8
8
|
this.streamHandler = new StreamHandler(this.logger);
|
|
9
|
-
this.setupConnectionListeners();
|
|
10
|
-
}
|
|
11
|
-
setupConnectionListeners() {
|
|
12
|
-
this.logger.debug('Setting up connection listeners for address: ' +
|
|
13
|
-
this.nextHopAddress.toString());
|
|
14
|
-
this.p2pConnection?.addEventListener('close', () => {
|
|
15
|
-
this.logger.debug('Connection closed for address: ' + this.nextHopAddress.toString());
|
|
16
|
-
});
|
|
17
9
|
}
|
|
18
10
|
validate(stream) {
|
|
19
11
|
if (this.config.p2pConnection.status !== 'open') {
|
|
@@ -7,9 +7,29 @@ export declare class oNodeConnectionManager extends oConnectionManager {
|
|
|
7
7
|
protected p2pNode: Libp2p;
|
|
8
8
|
private defaultReadTimeoutMs?;
|
|
9
9
|
private defaultDrainTimeoutMs?;
|
|
10
|
-
private
|
|
10
|
+
private connectionsByTransportKey;
|
|
11
|
+
private pendingDialsByTransportKey;
|
|
11
12
|
constructor(config: oNodeConnectionManagerConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Set up listeners to maintain connection cache state
|
|
15
|
+
*/
|
|
16
|
+
private setupConnectionListeners;
|
|
17
|
+
/**
|
|
18
|
+
* Build a stable cache key from the libp2p transports on an address.
|
|
19
|
+
*
|
|
20
|
+
* We intentionally key the cache by transports (multiaddrs) instead of peer IDs
|
|
21
|
+
* to avoid ambiguity when multiple peers may share a peer ID or when addresses
|
|
22
|
+
* change but the libp2p transports are the true dial targets.
|
|
23
|
+
*/
|
|
24
|
+
private getTransportKeyFromAddress;
|
|
25
|
+
/**
|
|
26
|
+
* Extract peer ID string from an address
|
|
27
|
+
* @param address - The address to extract peer ID from
|
|
28
|
+
* @returns The peer ID string or null if not found
|
|
29
|
+
*/
|
|
30
|
+
private getPeerIdFromAddress;
|
|
12
31
|
getOrCreateConnection(nextHopAddress: oAddress, address: oAddress): Promise<Connection>;
|
|
32
|
+
private performDial;
|
|
13
33
|
/**
|
|
14
34
|
* Connect to a given address, reusing libp2p connections when possible
|
|
15
35
|
* @param config - Connection configuration
|
|
@@ -17,16 +37,33 @@ export declare class oNodeConnectionManager extends oConnectionManager {
|
|
|
17
37
|
*/
|
|
18
38
|
connect(config: oConnectionConfig): Promise<oNodeConnection>;
|
|
19
39
|
/**
|
|
20
|
-
* Check if
|
|
40
|
+
* Check if we have an active connection to the target peer
|
|
21
41
|
* @param address - The address to check
|
|
22
42
|
* @returns true if an active connection exists
|
|
23
43
|
*/
|
|
24
44
|
isCached(address: oAddress): boolean;
|
|
25
45
|
/**
|
|
26
|
-
* Get an existing
|
|
46
|
+
* Get an existing connection to the target peer (from cache or libp2p)
|
|
27
47
|
* @param address - The address to get a connection for
|
|
28
|
-
* @returns The
|
|
48
|
+
* @returns The Connection object or null if not found
|
|
29
49
|
*/
|
|
30
50
|
getCachedLibp2pConnection(address: oAddress): Connection | null;
|
|
51
|
+
/**
|
|
52
|
+
* Get cache statistics for monitoring and debugging
|
|
53
|
+
* @returns Object containing cache statistics
|
|
54
|
+
*/
|
|
55
|
+
getCacheStats(): {
|
|
56
|
+
cachedConnections: number;
|
|
57
|
+
pendingDials: number;
|
|
58
|
+
connectionsByPeer: Array<{
|
|
59
|
+
peerId: string;
|
|
60
|
+
status: string;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Clean up all stale (non-open) connections from cache
|
|
65
|
+
* @returns Number of connections removed
|
|
66
|
+
*/
|
|
67
|
+
cleanupStaleConnections(): number;
|
|
31
68
|
}
|
|
32
69
|
//# sourceMappingURL=o-node-connection.manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;
|
|
1
|
+
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAOhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IANzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,0BAA0B,CAA+C;gBAE5D,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmBhC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YAsDR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAoCpC;;;;OAIG;IACH,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI;IA+C/D;;;OAGG;IACH,aAAa,IAAI;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9D;IAaD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAalC"}
|
|
@@ -4,32 +4,128 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
4
4
|
constructor(config) {
|
|
5
5
|
super(config);
|
|
6
6
|
this.config = config;
|
|
7
|
-
this.
|
|
7
|
+
this.connectionsByTransportKey = new Map();
|
|
8
|
+
this.pendingDialsByTransportKey = new Map();
|
|
8
9
|
this.p2pNode = config.p2pNode;
|
|
9
10
|
this.defaultReadTimeoutMs = config.defaultReadTimeoutMs;
|
|
10
11
|
this.defaultDrainTimeoutMs = config.defaultDrainTimeoutMs;
|
|
12
|
+
this.logger.setNamespace(`oNodeConnectionManager[${config.originAddress}]`);
|
|
13
|
+
// Set up connection lifecycle listeners for cache management
|
|
14
|
+
this.setupConnectionListeners();
|
|
11
15
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Set up listeners to maintain connection cache state
|
|
18
|
+
*/
|
|
19
|
+
setupConnectionListeners() {
|
|
20
|
+
this.p2pNode.addEventListener('connection:close', (event) => {
|
|
21
|
+
const connection = event.detail;
|
|
22
|
+
if (!connection) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const [transportKey, cachedConnection] of this.connectionsByTransportKey.entries()) {
|
|
26
|
+
if (cachedConnection === connection) {
|
|
27
|
+
this.logger.debug('Connection closed, removing from cache for transport key:', transportKey);
|
|
28
|
+
this.connectionsByTransportKey.delete(transportKey);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a stable cache key from the libp2p transports on an address.
|
|
35
|
+
*
|
|
36
|
+
* We intentionally key the cache by transports (multiaddrs) instead of peer IDs
|
|
37
|
+
* to avoid ambiguity when multiple peers may share a peer ID or when addresses
|
|
38
|
+
* change but the libp2p transports are the true dial targets.
|
|
39
|
+
*/
|
|
40
|
+
getTransportKeyFromAddress(address) {
|
|
41
|
+
try {
|
|
42
|
+
const nodeAddress = address;
|
|
43
|
+
const transports = nodeAddress.libp2pTransports;
|
|
44
|
+
if (!transports?.length) {
|
|
45
|
+
return null;
|
|
30
46
|
}
|
|
47
|
+
// Sort to ensure deterministic keys regardless of transport ordering.
|
|
48
|
+
const parts = transports.map((t) => t.toString()).sort();
|
|
49
|
+
return parts.join('|');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
this.logger.debug('Error extracting transport key from address:', error);
|
|
53
|
+
return null;
|
|
31
54
|
}
|
|
32
|
-
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract peer ID string from an address
|
|
58
|
+
* @param address - The address to extract peer ID from
|
|
59
|
+
* @returns The peer ID string or null if not found
|
|
60
|
+
*/
|
|
61
|
+
getPeerIdFromAddress(address) {
|
|
62
|
+
try {
|
|
63
|
+
const nodeAddress = address;
|
|
64
|
+
if (!nodeAddress.libp2pTransports?.length) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return nodeAddress.libp2pTransports[0].toPeerId() || null;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
this.logger.debug('Error extracting peer ID from address:', error);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async getOrCreateConnection(nextHopAddress, address) {
|
|
75
|
+
// Build a transport-based cache key from the next hop address
|
|
76
|
+
const transportKey = this.getTransportKeyFromAddress(nextHopAddress);
|
|
77
|
+
if (!transportKey) {
|
|
78
|
+
throw new Error(`Unable to extract libp2p transports from address: ${nextHopAddress.toString()}`);
|
|
79
|
+
}
|
|
80
|
+
// Check if we have a cached connection by transport key
|
|
81
|
+
const cachedConnection = this.connectionsByTransportKey.get(transportKey);
|
|
82
|
+
if (cachedConnection && cachedConnection.status === 'open') {
|
|
83
|
+
this.logger.debug('Reusing cached connection for transports:', transportKey);
|
|
84
|
+
return cachedConnection;
|
|
85
|
+
}
|
|
86
|
+
// Clean up stale connection if it exists but is not open
|
|
87
|
+
if (cachedConnection && cachedConnection.status !== 'open') {
|
|
88
|
+
this.logger.debug('Removing stale connection for transports:', transportKey);
|
|
89
|
+
this.connectionsByTransportKey.delete(transportKey);
|
|
90
|
+
}
|
|
91
|
+
// Check if libp2p has an active connection for this address
|
|
92
|
+
const libp2pConnection = this.getCachedLibp2pConnection(nextHopAddress);
|
|
93
|
+
if (libp2pConnection && libp2pConnection.status === 'open') {
|
|
94
|
+
this.logger.debug('Caching existing libp2p connection for transports:', transportKey);
|
|
95
|
+
this.connectionsByTransportKey.set(transportKey, libp2pConnection);
|
|
96
|
+
return libp2pConnection;
|
|
97
|
+
}
|
|
98
|
+
// Check if dial is already in progress for this transport key
|
|
99
|
+
const pendingDial = this.pendingDialsByTransportKey.get(transportKey);
|
|
100
|
+
if (pendingDial) {
|
|
101
|
+
this.logger.debug('Awaiting existing dial for transports:', transportKey);
|
|
102
|
+
return pendingDial;
|
|
103
|
+
}
|
|
104
|
+
// Start new dial and cache the promise by transport key
|
|
105
|
+
const dialPromise = this.performDial(nextHopAddress, transportKey);
|
|
106
|
+
this.pendingDialsByTransportKey.set(transportKey, dialPromise);
|
|
107
|
+
try {
|
|
108
|
+
const connection = await dialPromise;
|
|
109
|
+
// Cache the established connection by transport key
|
|
110
|
+
this.connectionsByTransportKey.set(transportKey, connection);
|
|
111
|
+
return connection;
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
this.pendingDialsByTransportKey.delete(transportKey);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async performDial(nextHopAddress, transportKey) {
|
|
118
|
+
this.logger.debug('Dialing new connection', {
|
|
119
|
+
address: nextHopAddress.value,
|
|
120
|
+
transportKey,
|
|
121
|
+
});
|
|
122
|
+
const connection = await this.p2pNode.dial(nextHopAddress.libp2pTransports.map((ma) => ma.toMultiaddr()));
|
|
123
|
+
this.logger.debug('Successfully dialed connection', {
|
|
124
|
+
transportKey,
|
|
125
|
+
status: connection.status,
|
|
126
|
+
remotePeer: connection.remotePeer?.toString(),
|
|
127
|
+
});
|
|
128
|
+
return connection;
|
|
33
129
|
}
|
|
34
130
|
/**
|
|
35
131
|
* Connect to a given address, reusing libp2p connections when possible
|
|
@@ -54,27 +150,35 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
54
150
|
return connection;
|
|
55
151
|
}
|
|
56
152
|
/**
|
|
57
|
-
* Check if
|
|
153
|
+
* Check if we have an active connection to the target peer
|
|
58
154
|
* @param address - The address to check
|
|
59
155
|
* @returns true if an active connection exists
|
|
60
156
|
*/
|
|
61
157
|
isCached(address) {
|
|
62
158
|
try {
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
65
|
-
nodeAddress.libp2pTransports.length === 0) {
|
|
159
|
+
const transportKey = this.getTransportKeyFromAddress(address);
|
|
160
|
+
if (!transportKey) {
|
|
66
161
|
return false;
|
|
67
162
|
}
|
|
68
|
-
//
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
return
|
|
163
|
+
// Check our transport-based cache first
|
|
164
|
+
const cachedConnection = this.connectionsByTransportKey.get(transportKey);
|
|
165
|
+
if (cachedConnection?.status === 'open') {
|
|
166
|
+
return true;
|
|
72
167
|
}
|
|
73
|
-
|
|
168
|
+
// Fall back to checking libp2p's connections
|
|
169
|
+
const peerId = this.getPeerIdFromAddress(address);
|
|
74
170
|
// the following works since the peer id param is not really required: https://github.com/libp2p/js-libp2p/blob/0bbf5021b53938b2bffcffca6c13c479a95c2a60/packages/libp2p/src/connection-manager/index.ts#L508
|
|
75
|
-
const connections = this.p2pNode.getConnections(
|
|
171
|
+
const connections = this.p2pNode.getConnections(peerId); // ignore since converting to a proper peer id breaks the browser implementation
|
|
76
172
|
// Check if we have at least one open connection
|
|
77
|
-
|
|
173
|
+
const hasOpenConnection = connections.some((conn) => conn.status === 'open');
|
|
174
|
+
// If libp2p has an open connection, update our cache
|
|
175
|
+
if (hasOpenConnection) {
|
|
176
|
+
const openConnection = connections.find((conn) => conn.status === 'open');
|
|
177
|
+
if (openConnection) {
|
|
178
|
+
this.connectionsByTransportKey.set(transportKey, openConnection);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return hasOpenConnection;
|
|
78
182
|
}
|
|
79
183
|
catch (error) {
|
|
80
184
|
this.logger.debug('Error checking cached connection:', error);
|
|
@@ -82,37 +186,75 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
82
186
|
}
|
|
83
187
|
}
|
|
84
188
|
/**
|
|
85
|
-
* Get an existing
|
|
189
|
+
* Get an existing connection to the target peer (from cache or libp2p)
|
|
86
190
|
* @param address - The address to get a connection for
|
|
87
|
-
* @returns The
|
|
191
|
+
* @returns The Connection object or null if not found
|
|
88
192
|
*/
|
|
89
193
|
getCachedLibp2pConnection(address) {
|
|
90
194
|
try {
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
195
|
+
const transportKey = this.getTransportKeyFromAddress(address);
|
|
196
|
+
if (!transportKey) {
|
|
93
197
|
return null;
|
|
94
198
|
}
|
|
95
|
-
|
|
96
|
-
|
|
199
|
+
// Check transport-based cache first
|
|
200
|
+
const cachedConnection = this.connectionsByTransportKey.get(transportKey);
|
|
201
|
+
if (cachedConnection?.status === 'open') {
|
|
202
|
+
return cachedConnection;
|
|
203
|
+
}
|
|
204
|
+
const peerId = this.getPeerIdFromAddress(address);
|
|
205
|
+
if (!peerId) {
|
|
97
206
|
return null;
|
|
98
207
|
}
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
208
|
+
// Query libp2p for connections to this peer
|
|
209
|
+
const connections = this.p2pNode.getConnections();
|
|
210
|
+
const filteredConnections = connections.filter((conn) => conn.remotePeer?.toString() === peerId);
|
|
211
|
+
// Find the first open connection
|
|
102
212
|
const openConnection = filteredConnections.find((conn) => conn.status === 'open');
|
|
213
|
+
// If we found an open connection in libp2p, cache it by transport key
|
|
103
214
|
if (openConnection) {
|
|
215
|
+
this.connectionsByTransportKey.set(transportKey, openConnection);
|
|
104
216
|
return openConnection;
|
|
105
217
|
}
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
218
|
+
// Clean up stale cache entry if connection is no longer open
|
|
219
|
+
if (cachedConnection) {
|
|
220
|
+
this.connectionsByTransportKey.delete(transportKey);
|
|
109
221
|
}
|
|
110
|
-
|
|
111
|
-
return connection ?? null;
|
|
222
|
+
return null;
|
|
112
223
|
}
|
|
113
224
|
catch (error) {
|
|
114
225
|
this.logger.debug('Error getting cached connection:', error);
|
|
115
226
|
return null;
|
|
116
227
|
}
|
|
117
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Get cache statistics for monitoring and debugging
|
|
231
|
+
* @returns Object containing cache statistics
|
|
232
|
+
*/
|
|
233
|
+
getCacheStats() {
|
|
234
|
+
return {
|
|
235
|
+
cachedConnections: this.connectionsByTransportKey.size,
|
|
236
|
+
pendingDials: this.pendingDialsByTransportKey.size,
|
|
237
|
+
connectionsByPeer: Array.from(this.connectionsByTransportKey.values()).map((conn) => ({
|
|
238
|
+
peerId: conn.remotePeer?.toString() ?? 'unknown',
|
|
239
|
+
status: conn.status,
|
|
240
|
+
})),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Clean up all stale (non-open) connections from cache
|
|
245
|
+
* @returns Number of connections removed
|
|
246
|
+
*/
|
|
247
|
+
cleanupStaleConnections() {
|
|
248
|
+
let removed = 0;
|
|
249
|
+
for (const [transportKey, connection] of this.connectionsByTransportKey.entries()) {
|
|
250
|
+
if (connection.status !== 'open') {
|
|
251
|
+
this.connectionsByTransportKey.delete(transportKey);
|
|
252
|
+
removed++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (removed > 0) {
|
|
256
|
+
this.logger.debug(`Cleaned up ${removed} stale connections`);
|
|
257
|
+
}
|
|
258
|
+
return removed;
|
|
259
|
+
}
|
|
118
260
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,QAAQ,EACR,SAAS,EAIT,MAAM,EAEP,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIhC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIjC;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAI7C;;;;;;OAMG;IACG,iBAAiB,CACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,QAAQ,EACR,SAAS,EAIT,MAAM,EAEP,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIhC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIjC;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAI7C;;;;;;OAMG;IACG,iBAAiB,CACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC;IAoClB;;;;;;OAMG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAiBhB;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5E;;;;;;;;OAQG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACtE,OAAO,CAAC,IAAI,CAAC;IAuChB;;;;;;OAMG;YACW,oBAAoB;IA4BlC;;;;;;;;;;;OAWG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,mBAAwB,EAChC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,EAC1E,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAC1B,OAAO,CAAC,SAAS,CAAC;IA+GrB;;;;;;;OAOG;IACG,cAAc,CAClB,OAAO,EAAE,cAAc,EACvB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;CAyBjB"}
|
|
@@ -43,7 +43,6 @@ export class StreamHandler {
|
|
|
43
43
|
throw new oError(oErrorCodes.INVALID_STATE, 'Connection not open');
|
|
44
44
|
}
|
|
45
45
|
const reusePolicy = config.reusePolicy ?? 'none';
|
|
46
|
-
this.logger.debug('Reuse policy:', reusePolicy);
|
|
47
46
|
// Check for existing stream if reuse is enabled
|
|
48
47
|
if (reusePolicy === 'reuse') {
|
|
49
48
|
const existingStream = connection.streams.find((stream) => stream.status === 'open' &&
|
|
@@ -56,7 +55,6 @@ export class StreamHandler {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
// Create new stream
|
|
59
|
-
this.logger.debug('Creating new stream');
|
|
60
58
|
const stream = await connection.newStream(protocol, {
|
|
61
59
|
signal: config.signal,
|
|
62
60
|
maxOutboundStreams: config.maxOutboundStreams ?? 1000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAMpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;gBAGhB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,uBAAuB;IAgDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;
|
|
1
|
+
{"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAMpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;gBAGhB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,uBAAuB;IAgDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YA8Cf,WAAW;IAoEzB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
|
|
@@ -95,7 +95,21 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
95
95
|
// Note: Using 'as any' since converting to proper PeerId breaks browser implementation
|
|
96
96
|
const connections = this.node.p2pNode.getConnections(peerIdString);
|
|
97
97
|
// Check if any connection is open
|
|
98
|
-
|
|
98
|
+
const existing = connections.some((conn) => conn.status === 'open');
|
|
99
|
+
if (existing) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
// check via ping
|
|
103
|
+
const pingResponse = this.node.use(address, {
|
|
104
|
+
method: 'ping'
|
|
105
|
+
}).catch((err) => {
|
|
106
|
+
if (err.message === 'Can not dial self') {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
this.logger.warn('Could not reach address in heartbeat:' + address.value, err);
|
|
110
|
+
return null;
|
|
111
|
+
});
|
|
112
|
+
return !!pingResponse;
|
|
99
113
|
}
|
|
100
114
|
catch (error) {
|
|
101
115
|
this.logger.debug(`Error checking connection status for ${address}`, error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EASR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;IAyBrB,mBAAmB,CAAC,KAAK,EAAE,GAAG;YAatB,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;
|
|
1
|
+
{"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EASR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;IAyBrB,mBAAmB,CAAC,KAAK,EAAE,GAAG;YAatB,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IAwG/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -189,6 +189,9 @@ export class oReconnectionManager extends oObject {
|
|
|
189
189
|
const startTime = Date.now();
|
|
190
190
|
let attempt = 0;
|
|
191
191
|
let currentDelay = this.config.parentDiscoveryIntervalMs;
|
|
192
|
+
if (!this.node.config.leader) {
|
|
193
|
+
throw new Error('Cannot connect to parent without leader');
|
|
194
|
+
}
|
|
192
195
|
// Infinite retry loop - keep trying until parent is found
|
|
193
196
|
while (true) {
|
|
194
197
|
attempt++;
|
|
@@ -196,18 +199,20 @@ export class oReconnectionManager extends oObject {
|
|
|
196
199
|
this.logger.info(`Parent discovery attempt ${attempt} (elapsed: ${elapsedMinutes}m)`);
|
|
197
200
|
try {
|
|
198
201
|
// Query registry for parent by its known address
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
if (!this.node.config.parent) {
|
|
203
|
+
throw new Error('Invalid parent definition');
|
|
204
|
+
}
|
|
205
|
+
const response = await this.node.use(this.node.config.parent, {
|
|
206
|
+
method: 'identify',
|
|
207
|
+
params: {},
|
|
204
208
|
});
|
|
205
|
-
|
|
209
|
+
this.logger.debug('Identify parent response:', response.result.data);
|
|
210
|
+
const { address: parentAddress, transports: parentTransports } = response.result.data;
|
|
206
211
|
// Check if parent was found in registry
|
|
207
212
|
if (parentAddress && parentTransports && parentTransports.length > 0) {
|
|
208
213
|
this.logger.info(`Parent found in registry: ${parentAddress} with ${parentTransports.length} transports`);
|
|
209
214
|
// Update parent reference with fresh transports
|
|
210
|
-
this.node.config.parent = new oNodeAddress(parentAddress, parentTransports.map((
|
|
215
|
+
this.node.config.parent = new oNodeAddress(parentAddress, parentTransports.map((value) => new oNodeTransport(value)));
|
|
211
216
|
// Attempt to register with parent and re-register with registry
|
|
212
217
|
try {
|
|
213
218
|
await this.tryDirectParentReconnection();
|
package/dist/src/o-node.d.ts
CHANGED
|
@@ -49,11 +49,30 @@ export declare class oNode extends oToolBase {
|
|
|
49
49
|
initConnectionManager(): Promise<void>;
|
|
50
50
|
hookInitializeFinished(): Promise<void>;
|
|
51
51
|
hookStartFinished(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Validates that if a leader address is defined, it has associated transports.
|
|
54
|
+
* This is critical for non-leader nodes to be able to connect to their leader.
|
|
55
|
+
* @throws Error if leader is defined but has no transports
|
|
56
|
+
*/
|
|
57
|
+
private validateLeaderTransports;
|
|
58
|
+
/**
|
|
59
|
+
* oNode-specific validation that runs before core start() logic.
|
|
60
|
+
*
|
|
61
|
+
* This ensures that leader transport configuration errors are
|
|
62
|
+
* surfaced quickly and before any libp2p nodes or other heavy
|
|
63
|
+
* resources are created.
|
|
64
|
+
*/
|
|
65
|
+
protected validate(): Promise<void>;
|
|
52
66
|
initialize(): Promise<void>;
|
|
53
67
|
/**
|
|
54
68
|
* Override use() to wrap leader/registry requests with retry logic
|
|
55
69
|
*/
|
|
56
70
|
teardown(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Reset node state to allow restart after stop
|
|
73
|
+
* Called at the end of teardown()
|
|
74
|
+
*/
|
|
75
|
+
protected resetState(): void;
|
|
57
76
|
getLeaders(): oNodeAddress[];
|
|
58
77
|
getParents(): oNodeAddress[];
|
|
59
78
|
getChildren(): oNodeAddress[];
|
package/dist/src/o-node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,EACN,YAAY,EAEb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAKL,QAAQ,EAER,oBAAoB,EAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEnF,OAAO,EAAmB,SAAS,EAAE,MAAM,eAAe,CAAC;AAG3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE5E,qBAAa,KAAM,SAAQ,SAAS;IAC3B,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAG,MAAM,CAAC;IACjB,OAAO,EAAG,YAAY,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,EAAG,sBAAsB,CAAC;IAC3C,gBAAgB,EAAG,qBAAqB,CAAC;IACzC,0BAA0B,CAAC,EAAE,2BAA2B,CAAC;IAChE,SAAS,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IACrD,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;gBAE3B,MAAM,EAAE,WAAW;IAK/B,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;IAED,IAAI,aAAa,IAAI,YAAY,CAKhC;IAED,IAAI,YAAY,IAAI,MAAM,GAAG,IAAI,CAOhC;IAED,mBAAmB,IAAI,GAAG,EAAE;IAItB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC,SAAS,CAAC,yBAAyB,IAAI,oBAAoB;IAQ3D,IAAI,aAAa,IAAI,YAAY,CAEhC;IAED,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,IAAI,UAAU,IAAI,cAAc,EAAE,CAIjC;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
|