@olane/o-node 0.7.28 → 0.7.31
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/o-node-connection.js +3 -3
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +3 -3
- package/dist/src/connection/stream-handler.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.js +0 -1
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.js +6 -3
- package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
- package/dist/src/managers/o-reconnection.manager.js +34 -21
- package/dist/src/o-node.d.ts +6 -2
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.hierarchy-manager.d.ts +41 -0
- package/dist/src/o-node.hierarchy-manager.d.ts.map +1 -1
- package/dist/src/o-node.hierarchy-manager.js +170 -1
- package/dist/src/o-node.js +71 -29
- package/dist/src/o-node.notification-manager.d.ts +6 -17
- package/dist/src/o-node.notification-manager.d.ts.map +1 -1
- package/dist/src/o-node.notification-manager.js +40 -119
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +6 -1
- package/package.json +7 -7
|
@@ -33,9 +33,9 @@ export class oNodeConnection extends oConnection {
|
|
|
33
33
|
}
|
|
34
34
|
async transmit(request) {
|
|
35
35
|
try {
|
|
36
|
-
if (this.config.runOnLimitedConnection) {
|
|
37
|
-
|
|
38
|
-
}
|
|
36
|
+
// if (this.config.runOnLimitedConnection) {
|
|
37
|
+
// this.logger.debug('Running on limited connection...');
|
|
38
|
+
// }
|
|
39
39
|
const stream = await this.getOrCreateStream();
|
|
40
40
|
this.validate(stream);
|
|
41
41
|
const streamConfig = {
|
|
@@ -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;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,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,CACtB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;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;YA+DR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAwCpC;;;;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;CAgBlC"}
|
|
@@ -22,7 +22,7 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
22
22
|
if (!connection) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
for (const [transportKey, cachedConnection] of this.connectionsByTransportKey.entries()) {
|
|
25
|
+
for (const [transportKey, cachedConnection,] of this.connectionsByTransportKey.entries()) {
|
|
26
26
|
if (cachedConnection === connection) {
|
|
27
27
|
this.logger.debug('Connection closed, removing from cache for transport key:', transportKey);
|
|
28
28
|
this.connectionsByTransportKey.delete(transportKey);
|
|
@@ -83,7 +83,7 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
83
83
|
// Check if we have a cached connection by transport key
|
|
84
84
|
const cachedConnection = this.connectionsByTransportKey.get(transportKey);
|
|
85
85
|
if (cachedConnection && cachedConnection.status === 'open') {
|
|
86
|
-
this.logger.debug('Reusing cached connection for transports:', nextHopAddress);
|
|
86
|
+
this.logger.debug('Reusing cached connection for transports:', nextHopAddress?.value);
|
|
87
87
|
return cachedConnection;
|
|
88
88
|
}
|
|
89
89
|
// Clean up stale connection if it exists but is not open
|
|
@@ -249,7 +249,7 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
249
249
|
*/
|
|
250
250
|
cleanupStaleConnections() {
|
|
251
251
|
let removed = 0;
|
|
252
|
-
for (const [transportKey, connection] of this.connectionsByTransportKey.entries()) {
|
|
252
|
+
for (const [transportKey, connection,] of this.connectionsByTransportKey.entries()) {
|
|
253
253
|
if (connection.status !== 'open') {
|
|
254
254
|
this.connectionsByTransportKey.delete(transportKey);
|
|
255
255
|
removed++;
|
|
@@ -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;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;
|
|
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;IAiB5E;;;;;;;;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;IAsChB;;;;;;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;IA8GrB;;;;;;;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"}
|
|
@@ -98,7 +98,6 @@ export class StreamHandler {
|
|
|
98
98
|
try {
|
|
99
99
|
// force the close for now until we can implement a proper close
|
|
100
100
|
await stream.abort(new Error('Stream closed'));
|
|
101
|
-
this.logger.debug('Stream closed successfully');
|
|
102
101
|
}
|
|
103
102
|
catch (error) {
|
|
104
103
|
this.logger.debug('Error closing stream:', error.message);
|
|
@@ -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;YAgDf,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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { oObject, ChildLeftEvent, ParentDisconnectedEvent, LeaderDisconnectedEvent, ConnectionDegradedEvent, ConnectionRecoveredEvent, oAddress, } from '@olane/o-core';
|
|
2
|
+
import { oNodeAddress } from '../router/o-node.address.js';
|
|
2
3
|
/**
|
|
3
4
|
* Connection Health Monitor
|
|
4
5
|
*
|
|
@@ -100,9 +101,11 @@ export class oConnectionHeartbeatManager extends oObject {
|
|
|
100
101
|
return true;
|
|
101
102
|
}
|
|
102
103
|
// check via ping
|
|
103
|
-
const pingResponse = this.node
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const pingResponse = this.node
|
|
105
|
+
.use(new oNodeAddress(address?.value), {
|
|
106
|
+
method: 'ping',
|
|
107
|
+
})
|
|
108
|
+
.catch((err) => {
|
|
106
109
|
if (err.message === 'Can not dial self') {
|
|
107
110
|
return true;
|
|
108
111
|
}
|
|
@@ -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;
|
|
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;YAoBtB,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IA4G/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -32,6 +32,7 @@ export class oReconnectionManager extends oObject {
|
|
|
32
32
|
}
|
|
33
33
|
async handleNodeConnected(event) {
|
|
34
34
|
const connectedEvent = event;
|
|
35
|
+
// if leader is back online re-register
|
|
35
36
|
if (connectedEvent.nodeAddress.toString() === oAddress.leader().toString()) {
|
|
36
37
|
// the leader is back online, let's re-register & tell sub-graphs to re-register
|
|
37
38
|
await this.node.useSelf({
|
|
@@ -39,6 +40,10 @@ export class oReconnectionManager extends oObject {
|
|
|
39
40
|
params: {},
|
|
40
41
|
});
|
|
41
42
|
}
|
|
43
|
+
if (connectedEvent.nodeAddress.toString() === this.node.config.parent?.value) {
|
|
44
|
+
// connect to the parent and register
|
|
45
|
+
await this.node.registerParent();
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
async handleConnectionDegraded(event) {
|
|
44
49
|
const degradedEvent = event;
|
|
@@ -73,26 +78,32 @@ export class oReconnectionManager extends oObject {
|
|
|
73
78
|
}
|
|
74
79
|
this.reconnecting = true;
|
|
75
80
|
let attempt = 0;
|
|
76
|
-
while (attempt < this.config.maxAttempts) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
// while (attempt < this.config.maxAttempts) {
|
|
82
|
+
// attempt++;
|
|
83
|
+
// this.logger.info(
|
|
84
|
+
// `Reconnection attempt ${attempt}/${this.config.maxAttempts} to parent: ${this.node.config.parent}`,
|
|
85
|
+
// );
|
|
86
|
+
// try {
|
|
87
|
+
// // Strategy 1: Try direct parent reconnection
|
|
88
|
+
// await this.tryDirectParentReconnection();
|
|
89
|
+
// // Success!
|
|
90
|
+
// this.reconnecting = false;
|
|
91
|
+
// this.logger.info(
|
|
92
|
+
// `Successfully reconnected to parent after ${attempt} attempts`,
|
|
93
|
+
// );
|
|
94
|
+
// return;
|
|
95
|
+
// } catch (error) {
|
|
96
|
+
// this.logger.warn(
|
|
97
|
+
// `Reconnection attempt ${attempt} failed:`,
|
|
98
|
+
// error instanceof Error ? error.message : error,
|
|
99
|
+
// );
|
|
100
|
+
// if (attempt < this.config.maxAttempts) {
|
|
101
|
+
// const delay = this.calculateBackoffDelay(attempt);
|
|
102
|
+
// this.logger.debug(`Waiting ${delay}ms before next attempt...`);
|
|
103
|
+
// await this.sleep(delay);
|
|
104
|
+
// }
|
|
105
|
+
// }
|
|
106
|
+
// }
|
|
96
107
|
// All direct attempts failed - try leader fallback
|
|
97
108
|
if (this.config.useLeaderFallback) {
|
|
98
109
|
await this.tryLeaderFallback();
|
|
@@ -186,6 +197,7 @@ export class oReconnectionManager extends oObject {
|
|
|
186
197
|
* Wait for non-leader parent to appear in registry and reconnect
|
|
187
198
|
*/
|
|
188
199
|
async waitForParentAndReconnect() {
|
|
200
|
+
this.logger.debug('waitForParentAndReconnect...');
|
|
189
201
|
const startTime = Date.now();
|
|
190
202
|
let attempt = 0;
|
|
191
203
|
let currentDelay = this.config.parentDiscoveryIntervalMs;
|
|
@@ -202,7 +214,8 @@ export class oReconnectionManager extends oObject {
|
|
|
202
214
|
if (!this.node.config.parent) {
|
|
203
215
|
throw new Error('Invalid parent definition');
|
|
204
216
|
}
|
|
205
|
-
|
|
217
|
+
this.logger.debug('Calling parent identify');
|
|
218
|
+
const response = await this.node.use(new oNodeAddress(this.node.config.parent.value), {
|
|
206
219
|
method: 'identify',
|
|
207
220
|
params: {},
|
|
208
221
|
});
|
package/dist/src/o-node.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export declare class oNode extends oToolBase {
|
|
|
21
21
|
connectionHeartbeatManager?: oConnectionHeartbeatManager;
|
|
22
22
|
protected reconnectionManager?: oReconnectionManager;
|
|
23
23
|
protected didRegister: boolean;
|
|
24
|
+
protected hooksStartFinished: any[];
|
|
25
|
+
protected hooksInitFinished: any[];
|
|
24
26
|
constructor(config: oNodeConfig);
|
|
25
27
|
get leader(): oNodeAddress | null;
|
|
26
28
|
get networkConfig(): Libp2pConfig;
|
|
@@ -47,8 +49,10 @@ export declare class oNode extends oToolBase {
|
|
|
47
49
|
protected createNode(): Promise<Libp2p>;
|
|
48
50
|
connect(config: oNodeConnectionConfig): Promise<oNodeConnection>;
|
|
49
51
|
initConnectionManager(): Promise<void>;
|
|
50
|
-
hookInitializeFinished(): Promise<void>;
|
|
51
|
-
|
|
52
|
+
protected hookInitializeFinished(): Promise<void>;
|
|
53
|
+
onInitFinished(cb: Function): void;
|
|
54
|
+
onStartFinished(cb: Function): void;
|
|
55
|
+
protected hookStartFinished(): Promise<void>;
|
|
52
56
|
/**
|
|
53
57
|
* Validates that if a leader address is defined, it has associated transports.
|
|
54
58
|
* This is critical for non-leader nodes to be able to connect to their leader.
|
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;
|
|
1
|
+
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
import { oHierarchyManager, oHierarchyManagerConfig } from '@olane/o-core';
|
|
2
2
|
import { oNodeAddress } from './router/o-node.address.js';
|
|
3
|
+
import { oNodeNotificationManager } from './o-node.notification-manager.js';
|
|
3
4
|
export interface oNodeHierarchyManagerConfig extends oHierarchyManagerConfig {
|
|
4
5
|
leaders: oNodeAddress[];
|
|
5
6
|
children: oNodeAddress[];
|
|
6
7
|
parents: oNodeAddress[];
|
|
8
|
+
notificationManager?: oNodeNotificationManager;
|
|
9
|
+
address: oNodeAddress;
|
|
7
10
|
}
|
|
8
11
|
export declare class oNodeHierarchyManager extends oHierarchyManager {
|
|
9
12
|
leaders: oNodeAddress[];
|
|
10
13
|
children: oNodeAddress[];
|
|
11
14
|
parents: oNodeAddress[];
|
|
15
|
+
private notificationManager?;
|
|
16
|
+
private address;
|
|
12
17
|
constructor(config: oNodeHierarchyManagerConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Set up event listeners to react to notification manager's peer events
|
|
20
|
+
*/
|
|
21
|
+
setupEventListeners(notificationManager: oNodeNotificationManager): void;
|
|
13
22
|
get leader(): oNodeAddress | null;
|
|
23
|
+
/**
|
|
24
|
+
* Handle peer connected event from notification manager
|
|
25
|
+
* Resolves peer ID to address and emits hierarchy-aware events
|
|
26
|
+
*/
|
|
27
|
+
private handlePeerConnected;
|
|
28
|
+
/**
|
|
29
|
+
* Handle peer disconnected event from notification manager
|
|
30
|
+
* Resolves peer ID to address and emits hierarchy-aware events
|
|
31
|
+
*/
|
|
32
|
+
private handlePeerDisconnected;
|
|
33
|
+
/**
|
|
34
|
+
* Handle peer discovered event from notification manager
|
|
35
|
+
* Resolves peer ID to address and emits node discovered event
|
|
36
|
+
*/
|
|
37
|
+
private handlePeerDiscovered;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a libp2p peer ID to an Olane address
|
|
40
|
+
* Checks children, parents, and leaders for matching transports
|
|
41
|
+
*/
|
|
42
|
+
peerIdToAddress(peerId: string): oNodeAddress | null;
|
|
43
|
+
/**
|
|
44
|
+
* Check if an address is a direct child
|
|
45
|
+
*/
|
|
46
|
+
isChild(address: oNodeAddress): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if an address is a parent
|
|
49
|
+
*/
|
|
50
|
+
isParent(address: oNodeAddress): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if an address is a leader
|
|
53
|
+
*/
|
|
54
|
+
isLeader(address: oNodeAddress): boolean;
|
|
14
55
|
}
|
|
15
56
|
//# sourceMappingURL=o-node.hierarchy-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.hierarchy-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.hierarchy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"o-node.hierarchy-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.hierarchy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EAaxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,WAAW,2BAA4B,SAAQ,uBAAuB;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;IACnD,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAM;IACpC,OAAO,CAAC,mBAAmB,CAAC,CAA2B;IACvD,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,2BAA2B;IAW/C;;OAEG;IACH,mBAAmB,CAAC,mBAAmB,EAAE,wBAAwB,GAAG,IAAI;IAqBxE,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;IAED;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA8C3B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAuD9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAqCpD;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAMvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAMxC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;CAKzC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { oHierarchyManager } from '@olane/o-core';
|
|
1
|
+
import { oHierarchyManager, NodeConnectedEvent, NodeDisconnectedEvent, NodeDiscoveredEvent, ChildJoinedEvent, ChildLeftEvent, ParentConnectedEvent, ParentDisconnectedEvent, LeaderDisconnectedEvent, } from '@olane/o-core';
|
|
2
2
|
export class oNodeHierarchyManager extends oHierarchyManager {
|
|
3
3
|
constructor(config) {
|
|
4
4
|
super(config);
|
|
@@ -8,8 +8,177 @@ export class oNodeHierarchyManager extends oHierarchyManager {
|
|
|
8
8
|
this.leaders = config.leaders || [];
|
|
9
9
|
this.children = config.children || [];
|
|
10
10
|
this.parents = config.parents || [];
|
|
11
|
+
this.address = config.address;
|
|
12
|
+
if (config.notificationManager) {
|
|
13
|
+
this.setupEventListeners(config.notificationManager);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Set up event listeners to react to notification manager's peer events
|
|
18
|
+
*/
|
|
19
|
+
setupEventListeners(notificationManager) {
|
|
20
|
+
this.logger.info('received notification manager, going to listen for key events');
|
|
21
|
+
this.notificationManager = notificationManager;
|
|
22
|
+
// Listen to peer connection events
|
|
23
|
+
this.notificationManager.on('peer:connected', this.handlePeerConnected.bind(this));
|
|
24
|
+
this.notificationManager.on('peer:disconnected', this.handlePeerDisconnected.bind(this));
|
|
25
|
+
this.notificationManager.on('peer:discovered', this.handlePeerDiscovered.bind(this));
|
|
11
26
|
}
|
|
12
27
|
get leader() {
|
|
13
28
|
return this.leaders.length > 0 ? this.leaders[0] : null;
|
|
14
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Handle peer connected event from notification manager
|
|
32
|
+
* Resolves peer ID to address and emits hierarchy-aware events
|
|
33
|
+
*/
|
|
34
|
+
handlePeerConnected(event) {
|
|
35
|
+
const peerEvent = event;
|
|
36
|
+
const peerId = peerEvent.peerId;
|
|
37
|
+
// Try to resolve peer ID to Olane address
|
|
38
|
+
const nodeAddress = this.peerIdToAddress(peerId);
|
|
39
|
+
if (!nodeAddress) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Emit generic node connected event through notification manager
|
|
43
|
+
this.notificationManager.emit(new NodeConnectedEvent({
|
|
44
|
+
source: this.address,
|
|
45
|
+
nodeAddress,
|
|
46
|
+
connectionMetadata: {
|
|
47
|
+
peerId,
|
|
48
|
+
transport: 'libp2p',
|
|
49
|
+
...peerEvent.connectionMetadata,
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
// Check if this is a child node
|
|
53
|
+
if (this.isChild(nodeAddress)) {
|
|
54
|
+
this.notificationManager.emit(new ChildJoinedEvent({
|
|
55
|
+
source: this.address,
|
|
56
|
+
childAddress: nodeAddress,
|
|
57
|
+
parentAddress: this.address,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
// Check if this is a parent node
|
|
61
|
+
if (this.isParent(nodeAddress)) {
|
|
62
|
+
this.notificationManager.emit(new ParentConnectedEvent({
|
|
63
|
+
source: this.address,
|
|
64
|
+
parentAddress: nodeAddress,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Handle peer disconnected event from notification manager
|
|
70
|
+
* Resolves peer ID to address and emits hierarchy-aware events
|
|
71
|
+
*/
|
|
72
|
+
handlePeerDisconnected(event) {
|
|
73
|
+
const peerEvent = event;
|
|
74
|
+
const peerId = peerEvent.peerId;
|
|
75
|
+
// Try to resolve peer ID to Olane address
|
|
76
|
+
const nodeAddress = this.peerIdToAddress(peerId);
|
|
77
|
+
if (!nodeAddress) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Emit generic node disconnected event through notification manager
|
|
81
|
+
this.notificationManager.emit(new NodeDisconnectedEvent({
|
|
82
|
+
source: this.address,
|
|
83
|
+
nodeAddress,
|
|
84
|
+
reason: peerEvent.reason || 'peer_disconnected',
|
|
85
|
+
}));
|
|
86
|
+
// Check if this is a child node
|
|
87
|
+
if (this.isChild(nodeAddress)) {
|
|
88
|
+
this.notificationManager.emit(new ChildLeftEvent({
|
|
89
|
+
source: this.address,
|
|
90
|
+
childAddress: nodeAddress,
|
|
91
|
+
parentAddress: this.address,
|
|
92
|
+
reason: peerEvent.reason || 'peer_disconnected',
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
// Check if this is a parent node
|
|
96
|
+
if (this.isParent(nodeAddress)) {
|
|
97
|
+
this.notificationManager.emit(new ParentDisconnectedEvent({
|
|
98
|
+
source: this.address,
|
|
99
|
+
parentAddress: nodeAddress,
|
|
100
|
+
reason: peerEvent.reason || 'peer_disconnected',
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
// Check if this is a leader node
|
|
104
|
+
if (this.isLeader(nodeAddress)) {
|
|
105
|
+
this.notificationManager.emit(new LeaderDisconnectedEvent({
|
|
106
|
+
source: this.address,
|
|
107
|
+
leaderAddress: nodeAddress,
|
|
108
|
+
reason: peerEvent.reason || 'peer_disconnected',
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Handle peer discovered event from notification manager
|
|
114
|
+
* Resolves peer ID to address and emits node discovered event
|
|
115
|
+
*/
|
|
116
|
+
handlePeerDiscovered(event) {
|
|
117
|
+
const peerEvent = event;
|
|
118
|
+
const peerId = peerEvent.peerId;
|
|
119
|
+
// Try to resolve peer ID to Olane address
|
|
120
|
+
const nodeAddress = this.peerIdToAddress(peerId);
|
|
121
|
+
if (!nodeAddress) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.notificationManager.emit(new NodeDiscoveredEvent({
|
|
125
|
+
source: this.address,
|
|
126
|
+
nodeAddress,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Resolve a libp2p peer ID to an Olane address
|
|
131
|
+
* Checks children, parents, and leaders for matching transports
|
|
132
|
+
*/
|
|
133
|
+
peerIdToAddress(peerId) {
|
|
134
|
+
// Check children
|
|
135
|
+
for (const child of this.children) {
|
|
136
|
+
const childTransports = child.libp2pTransports;
|
|
137
|
+
for (const transport of childTransports) {
|
|
138
|
+
if (transport.toString().includes(peerId)) {
|
|
139
|
+
return child;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Check parents
|
|
144
|
+
for (const parent of this.parents) {
|
|
145
|
+
const parentTransports = parent.libp2pTransports;
|
|
146
|
+
if (parentTransports?.length === 0) {
|
|
147
|
+
this.logger.error('Parent does not have transports fail!');
|
|
148
|
+
}
|
|
149
|
+
for (const transport of parentTransports) {
|
|
150
|
+
if (transport.toString().includes(peerId)) {
|
|
151
|
+
return parent;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Check leaders
|
|
156
|
+
for (const leader of this.leaders) {
|
|
157
|
+
const leaderTransports = leader.libp2pTransports;
|
|
158
|
+
for (const transport of leaderTransports) {
|
|
159
|
+
if (transport.toString().includes(peerId)) {
|
|
160
|
+
return leader;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if an address is a direct child
|
|
168
|
+
*/
|
|
169
|
+
isChild(address) {
|
|
170
|
+
return this.children.some((child) => child.toString() === address.toString());
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if an address is a parent
|
|
174
|
+
*/
|
|
175
|
+
isParent(address) {
|
|
176
|
+
return this.parents.some((parent) => parent.toString() === address.toString());
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if an address is a leader
|
|
180
|
+
*/
|
|
181
|
+
isLeader(address) {
|
|
182
|
+
return this.leaders.some((leader) => leader.toString() === address.toString());
|
|
183
|
+
}
|
|
15
184
|
}
|
package/dist/src/o-node.js
CHANGED
|
@@ -10,12 +10,13 @@ import { oNodeResolver } from './router/resolvers/o-node.resolver.js';
|
|
|
10
10
|
import { oMethodResolver, oToolBase } from '@olane/o-tool';
|
|
11
11
|
import { oLeaderResolverFallback } from './router/index.js';
|
|
12
12
|
import { oNodeNotificationManager } from './o-node.notification-manager.js';
|
|
13
|
-
import { oConnectionHeartbeatManager } from './managers/o-connection-heartbeat.manager.js';
|
|
14
13
|
import { oReconnectionManager } from './managers/o-reconnection.manager.js';
|
|
15
14
|
export class oNode extends oToolBase {
|
|
16
15
|
constructor(config) {
|
|
17
16
|
super(config);
|
|
18
17
|
this.didRegister = false;
|
|
18
|
+
this.hooksStartFinished = [];
|
|
19
|
+
this.hooksInitFinished = [];
|
|
19
20
|
this.config = config;
|
|
20
21
|
}
|
|
21
22
|
get leader() {
|
|
@@ -39,15 +40,10 @@ export class oNode extends oToolBase {
|
|
|
39
40
|
return [...(defaultLibp2pConfig.transports || [])];
|
|
40
41
|
}
|
|
41
42
|
async initializeRouter() {
|
|
42
|
-
this.hierarchyManager = new oNodeHierarchyManager({
|
|
43
|
-
leaders: this.config.leader ? [this.config.leader] : [],
|
|
44
|
-
parents: this.config.parent ? [this.config.parent] : [],
|
|
45
|
-
children: [],
|
|
46
|
-
});
|
|
47
43
|
this.router = new oNodeRouter();
|
|
48
44
|
}
|
|
49
45
|
createNotificationManager() {
|
|
50
|
-
return new oNodeNotificationManager(this.p2pNode, this.
|
|
46
|
+
return new oNodeNotificationManager(this.p2pNode, this.address);
|
|
51
47
|
}
|
|
52
48
|
get staticAddress() {
|
|
53
49
|
return this.config.address;
|
|
@@ -150,7 +146,7 @@ export class oNode extends oToolBase {
|
|
|
150
146
|
this.parent.setTransports(this.leader?.libp2pTransports || []);
|
|
151
147
|
}
|
|
152
148
|
else {
|
|
153
|
-
this.logger.debug('Waiting for parent and reconnecting...');
|
|
149
|
+
this.logger.debug('Waiting for parent and reconnecting... hello');
|
|
154
150
|
await this.reconnectionManager?.waitForParentAndReconnect();
|
|
155
151
|
}
|
|
156
152
|
}
|
|
@@ -169,6 +165,7 @@ export class oNode extends oToolBase {
|
|
|
169
165
|
},
|
|
170
166
|
});
|
|
171
167
|
this.setKeepAliveTag(this.parent);
|
|
168
|
+
this.hierarchyManager.addParent(this.parent);
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
171
|
async registerLeader() {
|
|
@@ -355,22 +352,56 @@ export class oNode extends oToolBase {
|
|
|
355
352
|
defaultReadTimeoutMs: this.config.connectionTimeouts?.readTimeoutMs,
|
|
356
353
|
defaultDrainTimeoutMs: this.config.connectionTimeouts?.drainTimeoutMs,
|
|
357
354
|
runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
|
|
358
|
-
originAddress: this.address?.value
|
|
355
|
+
originAddress: this.address?.value,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
async hookInitializeFinished() {
|
|
359
|
+
this.logger.debug('Running init-finished hooks');
|
|
360
|
+
this.hooksInitFinished.forEach((hook) => {
|
|
361
|
+
try {
|
|
362
|
+
hook();
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
this.logger.error('Failed to run hook:', error);
|
|
366
|
+
}
|
|
359
367
|
});
|
|
368
|
+
this.logger.debug('Completed init-finished hooks');
|
|
369
|
+
}
|
|
370
|
+
onInitFinished(cb) {
|
|
371
|
+
this.hooksInitFinished.push(cb);
|
|
372
|
+
}
|
|
373
|
+
onStartFinished(cb) {
|
|
374
|
+
this.hooksStartFinished.push(cb);
|
|
360
375
|
}
|
|
361
|
-
async hookInitializeFinished() { }
|
|
362
376
|
async hookStartFinished() {
|
|
377
|
+
await super.hookStartFinished();
|
|
363
378
|
// Initialize connection health monitor
|
|
364
|
-
this.connectionHeartbeatManager = new oConnectionHeartbeatManager(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
379
|
+
// this.connectionHeartbeatManager = new oConnectionHeartbeatManager(
|
|
380
|
+
// this as any,
|
|
381
|
+
// {
|
|
382
|
+
// enabled: this.config.connectionHeartbeat?.enabled ?? true,
|
|
383
|
+
// intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
|
|
384
|
+
// failureThreshold:
|
|
385
|
+
// this.config.connectionHeartbeat?.failureThreshold ?? 3,
|
|
386
|
+
// checkChildren: this.config.connectionHeartbeat?.checkChildren ?? false,
|
|
387
|
+
// checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
|
|
388
|
+
// checkLeader: true,
|
|
389
|
+
// },
|
|
390
|
+
// );
|
|
391
|
+
// this.logger.info(
|
|
392
|
+
// `Connection heartbeat config: leader=${this.connectionHeartbeatManager.getConfig().checkLeader}, ` +
|
|
393
|
+
// `parent=${this.connectionHeartbeatManager.getConfig().checkParent}`,
|
|
394
|
+
// );
|
|
395
|
+
this.logger.debug('Running start-finished hooks');
|
|
396
|
+
this.hooksStartFinished.forEach((hook) => {
|
|
397
|
+
try {
|
|
398
|
+
hook();
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
this.logger.error('Failed to run hook:', error);
|
|
402
|
+
}
|
|
371
403
|
});
|
|
372
|
-
this.logger.
|
|
373
|
-
`parent=${this.connectionHeartbeatManager.getConfig().checkParent}`);
|
|
404
|
+
this.logger.debug('Completed start-finished hooks');
|
|
374
405
|
}
|
|
375
406
|
/**
|
|
376
407
|
* Validates that if a leader address is defined, it has associated transports.
|
|
@@ -395,7 +426,7 @@ export class oNode extends oToolBase {
|
|
|
395
426
|
}
|
|
396
427
|
this.logger.debug('Leader transport validation passed', {
|
|
397
428
|
leader: leaderAddress.toString(),
|
|
398
|
-
transportCount: leaderAddress.transports.length
|
|
429
|
+
transportCount: leaderAddress.transports.length,
|
|
399
430
|
});
|
|
400
431
|
}
|
|
401
432
|
/**
|
|
@@ -417,7 +448,26 @@ export class oNode extends oToolBase {
|
|
|
417
448
|
throw new Error('Invalid address');
|
|
418
449
|
}
|
|
419
450
|
await this.createNode();
|
|
451
|
+
// Create and initialize notification manager
|
|
452
|
+
this.notificationManager = this.createNotificationManager();
|
|
453
|
+
await this.notificationManager.initialize();
|
|
420
454
|
await this.initializeRouter();
|
|
455
|
+
this.hierarchyManager = new oNodeHierarchyManager({
|
|
456
|
+
leaders: this.config.leader ? [this.config.leader] : [],
|
|
457
|
+
parents: this.config.parent ? [this.config.parent] : [],
|
|
458
|
+
children: [],
|
|
459
|
+
address: this.address,
|
|
460
|
+
notificationManager: this.notificationManager,
|
|
461
|
+
});
|
|
462
|
+
this.reconnectionManager = new oReconnectionManager(this, {
|
|
463
|
+
enabled: true,
|
|
464
|
+
maxAttempts: 10,
|
|
465
|
+
baseDelayMs: 5000,
|
|
466
|
+
maxDelayMs: 20000,
|
|
467
|
+
useLeaderFallback: true,
|
|
468
|
+
parentDiscoveryIntervalMs: 5000,
|
|
469
|
+
parentDiscoveryMaxDelayMs: 20000,
|
|
470
|
+
});
|
|
421
471
|
// need to wait until our libpp2 node is initialized before calling super.initialize
|
|
422
472
|
await super.initialize();
|
|
423
473
|
this.logger.debug('Node initialized!', this.transports.map((t) => t.toString()));
|
|
@@ -433,15 +483,6 @@ export class oNode extends oToolBase {
|
|
|
433
483
|
this.logger.debug('Adding leader resolver fallback...');
|
|
434
484
|
this.router.addResolver(new oLeaderResolverFallback(this.address));
|
|
435
485
|
}
|
|
436
|
-
this.reconnectionManager = new oReconnectionManager(this, {
|
|
437
|
-
enabled: true,
|
|
438
|
-
maxAttempts: 10,
|
|
439
|
-
baseDelayMs: 5000,
|
|
440
|
-
maxDelayMs: 20000,
|
|
441
|
-
useLeaderFallback: true,
|
|
442
|
-
parentDiscoveryIntervalMs: 5000,
|
|
443
|
-
parentDiscoveryMaxDelayMs: 20000,
|
|
444
|
-
});
|
|
445
486
|
await this.hookInitializeFinished();
|
|
446
487
|
}
|
|
447
488
|
/**
|
|
@@ -495,6 +536,7 @@ export class oNode extends oToolBase {
|
|
|
495
536
|
leaders: this.config.leader ? [this.config.leader] : [],
|
|
496
537
|
parents: this.config.parent ? [this.config.parent] : [],
|
|
497
538
|
children: [],
|
|
539
|
+
address: this.address,
|
|
498
540
|
});
|
|
499
541
|
// Clear router (will be recreated in initialize)
|
|
500
542
|
this.router = undefined;
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { Libp2p } from '@olane/o-config';
|
|
2
2
|
import { oNotificationManager } from '@olane/o-core';
|
|
3
3
|
import { oNodeAddress } from './router/o-node.address.js';
|
|
4
|
-
import { oNodeHierarchyManager } from './o-node.hierarchy-manager.js';
|
|
5
4
|
/**
|
|
6
5
|
* libp2p-specific implementation of oNotificationManager
|
|
7
|
-
*
|
|
6
|
+
* Emits low-level peer connection events without hierarchy awareness
|
|
8
7
|
*/
|
|
9
8
|
export declare class oNodeNotificationManager extends oNotificationManager {
|
|
10
9
|
private p2pNode;
|
|
11
|
-
private hierarchyManager;
|
|
12
10
|
private address;
|
|
13
|
-
constructor(p2pNode: Libp2p,
|
|
11
|
+
constructor(p2pNode: Libp2p, address: oNodeAddress);
|
|
14
12
|
/**
|
|
15
13
|
* Wire up libp2p event listeners
|
|
16
14
|
*/
|
|
17
15
|
protected setupListeners(): void;
|
|
18
16
|
/**
|
|
19
17
|
* Handle peer connect event from libp2p
|
|
18
|
+
* Emits low-level peer connected event for hierarchy manager to process
|
|
20
19
|
*/
|
|
21
20
|
private handlePeerConnect;
|
|
22
21
|
/**
|
|
23
22
|
* Handle peer disconnect event from libp2p
|
|
23
|
+
* Emits low-level peer disconnected event for hierarchy manager to process
|
|
24
24
|
*/
|
|
25
25
|
private handlePeerDisconnect;
|
|
26
26
|
/**
|
|
27
27
|
* Handle peer discovery event from libp2p
|
|
28
|
+
* Emits low-level peer discovered event for hierarchy manager to process
|
|
28
29
|
*/
|
|
29
30
|
private handlePeerDiscovery;
|
|
30
31
|
/**
|
|
@@ -33,20 +34,8 @@ export declare class oNodeNotificationManager extends oNotificationManager {
|
|
|
33
34
|
private handleConnectionOpen;
|
|
34
35
|
/**
|
|
35
36
|
* Handle connection close event from libp2p
|
|
37
|
+
* Emits low-level peer disconnected event for hierarchy manager to process
|
|
36
38
|
*/
|
|
37
39
|
private handleConnectionClose;
|
|
38
|
-
/**
|
|
39
|
-
* Try to resolve a libp2p peer ID to an Olane address
|
|
40
|
-
* Checks hierarchy manager for known peers
|
|
41
|
-
*/
|
|
42
|
-
private peerIdToAddress;
|
|
43
|
-
/**
|
|
44
|
-
* Check if an address is a direct child
|
|
45
|
-
*/
|
|
46
|
-
private isChild;
|
|
47
|
-
/**
|
|
48
|
-
* Check if an address is a parent
|
|
49
|
-
*/
|
|
50
|
-
private isParent;
|
|
51
40
|
}
|
|
52
41
|
//# sourceMappingURL=o-node.notification-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;IAE9D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBADP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY;IAK/B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAgChC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAoC9B"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { oNotificationManager,
|
|
1
|
+
import { oNotificationManager, PeerConnectedEvent, PeerDisconnectedEvent, PeerDiscoveredEvent, } from '@olane/o-core';
|
|
2
2
|
/**
|
|
3
3
|
* libp2p-specific implementation of oNotificationManager
|
|
4
|
-
*
|
|
4
|
+
* Emits low-level peer connection events without hierarchy awareness
|
|
5
5
|
*/
|
|
6
6
|
export class oNodeNotificationManager extends oNotificationManager {
|
|
7
|
-
constructor(p2pNode,
|
|
7
|
+
constructor(p2pNode, address) {
|
|
8
8
|
super();
|
|
9
9
|
this.p2pNode = p2pNode;
|
|
10
|
-
this.hierarchyManager = hierarchyManager;
|
|
11
10
|
this.address = address;
|
|
12
11
|
}
|
|
13
12
|
/**
|
|
@@ -30,101 +29,44 @@ export class oNodeNotificationManager extends oNotificationManager {
|
|
|
30
29
|
}
|
|
31
30
|
/**
|
|
32
31
|
* Handle peer connect event from libp2p
|
|
32
|
+
* Emits low-level peer connected event for hierarchy manager to process
|
|
33
33
|
*/
|
|
34
34
|
handlePeerConnect(evt) {
|
|
35
35
|
const peerId = evt.detail;
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
const nodeAddress = this.peerIdToAddress(peerId.toString());
|
|
39
|
-
if (!nodeAddress) {
|
|
40
|
-
// this.logger.debug(
|
|
41
|
-
// `Could not resolve peer ID ${peerId.toString()} to address`,
|
|
42
|
-
// );
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
// Emit generic node connected event
|
|
46
|
-
this.emit(new NodeConnectedEvent({
|
|
36
|
+
// Emit low-level peer connected event
|
|
37
|
+
this.emit(new PeerConnectedEvent({
|
|
47
38
|
source: this.address,
|
|
48
|
-
|
|
39
|
+
peerId: peerId.toString(),
|
|
49
40
|
connectionMetadata: {
|
|
50
|
-
peerId: peerId.toString(),
|
|
51
41
|
transport: 'libp2p',
|
|
52
42
|
},
|
|
53
43
|
}));
|
|
54
|
-
// Check if this is a child node
|
|
55
|
-
if (this.isChild(nodeAddress)) {
|
|
56
|
-
// this.logger.debug(`Child node connected: ${nodeAddress.toString()}`);
|
|
57
|
-
this.emit(new ChildJoinedEvent({
|
|
58
|
-
source: this.address,
|
|
59
|
-
childAddress: nodeAddress,
|
|
60
|
-
parentAddress: this.address,
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
// Check if this is a parent node
|
|
64
|
-
if (this.isParent(nodeAddress)) {
|
|
65
|
-
// this.logger.debug(`Parent node connected: ${nodeAddress.toString()}`);
|
|
66
|
-
this.emit(new ParentConnectedEvent({
|
|
67
|
-
source: this.address,
|
|
68
|
-
parentAddress: nodeAddress,
|
|
69
|
-
}));
|
|
70
|
-
}
|
|
71
44
|
}
|
|
72
45
|
/**
|
|
73
46
|
* Handle peer disconnect event from libp2p
|
|
47
|
+
* Emits low-level peer disconnected event for hierarchy manager to process
|
|
74
48
|
*/
|
|
75
49
|
handlePeerDisconnect(evt) {
|
|
76
50
|
const peerId = evt.detail;
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
const nodeAddress = this.peerIdToAddress(peerId.toString());
|
|
80
|
-
if (!nodeAddress) {
|
|
81
|
-
// this.logger.debug(
|
|
82
|
-
// `Could not resolve peer ID ${peerId.toString()} to address`,
|
|
83
|
-
// );
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
// Emit generic node disconnected event
|
|
87
|
-
this.emit(new NodeDisconnectedEvent({
|
|
51
|
+
// Emit low-level peer disconnected event
|
|
52
|
+
this.emit(new PeerDisconnectedEvent({
|
|
88
53
|
source: this.address,
|
|
89
|
-
|
|
54
|
+
peerId: peerId.toString(),
|
|
90
55
|
reason: 'peer_disconnected',
|
|
91
56
|
}));
|
|
92
|
-
// Check if this is a child node
|
|
93
|
-
if (this.isChild(nodeAddress)) {
|
|
94
|
-
this.logger.debug(`Child node disconnected: ${nodeAddress.toString()}`);
|
|
95
|
-
this.emit(new ChildLeftEvent({
|
|
96
|
-
source: this.address,
|
|
97
|
-
childAddress: nodeAddress,
|
|
98
|
-
parentAddress: this.address,
|
|
99
|
-
reason: 'peer_disconnected',
|
|
100
|
-
}));
|
|
101
|
-
// Optionally remove from hierarchy (auto-cleanup)
|
|
102
|
-
// this.hierarchyManager.removeChild(nodeAddress);
|
|
103
|
-
}
|
|
104
|
-
// Check if this is a parent node
|
|
105
|
-
if (this.isParent(nodeAddress)) {
|
|
106
|
-
this.logger.debug(`Parent node disconnected: ${nodeAddress.toString()}`);
|
|
107
|
-
this.emit(new ParentDisconnectedEvent({
|
|
108
|
-
source: this.address,
|
|
109
|
-
parentAddress: nodeAddress,
|
|
110
|
-
reason: 'peer_disconnected',
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
113
57
|
}
|
|
114
58
|
/**
|
|
115
59
|
* Handle peer discovery event from libp2p
|
|
60
|
+
* Emits low-level peer discovered event for hierarchy manager to process
|
|
116
61
|
*/
|
|
117
62
|
handlePeerDiscovery(evt) {
|
|
118
63
|
const peerInfo = evt.detail;
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (!nodeAddress) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
this.emit(new NodeDiscoveredEvent({
|
|
64
|
+
// Extract multiaddrs if available
|
|
65
|
+
const multiaddrs = peerInfo.multiaddrs?.map((ma) => ma.toString());
|
|
66
|
+
this.emit(new PeerDiscoveredEvent({
|
|
126
67
|
source: this.address,
|
|
127
|
-
|
|
68
|
+
peerId: peerInfo.id.toString(),
|
|
69
|
+
multiaddrs,
|
|
128
70
|
}));
|
|
129
71
|
}
|
|
130
72
|
/**
|
|
@@ -135,54 +77,33 @@ export class oNodeNotificationManager extends oNotificationManager {
|
|
|
135
77
|
}
|
|
136
78
|
/**
|
|
137
79
|
* Handle connection close event from libp2p
|
|
80
|
+
* Emits low-level peer disconnected event for hierarchy manager to process
|
|
138
81
|
*/
|
|
139
82
|
handleConnectionClose(evt) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* Try to resolve a libp2p peer ID to an Olane address
|
|
144
|
-
* Checks hierarchy manager for known peers
|
|
145
|
-
*/
|
|
146
|
-
peerIdToAddress(peerId) {
|
|
147
|
-
// Check children
|
|
148
|
-
for (const child of this.hierarchyManager.children) {
|
|
149
|
-
const childTransports = child.transports;
|
|
150
|
-
for (const transport of childTransports) {
|
|
151
|
-
if (transport.toString().includes(peerId)) {
|
|
152
|
-
return child;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
83
|
+
const connection = evt.detail;
|
|
84
|
+
if (!connection) {
|
|
85
|
+
return;
|
|
155
86
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
for (const transport of parentTransports) {
|
|
160
|
-
if (transport.toString().includes(peerId)) {
|
|
161
|
-
return parent;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
87
|
+
const remotePeerId = connection.remotePeer?.toString();
|
|
88
|
+
if (!remotePeerId) {
|
|
89
|
+
return;
|
|
164
90
|
}
|
|
165
|
-
// Check
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
91
|
+
// Check if there are any remaining open connections to this peer
|
|
92
|
+
const remainingConnections = this.p2pNode
|
|
93
|
+
.getConnections(remotePeerId)
|
|
94
|
+
.filter((conn) => conn.status === 'open');
|
|
95
|
+
// Only emit disconnect events if this was the last connection
|
|
96
|
+
if (remainingConnections.length > 0) {
|
|
97
|
+
this.logger.debug(`Connection closed to ${remotePeerId}, but ${remainingConnections.length} connection(s) remain open`);
|
|
98
|
+
return;
|
|
173
99
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Check if an address is a parent
|
|
184
|
-
*/
|
|
185
|
-
isParent(address) {
|
|
186
|
-
return this.hierarchyManager.parents.some((parent) => parent.toString() === address.toString());
|
|
100
|
+
// All connections to this peer are now closed
|
|
101
|
+
this.logger.debug(`Last connection closed to ${remotePeerId}`);
|
|
102
|
+
// Emit low-level peer disconnected event
|
|
103
|
+
this.emit(new PeerDisconnectedEvent({
|
|
104
|
+
source: this.address,
|
|
105
|
+
peerId: remotePeerId,
|
|
106
|
+
reason: 'connection_closed',
|
|
107
|
+
}));
|
|
187
108
|
}
|
|
188
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAoB,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;;AAKrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAehC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnE,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAiC5D"}
|
package/dist/src/o-node.tool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChildJoinedEvent
|
|
1
|
+
import { ChildJoinedEvent } from '@olane/o-core';
|
|
2
2
|
import { oTool } from '@olane/o-tool';
|
|
3
3
|
import { oServerNode } from './nodes/server.node.js';
|
|
4
4
|
import { oNodeTransport } from './router/o-node.transport.js';
|
|
@@ -69,6 +69,11 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
69
69
|
parentAddress: this.address,
|
|
70
70
|
}));
|
|
71
71
|
}
|
|
72
|
+
// create downward direction connection
|
|
73
|
+
await this.useChild(childAddress, {
|
|
74
|
+
method: 'ping',
|
|
75
|
+
params: {},
|
|
76
|
+
});
|
|
72
77
|
return {
|
|
73
78
|
message: `Child node registered with parent! ${childAddress.toString()}`,
|
|
74
79
|
parentTransports: this.parentTransports.map((t) => t.toString()),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@eslint/eslintrc": "^3.3.1",
|
|
42
42
|
"@eslint/js": "^9.29.0",
|
|
43
|
-
"@olane/o-test": "0.7.
|
|
43
|
+
"@olane/o-test": "0.7.31",
|
|
44
44
|
"@tsconfig/node20": "^20.1.6",
|
|
45
45
|
"@types/jest": "^30.0.0",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"typescript": "5.4.5"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@olane/o-config": "0.7.
|
|
63
|
-
"@olane/o-core": "0.7.
|
|
64
|
-
"@olane/o-protocol": "0.7.
|
|
65
|
-
"@olane/o-tool": "0.7.
|
|
62
|
+
"@olane/o-config": "0.7.31",
|
|
63
|
+
"@olane/o-core": "0.7.31",
|
|
64
|
+
"@olane/o-protocol": "0.7.31",
|
|
65
|
+
"@olane/o-tool": "0.7.31",
|
|
66
66
|
"debug": "^4.4.1",
|
|
67
67
|
"dotenv": "^16.5.0"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "a17496faa38e2c7680ea774f76d96bce07246f78"
|
|
70
70
|
}
|