@olane/o-node 0.7.12-alpha.12 → 0.7.12-alpha.13
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/interfaces/i-heartbeatable-node.d.ts +49 -0
- package/dist/src/interfaces/i-heartbeatable-node.d.ts.map +1 -0
- package/dist/src/interfaces/i-heartbeatable-node.js +1 -0
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts +4 -8
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.js +31 -29
- package/dist/src/managers/o-reconnection.manager.d.ts +1 -1
- package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
- package/dist/src/o-node.d.ts +5 -0
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +38 -17
- package/dist/src/router/o-node.routing-policy.js +2 -1
- package/package.json +6 -6
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { oNotificationManager } from '@olane/o-core';
|
|
2
|
+
import { Libp2p } from '@olane/o-config';
|
|
3
|
+
import { oNodeAddress } from '../router/o-node.address.js';
|
|
4
|
+
/**
|
|
5
|
+
* Interface for nodes that support connection heartbeat monitoring.
|
|
6
|
+
* This interface defines the contract that oConnectionHeartbeatManager needs
|
|
7
|
+
* to access live hierarchy state without holding stale references.
|
|
8
|
+
*/
|
|
9
|
+
export interface IHeartbeatableNode {
|
|
10
|
+
/**
|
|
11
|
+
* The node's current address
|
|
12
|
+
*/
|
|
13
|
+
address: oNodeAddress;
|
|
14
|
+
/**
|
|
15
|
+
* The notification manager for emitting heartbeat events
|
|
16
|
+
*/
|
|
17
|
+
notificationManager: oNotificationManager;
|
|
18
|
+
/**
|
|
19
|
+
* The underlying libp2p node for ping operations
|
|
20
|
+
*/
|
|
21
|
+
p2pNode: Libp2p;
|
|
22
|
+
/**
|
|
23
|
+
* The current parent address (with live transport updates)
|
|
24
|
+
* @returns Parent address or null if no parent
|
|
25
|
+
*/
|
|
26
|
+
parent: oNodeAddress | null;
|
|
27
|
+
/**
|
|
28
|
+
* Get the current list of leader addresses
|
|
29
|
+
* @returns Array of leader addresses (empty if this node is the leader)
|
|
30
|
+
*/
|
|
31
|
+
getLeaders(): oNodeAddress[];
|
|
32
|
+
/**
|
|
33
|
+
* Get the current list of parent addresses
|
|
34
|
+
* @returns Array of parent addresses
|
|
35
|
+
*/
|
|
36
|
+
getParents(): oNodeAddress[];
|
|
37
|
+
/**
|
|
38
|
+
* Get the current list of child addresses
|
|
39
|
+
* @returns Array of child addresses
|
|
40
|
+
*/
|
|
41
|
+
getChildren(): oNodeAddress[];
|
|
42
|
+
/**
|
|
43
|
+
* Remove a child from the hierarchy
|
|
44
|
+
* @param childAddress The address of the child to remove
|
|
45
|
+
*/
|
|
46
|
+
removeChild(childAddress: oNodeAddress): void;
|
|
47
|
+
use(param1: any, param2: any): Promise<any>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=i-heartbeatable-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-heartbeatable-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/i-heartbeatable-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAE1C;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,WAAW,IAAI,YAAY,EAAE,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAE9C,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { Libp2p } from '@olane/o-config';
|
|
2
1
|
import { oObject } from '@olane/o-core';
|
|
3
2
|
import { oNodeAddress } from '../router/o-node.address.js';
|
|
4
|
-
import {
|
|
5
|
-
import { oNotificationManager } from '@olane/o-core';
|
|
3
|
+
import { IHeartbeatableNode } from '../interfaces/i-heartbeatable-node.js';
|
|
6
4
|
export interface HeartbeatConfig {
|
|
7
5
|
enabled: boolean;
|
|
8
6
|
intervalMs: number;
|
|
@@ -35,17 +33,15 @@ export interface ConnectionHealth {
|
|
|
35
33
|
* - Emits ParentDisconnectedEvent when parent dies (triggers reconnection)
|
|
36
34
|
*/
|
|
37
35
|
export declare class oConnectionHeartbeatManager extends oObject {
|
|
38
|
-
private
|
|
39
|
-
private hierarchyManager;
|
|
40
|
-
private notificationManager;
|
|
41
|
-
private address;
|
|
36
|
+
private node;
|
|
42
37
|
private config;
|
|
43
38
|
private heartbeatInterval?;
|
|
44
39
|
private healthMap;
|
|
45
|
-
constructor(
|
|
40
|
+
constructor(node: IHeartbeatableNode, config: HeartbeatConfig);
|
|
46
41
|
start(): Promise<void>;
|
|
47
42
|
stop(): Promise<void>;
|
|
48
43
|
private performHeartbeatCycle;
|
|
44
|
+
private doPing;
|
|
49
45
|
private pingTarget;
|
|
50
46
|
private handleConnectionDead;
|
|
51
47
|
private emitConnectionDegradedEvent;
|
|
@@ -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,
|
|
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,SAAS,EAAE,MAAM,CAAC;IAClB,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;;;;;;;;;;;;;GAaG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAKpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;gBAG9C,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,qBAAqB;IA0CnC,OAAO,CAAC,MAAM;YAOA,UAAU;IAuFxB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC,OAAO,CAAC,wBAAwB;IAahC;;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"}
|
|
@@ -14,12 +14,9 @@ import { oObject, ChildLeftEvent, ParentDisconnectedEvent, LeaderDisconnectedEve
|
|
|
14
14
|
* - Emits ParentDisconnectedEvent when parent dies (triggers reconnection)
|
|
15
15
|
*/
|
|
16
16
|
export class oConnectionHeartbeatManager extends oObject {
|
|
17
|
-
constructor(
|
|
17
|
+
constructor(node, config) {
|
|
18
18
|
super();
|
|
19
|
-
this.
|
|
20
|
-
this.hierarchyManager = hierarchyManager;
|
|
21
|
-
this.notificationManager = notificationManager;
|
|
22
|
-
this.address = address;
|
|
19
|
+
this.node = node;
|
|
23
20
|
this.config = config;
|
|
24
21
|
this.healthMap = new Map();
|
|
25
22
|
}
|
|
@@ -45,24 +42,27 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
45
42
|
async performHeartbeatCycle() {
|
|
46
43
|
const targets = [];
|
|
47
44
|
// Check if this is a leader node (no leader in hierarchy = we are leader)
|
|
48
|
-
const isLeaderNode = this.
|
|
45
|
+
const isLeaderNode = this.node.getLeaders().length === 0;
|
|
49
46
|
// Collect leader (if enabled and we're not the leader)
|
|
50
47
|
if (!isLeaderNode) {
|
|
51
|
-
const leaders = this.
|
|
48
|
+
const leaders = this.node.getLeaders();
|
|
52
49
|
for (const leader of leaders) {
|
|
53
50
|
targets.push({ address: leader, role: 'leader' });
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
53
|
// Collect parent
|
|
57
54
|
if (this.config.checkParent && !isLeaderNode) {
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
// Use this.node.parent getter to get the current parent address with transports
|
|
56
|
+
// rather than getParents() which may have a stale reference
|
|
57
|
+
const parent = this.node.parent;
|
|
58
|
+
this.logger.debug('Parent address:', parent);
|
|
59
|
+
if (parent) {
|
|
60
60
|
targets.push({ address: parent, role: 'parent' });
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
// Collect children
|
|
64
64
|
if (this.config.checkChildren) {
|
|
65
|
-
const children = this.
|
|
65
|
+
const children = this.node.getChildren();
|
|
66
66
|
for (const child of children) {
|
|
67
67
|
targets.push({ address: child, role: 'child' });
|
|
68
68
|
}
|
|
@@ -70,12 +70,17 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
70
70
|
// Ping all targets in parallel
|
|
71
71
|
await Promise.allSettled(targets.map((target) => this.pingTarget(target.address, target.role)));
|
|
72
72
|
}
|
|
73
|
+
doPing(address) {
|
|
74
|
+
return this.node.use(address, {
|
|
75
|
+
method: 'ping',
|
|
76
|
+
params: {},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
73
79
|
async pingTarget(address, role) {
|
|
74
80
|
if (!address.libp2pTransports.length) {
|
|
75
|
-
this.logger.
|
|
81
|
+
this.logger.debug(`${role} has no transports, skipping ping`, address);
|
|
76
82
|
return;
|
|
77
83
|
}
|
|
78
|
-
const transports = address.libp2pTransports;
|
|
79
84
|
const key = address.toString();
|
|
80
85
|
let health = this.healthMap.get(key);
|
|
81
86
|
if (!health) {
|
|
@@ -98,10 +103,7 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
98
103
|
});
|
|
99
104
|
// Race between ping and timeout
|
|
100
105
|
// The ping service accepts PeerId as string or object
|
|
101
|
-
await Promise.race([
|
|
102
|
-
this.p2pNode.services.ping.ping(transports[0].toMultiaddr()),
|
|
103
|
-
timeoutPromise,
|
|
104
|
-
]);
|
|
106
|
+
await Promise.race([this.doPing(address), timeoutPromise]);
|
|
105
107
|
const latency = Date.now() - startTime;
|
|
106
108
|
// Success - update health
|
|
107
109
|
health.lastSuccessfulPing = Date.now();
|
|
@@ -121,7 +123,7 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
121
123
|
}
|
|
122
124
|
catch (error) {
|
|
123
125
|
health.consecutiveFailures++;
|
|
124
|
-
this.logger.warn(`Ping failed: ${address} (failures: ${health.consecutiveFailures}/${this.config.failureThreshold})
|
|
126
|
+
this.logger.warn(`Ping failed: ${address} (failures: ${health.consecutiveFailures}/${this.config.failureThreshold})`, error);
|
|
125
127
|
// Update status based on failure count
|
|
126
128
|
if (health.consecutiveFailures >= this.config.failureThreshold) {
|
|
127
129
|
this.handleConnectionDead(address, role, health);
|
|
@@ -141,20 +143,20 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
141
143
|
// Emit events based on role
|
|
142
144
|
if (role === 'child') {
|
|
143
145
|
// Remove dead child from hierarchy
|
|
144
|
-
this.
|
|
146
|
+
this.node.removeChild(address);
|
|
145
147
|
// Emit child left event
|
|
146
|
-
this.notificationManager.emit(new ChildLeftEvent({
|
|
147
|
-
source: this.address,
|
|
148
|
+
this.node.notificationManager.emit(new ChildLeftEvent({
|
|
149
|
+
source: this.node.address,
|
|
148
150
|
childAddress: address,
|
|
149
|
-
parentAddress: this.address,
|
|
151
|
+
parentAddress: this.node.address,
|
|
150
152
|
reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
|
|
151
153
|
}));
|
|
152
154
|
this.logger.warn(`Removed dead child: ${address}`);
|
|
153
155
|
}
|
|
154
156
|
else if (role === 'parent') {
|
|
155
157
|
// Emit parent disconnected event
|
|
156
|
-
this.notificationManager.emit(new ParentDisconnectedEvent({
|
|
157
|
-
source: this.address,
|
|
158
|
+
this.node.notificationManager.emit(new ParentDisconnectedEvent({
|
|
159
|
+
source: this.node.address,
|
|
158
160
|
parentAddress: address,
|
|
159
161
|
reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
|
|
160
162
|
}));
|
|
@@ -163,8 +165,8 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
163
165
|
}
|
|
164
166
|
else if (role === 'leader') {
|
|
165
167
|
// Emit leader disconnected event
|
|
166
|
-
this.notificationManager.emit(new LeaderDisconnectedEvent({
|
|
167
|
-
source: this.address,
|
|
168
|
+
this.node.notificationManager.emit(new LeaderDisconnectedEvent({
|
|
169
|
+
source: this.node.address,
|
|
168
170
|
leaderAddress: address,
|
|
169
171
|
reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
|
|
170
172
|
}));
|
|
@@ -175,8 +177,8 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
175
177
|
emitConnectionDegradedEvent(address, role, failures) {
|
|
176
178
|
// ConnectionDegradedEvent only supports parent/child, so we map leader to parent
|
|
177
179
|
const eventRole = role === 'leader' ? 'parent' : role === 'child' ? 'child' : 'parent';
|
|
178
|
-
this.notificationManager.emit(new ConnectionDegradedEvent({
|
|
179
|
-
source: this.address,
|
|
180
|
+
this.node.notificationManager.emit(new ConnectionDegradedEvent({
|
|
181
|
+
source: this.node.address,
|
|
180
182
|
targetAddress: address,
|
|
181
183
|
role: eventRole,
|
|
182
184
|
consecutiveFailures: failures,
|
|
@@ -185,8 +187,8 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
185
187
|
emitConnectionRecoveredEvent(address, role) {
|
|
186
188
|
// ConnectionRecoveredEvent only supports parent/child, so we map leader to parent
|
|
187
189
|
const eventRole = role === 'leader' ? 'parent' : role === 'child' ? 'child' : 'parent';
|
|
188
|
-
this.notificationManager.emit(new ConnectionRecoveredEvent({
|
|
189
|
-
source: this.address,
|
|
190
|
+
this.node.notificationManager.emit(new ConnectionRecoveredEvent({
|
|
191
|
+
source: this.node.address,
|
|
190
192
|
targetAddress: address,
|
|
191
193
|
role: eventRole,
|
|
192
194
|
}));
|
|
@@ -41,7 +41,7 @@ export declare class oReconnectionManager extends oObject {
|
|
|
41
41
|
/**
|
|
42
42
|
* Wait for non-leader parent to appear in registry and reconnect
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
waitForParentAndReconnect(): Promise<void>;
|
|
45
45
|
private handleReconnectionFailure;
|
|
46
46
|
private calculateNodeLevel;
|
|
47
47
|
private calculateBackoffDelay;
|
|
@@ -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,EAQR,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;YAoBb,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAQR,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;YAoBb,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IAiG/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
|
package/dist/src/o-node.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export declare class oNode extends oToolBase {
|
|
|
45
45
|
configure(): Promise<Libp2pConfig>;
|
|
46
46
|
protected createNode(): Promise<Libp2p>;
|
|
47
47
|
connect(nextHopAddress: oNodeAddress, targetAddress: oNodeAddress): Promise<oNodeConnection>;
|
|
48
|
+
postInitialize(): Promise<void>;
|
|
48
49
|
initialize(): Promise<void>;
|
|
49
50
|
/**
|
|
50
51
|
* Override use() to wrap leader/registry requests with retry logic
|
|
@@ -57,5 +58,9 @@ export declare class oNode extends oToolBase {
|
|
|
57
58
|
id?: string;
|
|
58
59
|
}): Promise<any>;
|
|
59
60
|
teardown(): Promise<void>;
|
|
61
|
+
getLeaders(): oNodeAddress[];
|
|
62
|
+
getParents(): oNodeAddress[];
|
|
63
|
+
getChildren(): oNodeAddress[];
|
|
64
|
+
removeChild(childAddress: oNodeAddress): void;
|
|
60
65
|
}
|
|
61
66
|
//# sourceMappingURL=o-node.d.ts.map
|
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,EAGL,MAAM,EACN,YAAY,EACb,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,EAIL,QAAQ,EACR,QAAQ,EAER,oBAAoB,EACrB,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;AAGnF,OAAO,EAAmB,SAAS,EAAE,MAAM,eAAe,CAAC;AAI3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,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;IACzD,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,oBAAoB,EAAG,oBAAoB,CAAC;IACnD,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;IAsD3B,cAAc,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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"}
|
package/dist/src/o-node.js
CHANGED
|
@@ -110,11 +110,20 @@ export class oNode extends oToolBase {
|
|
|
110
110
|
this.logger.debug('Skipping parent registration, node is leader');
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
|
+
if (!this.parent?.libp2pTransports?.length) {
|
|
114
|
+
this.logger.debug('Parent has no transports, waiting for reconnection & leader ack');
|
|
115
|
+
if (this.parent?.toString() === oAddress.leader().toString()) {
|
|
116
|
+
this.parent.setTransports(this.leader?.libp2pTransports || []);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
await this.reconnectionManager?.waitForParentAndReconnect();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
113
122
|
// if no parent transports, register with the parent to get them
|
|
114
123
|
// TODO: should we remove the transports check to make this more consistent?
|
|
115
|
-
if (this.config.parent
|
|
124
|
+
if (this.config.parent) {
|
|
116
125
|
this.logger.debug('Registering node with parent...', this.config.parent);
|
|
117
|
-
|
|
126
|
+
await this.use(this.config.parent, {
|
|
118
127
|
method: 'child_register',
|
|
119
128
|
params: {
|
|
120
129
|
address: this.address.toString(),
|
|
@@ -123,9 +132,6 @@ export class oNode extends oToolBase {
|
|
|
123
132
|
_token: this.config.joinToken,
|
|
124
133
|
},
|
|
125
134
|
});
|
|
126
|
-
const { parentTransports } = parentRegistration.result.data;
|
|
127
|
-
// update the parent transports
|
|
128
|
-
this.config.parent.setTransports(parentTransports.map((t) => new oNodeTransport(t)));
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
async register() {
|
|
@@ -281,6 +287,20 @@ export class oNode extends oToolBase {
|
|
|
281
287
|
}
|
|
282
288
|
return connection;
|
|
283
289
|
}
|
|
290
|
+
async postInitialize() {
|
|
291
|
+
// Initialize connection heartbeat manager
|
|
292
|
+
this.connectionHeartbeatManager = new oConnectionHeartbeatManager(this, {
|
|
293
|
+
enabled: this.config.connectionHeartbeat?.enabled ?? true,
|
|
294
|
+
intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
|
|
295
|
+
timeoutMs: this.config.connectionHeartbeat?.timeoutMs ?? 15000,
|
|
296
|
+
failureThreshold: this.config.connectionHeartbeat?.failureThreshold ?? 3,
|
|
297
|
+
checkChildren: this.config.connectionHeartbeat?.checkChildren ?? false,
|
|
298
|
+
checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
|
|
299
|
+
checkLeader: true,
|
|
300
|
+
});
|
|
301
|
+
this.logger.info(`Connection heartbeat config: leader=${this.connectionHeartbeatManager.getConfig().checkLeader}, ` +
|
|
302
|
+
`parent=${this.connectionHeartbeatManager.getConfig().checkParent}`);
|
|
303
|
+
}
|
|
284
304
|
async initialize() {
|
|
285
305
|
this.logger.debug('Initializing node...');
|
|
286
306
|
if (this.p2pNode && this.state !== NodeState.STOPPED) {
|
|
@@ -328,18 +348,6 @@ export class oNode extends oToolBase {
|
|
|
328
348
|
// Read ENABLE_LEADER_HEARTBEAT environment variable
|
|
329
349
|
const enableLeaderHeartbeat = this.parent?.toString() === oAddress.leader().toString();
|
|
330
350
|
this.logger.debug(`Enable leader heartbeat: ${enableLeaderHeartbeat}`);
|
|
331
|
-
// Initialize connection heartbeat manager
|
|
332
|
-
this.connectionHeartbeatManager = new oConnectionHeartbeatManager(this.p2pNode, this.hierarchyManager, this.notificationManager, this.address, {
|
|
333
|
-
enabled: this.config.connectionHeartbeat?.enabled ?? true,
|
|
334
|
-
intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
|
|
335
|
-
timeoutMs: this.config.connectionHeartbeat?.timeoutMs ?? 5000,
|
|
336
|
-
failureThreshold: this.config.connectionHeartbeat?.failureThreshold ?? 3,
|
|
337
|
-
checkChildren: this.config.connectionHeartbeat?.checkChildren ?? true,
|
|
338
|
-
checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
|
|
339
|
-
checkLeader: enableLeaderHeartbeat,
|
|
340
|
-
});
|
|
341
|
-
this.logger.info(`Connection heartbeat config: leader=${this.connectionHeartbeatManager.getConfig().checkLeader}, ` +
|
|
342
|
-
`parent=${this.connectionHeartbeatManager.getConfig().checkParent}`);
|
|
343
351
|
// Initialize reconnection manager
|
|
344
352
|
if (this.config.reconnection?.enabled !== false) {
|
|
345
353
|
this.reconnectionManager = new oReconnectionManager(this, {
|
|
@@ -371,4 +379,17 @@ export class oNode extends oToolBase {
|
|
|
371
379
|
await this.p2pNode.stop();
|
|
372
380
|
}
|
|
373
381
|
}
|
|
382
|
+
// IHeartbeatableNode interface methods
|
|
383
|
+
getLeaders() {
|
|
384
|
+
return [this.leader];
|
|
385
|
+
}
|
|
386
|
+
getParents() {
|
|
387
|
+
return this.hierarchyManager.getParents();
|
|
388
|
+
}
|
|
389
|
+
getChildren() {
|
|
390
|
+
return this.hierarchyManager.getChildren();
|
|
391
|
+
}
|
|
392
|
+
removeChild(childAddress) {
|
|
393
|
+
this.hierarchyManager.removeChild(childAddress);
|
|
394
|
+
}
|
|
374
395
|
}
|
|
@@ -21,7 +21,8 @@ export class oNodeRoutingPolicy extends oRoutingPolicy {
|
|
|
21
21
|
nodeAddress.libp2pTransports?.length > 0) {
|
|
22
22
|
// transports are provided, let's see if they match our known leaders
|
|
23
23
|
const isLeaderRef = nodeAddress.toString() === oAddress.leader().toString();
|
|
24
|
-
const isOurLeaderRef = node.
|
|
24
|
+
const isOurLeaderRef = node.address.equals(nodeAddress) ||
|
|
25
|
+
node.hierarchyManager.leaders.some((l) => l.equals(nodeAddress));
|
|
25
26
|
return isLeaderRef || isOurLeaderRef;
|
|
26
27
|
}
|
|
27
28
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.12-alpha.
|
|
3
|
+
"version": "0.7.12-alpha.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"typescript": "5.4.5"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@olane/o-config": "0.7.12-alpha.
|
|
58
|
-
"@olane/o-core": "0.7.12-alpha.
|
|
59
|
-
"@olane/o-protocol": "0.7.12-alpha.
|
|
60
|
-
"@olane/o-tool": "0.7.12-alpha.
|
|
57
|
+
"@olane/o-config": "0.7.12-alpha.13",
|
|
58
|
+
"@olane/o-core": "0.7.12-alpha.13",
|
|
59
|
+
"@olane/o-protocol": "0.7.12-alpha.13",
|
|
60
|
+
"@olane/o-tool": "0.7.12-alpha.13",
|
|
61
61
|
"debug": "^4.4.1",
|
|
62
62
|
"dotenv": "^16.5.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "dad019b117feb02f74eeec70de9ee82b76b68f6c"
|
|
65
65
|
}
|