@olane/o-node 0.7.6 → 0.7.7
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.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +2 -0
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +1 -0
- package/dist/src/router/o-node.router.d.ts +34 -1
- package/dist/src/router/o-node.router.d.ts.map +1 -1
- package/dist/src/router/o-node.router.js +74 -59
- package/dist/src/router/o-node.routing-policy.d.ts +30 -0
- package/dist/src/router/o-node.routing-policy.d.ts.map +1 -0
- package/dist/src/router/o-node.routing-policy.js +52 -0
- package/dist/src/router/resolvers/o-node.search-resolver.d.ts +163 -1
- package/dist/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -1
- package/dist/src/router/resolvers/o-node.search-resolver.js +223 -30
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,MAAM,EAEP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,qBAAa,eAAgB,SAAQ,WAAW;IAGlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAFrD,aAAa,EAAE,UAAU,CAAC;gBAEF,MAAM,EAAE,qBAAqB;IAKtD,IAAI,CAAC,MAAM,EAAE,MAAM;IAWzB,QAAQ;IAOF,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,MAAM,EAEP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,qBAAa,eAAgB,SAAQ,WAAW;IAGlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAFrD,aAAa,EAAE,UAAU,CAAC;gBAEF,MAAM,EAAE,qBAAqB;IAKtD,IAAI,CAAC,MAAM,EAAE,MAAM;IAWzB,QAAQ;IAOF,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAyC/C,KAAK;CAKZ"}
|
|
@@ -25,6 +25,7 @@ export class oNodeConnection extends oConnection {
|
|
|
25
25
|
try {
|
|
26
26
|
const stream = await this.p2pConnection.newStream(this.nextHopAddress.protocol, {
|
|
27
27
|
maxOutboundStreams: Infinity,
|
|
28
|
+
runOnLimitedConnection: true, // TODO: should this be configurable?
|
|
28
29
|
});
|
|
29
30
|
if (!stream || (stream.status !== 'open' && stream.status !== 'reset')) {
|
|
30
31
|
throw new oError(oErrorCodes.FAILED_TO_DIAL_TARGET, 'Failed to dial target');
|
|
@@ -35,6 +36,7 @@ export class oNodeConnection extends oConnection {
|
|
|
35
36
|
// Send the data
|
|
36
37
|
await stream.send(new TextEncoder().encode(request.toString()));
|
|
37
38
|
const res = await this.read(stream);
|
|
39
|
+
await stream.close();
|
|
38
40
|
// process the response
|
|
39
41
|
const response = new oResponse({
|
|
40
42
|
...res.result,
|
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,EAKL,QAAQ,EAET,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,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;IAChD,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,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;IAuB3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
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,EAKL,QAAQ,EAET,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,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;IAChD,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,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;IAuB3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC/B,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM;IAItC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,mBAAmB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAG1D;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;cA0FxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAMvC,OAAO,CACX,cAAc,EAAE,YAAY,EAC5B,aAAa,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC;IA0BrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC"}
|
package/dist/src/o-node.js
CHANGED
|
@@ -80,6 +80,7 @@ export class oNode extends oToolBase {
|
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
// if no parent transports, register with the parent to get them
|
|
83
|
+
// TODO: should we remove the transports check to make this more consistent?
|
|
83
84
|
if (this.config.parent && this.config.parent.transports.length === 0) {
|
|
84
85
|
this.logger.debug('Registering node with parent...', this.config.parent);
|
|
85
86
|
const parentRegistration = await this.use(this.config.parent, {
|
|
@@ -3,10 +3,43 @@ import { oRouterRequest, RouteResponse } from '@olane/o-core';
|
|
|
3
3
|
import type { oNode } from '../o-node.js';
|
|
4
4
|
import { oToolRouter } from '@olane/o-tool';
|
|
5
5
|
export declare class oNodeRouter extends oToolRouter {
|
|
6
|
+
private routingPolicy;
|
|
6
7
|
constructor();
|
|
8
|
+
/**
|
|
9
|
+
* Forwards a request to the specified address via libp2p transport.
|
|
10
|
+
* Handles self-routing (local execution) and destination detection.
|
|
11
|
+
*
|
|
12
|
+
* @param address The next hop address to forward to
|
|
13
|
+
* @param request The router request to forward
|
|
14
|
+
* @param node The current node context
|
|
15
|
+
* @returns The response from the forwarded request
|
|
16
|
+
*/
|
|
7
17
|
protected forward(address: oNodeAddress, request: oRouterRequest, node: oNode): Promise<any>;
|
|
8
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Executes a request locally when routing to self.
|
|
20
|
+
*/
|
|
21
|
+
private executeSelfRouting;
|
|
22
|
+
/**
|
|
23
|
+
* Checks if the next hop is the final destination address.
|
|
24
|
+
*/
|
|
25
|
+
private isDestinationAddress;
|
|
26
|
+
/**
|
|
27
|
+
* Unwraps the routing envelope when we've reached the destination.
|
|
28
|
+
*/
|
|
29
|
+
private unwrapDestinationRequest;
|
|
30
|
+
/**
|
|
31
|
+
* Dials a remote node and transmits the request via libp2p.
|
|
32
|
+
*/
|
|
33
|
+
private dialAndTransmit;
|
|
34
|
+
/**
|
|
35
|
+
* Translates an address to determine the next hop and target addresses.
|
|
36
|
+
* First checks routing policy for external routing, then applies resolver chain.
|
|
37
|
+
*/
|
|
9
38
|
translate(address: oNodeAddress, node: oNode): Promise<RouteResponse>;
|
|
39
|
+
/**
|
|
40
|
+
* Determines if an address is internal to this node's hierarchy.
|
|
41
|
+
* Delegates to the routing policy for the decision.
|
|
42
|
+
*/
|
|
10
43
|
isInternal(addressWithTransports: oNodeAddress, node: oNode): boolean;
|
|
11
44
|
}
|
|
12
45
|
//# sourceMappingURL=o-node.router.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.router.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAML,cAAc,EACd,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node.router.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAML,cAAc,EACd,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAK5C,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,aAAa,CAAqB;;IAO1C;;;;;;;;OAQG;cACa,OAAO,CACrB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,KAAK,GACV,OAAO,CAAC,GAAG,CAAC;IA0Bf;;OAEG;YACW,kBAAkB;IAgBhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAUhC;;OAEG;YACW,eAAe;IA2B7B;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IAyB3E;;;OAGG;IACH,UAAU,CAAC,qBAAqB,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;CAGtE"}
|
|
@@ -1,62 +1,89 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CoreUtils, oAddress, oError, oErrorCodes, oRequest, } from '@olane/o-core';
|
|
1
|
+
import { oAddress, oError, oErrorCodes, oRequest, } from '@olane/o-core';
|
|
3
2
|
import { oToolRouter } from '@olane/o-tool';
|
|
4
3
|
import { oNodeConnection } from '../connection/o-node-connection.js';
|
|
4
|
+
import { oNodeRoutingPolicy } from './o-node.routing-policy.js';
|
|
5
5
|
export class oNodeRouter extends oToolRouter {
|
|
6
6
|
constructor() {
|
|
7
7
|
super();
|
|
8
|
+
this.routingPolicy = new oNodeRoutingPolicy();
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Forwards a request to the specified address via libp2p transport.
|
|
12
|
+
* Handles self-routing (local execution) and destination detection.
|
|
13
|
+
*
|
|
14
|
+
* @param address The next hop address to forward to
|
|
15
|
+
* @param request The router request to forward
|
|
16
|
+
* @param node The current node context
|
|
17
|
+
* @returns The response from the forwarded request
|
|
18
|
+
*/
|
|
9
19
|
async forward(address, request, node) {
|
|
10
20
|
if (!request.stream) {
|
|
11
21
|
throw new oError(oErrorCodes.INVALID_REQUEST, 'Stream is required');
|
|
12
22
|
}
|
|
13
|
-
const stream = request.stream;
|
|
14
23
|
let nextHopRequest = new oRequest({
|
|
15
24
|
method: request.method,
|
|
16
25
|
params: request.params,
|
|
17
26
|
id: request.id,
|
|
18
27
|
});
|
|
19
|
-
//
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
const params = payload.params;
|
|
23
|
-
nextHopRequest = new oRequest({
|
|
24
|
-
method: payload.method,
|
|
25
|
-
params: {
|
|
26
|
-
...params,
|
|
27
|
-
},
|
|
28
|
-
id: request.id,
|
|
29
|
-
});
|
|
30
|
-
const result = await node.execute(nextHopRequest);
|
|
31
|
-
const response = CoreUtils.buildResponse(nextHopRequest, result, result?.error);
|
|
32
|
-
// add the request method to the response
|
|
33
|
-
return response;
|
|
28
|
+
// Handle self-routing: execute locally instead of dialing
|
|
29
|
+
if (this.routingPolicy.isSelfAddress(address, node)) {
|
|
30
|
+
return this.executeSelfRouting(request, node);
|
|
34
31
|
}
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
// reached destination, so change from route to actual request
|
|
40
|
-
const { payload } = request.params;
|
|
41
|
-
const params = payload.params;
|
|
42
|
-
nextHopRequest = new oRequest({
|
|
43
|
-
method: payload.method,
|
|
44
|
-
params: {
|
|
45
|
-
...params,
|
|
46
|
-
},
|
|
47
|
-
id: request.id,
|
|
48
|
-
});
|
|
32
|
+
// Check if we've reached the final destination
|
|
33
|
+
const isDestination = this.isDestinationAddress(address, request);
|
|
34
|
+
if (isDestination) {
|
|
35
|
+
nextHopRequest = this.unwrapDestinationRequest(request);
|
|
49
36
|
}
|
|
50
|
-
//
|
|
37
|
+
// Dial and transmit to remote node
|
|
38
|
+
return this.dialAndTransmit(address, nextHopRequest, node);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Executes a request locally when routing to self.
|
|
42
|
+
*/
|
|
43
|
+
async executeSelfRouting(request, node) {
|
|
44
|
+
const { payload } = request.params;
|
|
45
|
+
const params = payload.params;
|
|
46
|
+
const localRequest = new oRequest({
|
|
47
|
+
method: payload.method,
|
|
48
|
+
params: { ...params },
|
|
49
|
+
id: request.id,
|
|
50
|
+
});
|
|
51
|
+
const result = await node.execute(localRequest);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Checks if the next hop is the final destination address.
|
|
56
|
+
*/
|
|
57
|
+
isDestinationAddress(address, request) {
|
|
58
|
+
return address
|
|
59
|
+
?.toStaticAddress()
|
|
60
|
+
.equals(new oAddress(request?.params?.address).toStaticAddress());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Unwraps the routing envelope when we've reached the destination.
|
|
64
|
+
*/
|
|
65
|
+
unwrapDestinationRequest(request) {
|
|
66
|
+
const { payload } = request.params;
|
|
67
|
+
const params = payload.params;
|
|
68
|
+
return new oRequest({
|
|
69
|
+
method: payload.method,
|
|
70
|
+
params: { ...params },
|
|
71
|
+
id: request.id,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Dials a remote node and transmits the request via libp2p.
|
|
76
|
+
*/
|
|
77
|
+
async dialAndTransmit(address, request, node) {
|
|
51
78
|
try {
|
|
52
|
-
const connection = await node
|
|
79
|
+
const connection = await node.p2pNode.dial(address.libp2pTransports.map((t) => t.toMultiaddr()));
|
|
53
80
|
const nodeConnection = new oNodeConnection({
|
|
54
81
|
p2pConnection: connection,
|
|
55
82
|
nextHopAddress: address,
|
|
56
83
|
address: node.address,
|
|
57
84
|
callerAddress: node.address,
|
|
58
85
|
});
|
|
59
|
-
const response = await nodeConnection.transmit(
|
|
86
|
+
const response = await nodeConnection.transmit(request);
|
|
60
87
|
return response.result.data;
|
|
61
88
|
}
|
|
62
89
|
catch (error) {
|
|
@@ -66,26 +93,17 @@ export class oNodeRouter extends oToolRouter {
|
|
|
66
93
|
throw error;
|
|
67
94
|
}
|
|
68
95
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// external address, so we need to route
|
|
74
|
-
this.logger.debug('Address is external, routing...', address);
|
|
75
|
-
// route to leader of external OS
|
|
76
|
-
return {
|
|
77
|
-
nextHopAddress: new oNodeAddress(oAddress.leader().toString(), address.libp2pTransports),
|
|
78
|
-
targetAddress: address,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
96
|
+
/**
|
|
97
|
+
* Translates an address to determine the next hop and target addresses.
|
|
98
|
+
* First checks routing policy for external routing, then applies resolver chain.
|
|
99
|
+
*/
|
|
83
100
|
async translate(address, node) {
|
|
84
|
-
|
|
101
|
+
// Check if external routing is needed
|
|
102
|
+
const externalRoute = this.routingPolicy.getExternalRoutingStrategy(address, node);
|
|
85
103
|
if (externalRoute) {
|
|
86
|
-
this.logger.debug('External route found', externalRoute);
|
|
87
104
|
return externalRoute;
|
|
88
105
|
}
|
|
106
|
+
// Apply resolver chain for internal routing
|
|
89
107
|
const { nextHopAddress, targetAddress, requestOverride } = await this.addressResolution.resolve({
|
|
90
108
|
address,
|
|
91
109
|
node,
|
|
@@ -97,14 +115,11 @@ export class oNodeRouter extends oToolRouter {
|
|
|
97
115
|
requestOverride,
|
|
98
116
|
};
|
|
99
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Determines if an address is internal to this node's hierarchy.
|
|
120
|
+
* Delegates to the routing policy for the decision.
|
|
121
|
+
*/
|
|
100
122
|
isInternal(addressWithTransports, node) {
|
|
101
|
-
|
|
102
|
-
addressWithTransports.libp2pTransports?.length > 0) {
|
|
103
|
-
// transports are provided, let's see if they match our known leaders
|
|
104
|
-
const isLeaderRef = addressWithTransports.toString() === oAddress.leader().toString();
|
|
105
|
-
const isOurLeaderRef = node.hierarchyManager.leaders.some((l) => l.equals(addressWithTransports));
|
|
106
|
-
return isLeaderRef || isOurLeaderRef;
|
|
107
|
-
}
|
|
108
|
-
return true;
|
|
123
|
+
return this.routingPolicy.isInternalAddress(addressWithTransports, node);
|
|
109
124
|
}
|
|
110
125
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { oAddress, oRoutingPolicy, RouteResponse } from '@olane/o-core';
|
|
2
|
+
import type { oNode } from '../o-node.js';
|
|
3
|
+
/**
|
|
4
|
+
* Routing policy implementation for oNode that handles internal/external routing decisions
|
|
5
|
+
* and leader-based routing strategies.
|
|
6
|
+
*/
|
|
7
|
+
export declare class oNodeRoutingPolicy extends oRoutingPolicy {
|
|
8
|
+
/**
|
|
9
|
+
* Determines if an address is internal to the current node's hierarchy.
|
|
10
|
+
* An address is considered internal if:
|
|
11
|
+
* 1. It doesn't have leader references, OR
|
|
12
|
+
* 2. Its leader references match our known leaders
|
|
13
|
+
*
|
|
14
|
+
* @param address The address to check
|
|
15
|
+
* @param node The current node context
|
|
16
|
+
* @returns True if the address is internal to this hierarchy
|
|
17
|
+
*/
|
|
18
|
+
isInternalAddress(address: oAddress, node: oNode): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Determines the routing strategy for external addresses.
|
|
21
|
+
* External addresses are routed to the leader of the external OS using
|
|
22
|
+
* the address's libp2p transports.
|
|
23
|
+
*
|
|
24
|
+
* @param address The address to evaluate
|
|
25
|
+
* @param node The current node context
|
|
26
|
+
* @returns RouteResponse if external routing is needed, null if internal
|
|
27
|
+
*/
|
|
28
|
+
getExternalRoutingStrategy(address: oAddress, node: oNode): RouteResponse | null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=o-node.routing-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"o-node.routing-policy.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.routing-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAG1C;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,cAAc;IACpD;;;;;;;;;OASG;IACH,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;IAkB1D;;;;;;;;OAQG;IACH,0BAA0B,CACxB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,GACV,aAAa,GAAG,IAAI;CAuBxB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { oAddress, oRoutingPolicy } from '@olane/o-core';
|
|
2
|
+
import { oNodeAddress } from './o-node.address.js';
|
|
3
|
+
/**
|
|
4
|
+
* Routing policy implementation for oNode that handles internal/external routing decisions
|
|
5
|
+
* and leader-based routing strategies.
|
|
6
|
+
*/
|
|
7
|
+
export class oNodeRoutingPolicy extends oRoutingPolicy {
|
|
8
|
+
/**
|
|
9
|
+
* Determines if an address is internal to the current node's hierarchy.
|
|
10
|
+
* An address is considered internal if:
|
|
11
|
+
* 1. It doesn't have leader references, OR
|
|
12
|
+
* 2. Its leader references match our known leaders
|
|
13
|
+
*
|
|
14
|
+
* @param address The address to check
|
|
15
|
+
* @param node The current node context
|
|
16
|
+
* @returns True if the address is internal to this hierarchy
|
|
17
|
+
*/
|
|
18
|
+
isInternalAddress(address, node) {
|
|
19
|
+
const nodeAddress = address;
|
|
20
|
+
if (nodeAddress.paths.indexOf(oAddress.leader().paths) !== -1 && // if the address has a leader
|
|
21
|
+
nodeAddress.libp2pTransports?.length > 0) {
|
|
22
|
+
// transports are provided, let's see if they match our known leaders
|
|
23
|
+
const isLeaderRef = nodeAddress.toString() === oAddress.leader().toString();
|
|
24
|
+
const isOurLeaderRef = node.hierarchyManager.leaders.some((l) => l.equals(nodeAddress));
|
|
25
|
+
return isLeaderRef || isOurLeaderRef;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Determines the routing strategy for external addresses.
|
|
31
|
+
* External addresses are routed to the leader of the external OS using
|
|
32
|
+
* the address's libp2p transports.
|
|
33
|
+
*
|
|
34
|
+
* @param address The address to evaluate
|
|
35
|
+
* @param node The current node context
|
|
36
|
+
* @returns RouteResponse if external routing is needed, null if internal
|
|
37
|
+
*/
|
|
38
|
+
getExternalRoutingStrategy(address, node) {
|
|
39
|
+
const nodeAddress = address;
|
|
40
|
+
const isInternal = this.isInternalAddress(address, node);
|
|
41
|
+
if (!isInternal) {
|
|
42
|
+
// external address, so we need to route
|
|
43
|
+
this.logger.debug('Address is external, routing...', nodeAddress.toString(), nodeAddress.libp2pTransports.map((t) => t.toString()));
|
|
44
|
+
// route to leader of external OS
|
|
45
|
+
return {
|
|
46
|
+
nextHopAddress: new oNodeAddress(oAddress.leader().toString(), nodeAddress.libp2pTransports),
|
|
47
|
+
targetAddress: nodeAddress,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,8 +1,170 @@
|
|
|
1
|
-
import { oAddress, oAddressResolver, oTransport, ResolveRequest, RouteResponse } from '@olane/o-core';
|
|
1
|
+
import { oAddress, oAddressResolver, oCore, oTransport, ResolveRequest, RouteResponse } from '@olane/o-core';
|
|
2
|
+
import { oNodeTransport } from '../o-node.transport.js';
|
|
3
|
+
/**
|
|
4
|
+
* Address resolver that searches a registry to find transports for addresses.
|
|
5
|
+
*
|
|
6
|
+
* This resolver queries a registry service to find the transport information
|
|
7
|
+
* for addresses that don't already have transports configured. It's designed
|
|
8
|
+
* to be extensible through subclassing via protected template methods.
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const resolver = new oSearchResolver(nodeAddress);
|
|
13
|
+
* router.addResolver(resolver);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Creating a custom search resolver
|
|
17
|
+
* ```typescript
|
|
18
|
+
* class CustomSearchResolver extends oSearchResolver {
|
|
19
|
+
* // Search a different registry
|
|
20
|
+
* protected getRegistryAddress(): oAddress {
|
|
21
|
+
* return new oAddress('o://my-custom-registry');
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* // Use round-robin selection instead of first result
|
|
25
|
+
* private currentIndex = 0;
|
|
26
|
+
* protected selectResult(results: any[]): any | null {
|
|
27
|
+
* if (results.length === 0) return null;
|
|
28
|
+
* const result = results[this.currentIndex % results.length];
|
|
29
|
+
* this.currentIndex++;
|
|
30
|
+
* return result;
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* // Add custom filtering logic
|
|
34
|
+
* protected filterSearchResults(results: any[], node: oCore): any[] {
|
|
35
|
+
* return super.filterSearchResults(results, node).filter(
|
|
36
|
+
* result => result.status === 'active'
|
|
37
|
+
* );
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Implement custom routing logic with transport setup
|
|
41
|
+
* protected determineNextHop(
|
|
42
|
+
* node: oCore,
|
|
43
|
+
* resolvedTargetAddress: oAddress,
|
|
44
|
+
* searchResult: any
|
|
45
|
+
* ): oAddress {
|
|
46
|
+
* // Always route directly to target, bypassing hierarchy
|
|
47
|
+
* const targetTransports = this.mapTransports(searchResult);
|
|
48
|
+
* resolvedTargetAddress.setTransports(targetTransports);
|
|
49
|
+
* return resolvedTargetAddress;
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* ## Extension Points
|
|
55
|
+
*
|
|
56
|
+
* The following protected methods can be overridden to customize behavior:
|
|
57
|
+
*
|
|
58
|
+
* - `getRegistryAddress()` - Change which registry to search
|
|
59
|
+
* - `getSearchMethod()` - Change the registry method to call
|
|
60
|
+
* - `buildSearchParams()` - Customize search parameters
|
|
61
|
+
* - `filterSearchResults()` - Add custom filtering logic
|
|
62
|
+
* - `selectResult()` - Implement custom result selection (e.g., load balancing)
|
|
63
|
+
* - `mapTransports()` - Customize how transports are mapped from results
|
|
64
|
+
* - `determineNextHop()` - Implement custom routing logic to determine the next hop address
|
|
65
|
+
* - `resolveNextHopTransports()` - Customize transport resolution for the next hop
|
|
66
|
+
*/
|
|
2
67
|
export declare class oSearchResolver extends oAddressResolver {
|
|
3
68
|
protected readonly address: oAddress;
|
|
4
69
|
constructor(address: oAddress);
|
|
5
70
|
get customTransports(): oTransport[];
|
|
71
|
+
/**
|
|
72
|
+
* Returns the address of the registry to search.
|
|
73
|
+
* Override this method to search a different registry.
|
|
74
|
+
* @returns The registry address to query
|
|
75
|
+
*/
|
|
76
|
+
protected getRegistryAddress(): oAddress;
|
|
77
|
+
/**
|
|
78
|
+
* Returns the method name to call on the registry.
|
|
79
|
+
* Override this method to use a different search method.
|
|
80
|
+
* @returns The method name to call
|
|
81
|
+
*/
|
|
82
|
+
protected getSearchMethod(): string;
|
|
83
|
+
/**
|
|
84
|
+
* Builds the search parameters for the registry query.
|
|
85
|
+
* Override this method to customize search parameters.
|
|
86
|
+
* @param address - The address being resolved
|
|
87
|
+
* @returns Parameters to pass to the registry search method
|
|
88
|
+
*/
|
|
89
|
+
protected buildSearchParams(address: oAddress): any;
|
|
90
|
+
/**
|
|
91
|
+
* Filters the search results from the registry.
|
|
92
|
+
* Override this method to apply custom filtering logic.
|
|
93
|
+
* @param results - Raw results from the registry
|
|
94
|
+
* @param node - The current node context
|
|
95
|
+
* @returns Filtered array of results
|
|
96
|
+
*/
|
|
97
|
+
protected filterSearchResults(results: any[], node: oCore): any[];
|
|
98
|
+
/**
|
|
99
|
+
* Selects which result to use from the filtered results.
|
|
100
|
+
* Override this method to implement custom selection logic (e.g., load balancing).
|
|
101
|
+
* @param results - Filtered search results
|
|
102
|
+
* @returns The selected result, or null if no suitable result
|
|
103
|
+
*/
|
|
104
|
+
protected selectResult(results: any[]): any | null;
|
|
105
|
+
/**
|
|
106
|
+
* Maps the transport data from the search result to oNodeTransport instances.
|
|
107
|
+
* Override this method to customize transport mapping.
|
|
108
|
+
* @param result - The selected search result
|
|
109
|
+
* @returns Array of oNodeTransport instances
|
|
110
|
+
*/
|
|
111
|
+
protected mapTransports(result: any): oNodeTransport[];
|
|
112
|
+
/**
|
|
113
|
+
* Resolves the transports for the next hop address.
|
|
114
|
+
* This handles the logic of determining which transports to use based on
|
|
115
|
+
* whether the next hop is the leader, a known child, or a new target.
|
|
116
|
+
*
|
|
117
|
+
* Override this method to customize transport resolution logic.
|
|
118
|
+
*
|
|
119
|
+
* @param nextHop - The next hop address
|
|
120
|
+
* @param targetTransports - The transports from the registry search result
|
|
121
|
+
* @param node - The current node context
|
|
122
|
+
* @returns Array of transports to use for the next hop
|
|
123
|
+
*/
|
|
124
|
+
protected resolveNextHopTransports(nextHop: oAddress, targetTransports: oNodeTransport[], node: oCore): oNodeTransport[];
|
|
125
|
+
/**
|
|
126
|
+
* Determines the next hop address for routing to the target and sets up its transports.
|
|
127
|
+
*
|
|
128
|
+
* This method implements the complete routing logic including:
|
|
129
|
+
* 1. Determining the next address in the path (using `oAddress.next()`)
|
|
130
|
+
* 2. Mapping transports from the search result
|
|
131
|
+
* 3. Resolving and setting transports on the next hop address
|
|
132
|
+
* 4. Setting transports on the target address
|
|
133
|
+
*
|
|
134
|
+
* The default implementation:
|
|
135
|
+
* - Uses `oAddress.next()` for standard hierarchy-based routing
|
|
136
|
+
* - Maps transports from the registry search result
|
|
137
|
+
* - Resolves next hop transports based on leader/hierarchy
|
|
138
|
+
* - Configures both next hop and target with appropriate transports
|
|
139
|
+
*
|
|
140
|
+
* Override this method to implement custom routing logic, such as:
|
|
141
|
+
* - Direct peer-to-peer routing
|
|
142
|
+
* - Custom hierarchy traversal
|
|
143
|
+
* - Alternative transport selection strategies
|
|
144
|
+
* - Bypass leader for certain routes
|
|
145
|
+
*
|
|
146
|
+
* @param node - The current node context
|
|
147
|
+
* @param resolvedTargetAddress - The resolved target address to route to
|
|
148
|
+
* @param searchResult - The raw search result from the registry containing transport data
|
|
149
|
+
* @returns The next hop address with transports configured
|
|
150
|
+
*
|
|
151
|
+
* @example Custom direct routing
|
|
152
|
+
* ```typescript
|
|
153
|
+
* class DirectSearchResolver extends oSearchResolver {
|
|
154
|
+
* protected determineNextHop(
|
|
155
|
+
* node: oCore,
|
|
156
|
+
* resolvedTargetAddress: oAddress,
|
|
157
|
+
* searchResult: any
|
|
158
|
+
* ): oAddress {
|
|
159
|
+
* // Always route directly to the target, bypassing hierarchy
|
|
160
|
+
* const targetTransports = this.mapTransports(searchResult);
|
|
161
|
+
* resolvedTargetAddress.setTransports(targetTransports);
|
|
162
|
+
* return resolvedTargetAddress;
|
|
163
|
+
* }
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
protected determineNextHop(node: oCore, resolvedTargetAddress: oAddress, searchResult: any): oAddress;
|
|
6
168
|
resolve(request: ResolveRequest): Promise<RouteResponse>;
|
|
7
169
|
}
|
|
8
170
|
//# sourceMappingURL=o-node.search-resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.search-resolver.d.ts","sourceRoot":"","sources":["../../../../src/router/resolvers/o-node.search-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,gBAAgB,
|
|
1
|
+
{"version":3,"file":"o-node.search-resolver.d.ts","sourceRoot":"","sources":["../../../../src/router/resolvers/o-node.search-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,KAAK,EAEL,UAAU,EACV,cAAc,EAEd,aAAa,EAEd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,qBAAa,eAAgB,SAAQ,gBAAgB;IACvC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ;gBAAjB,OAAO,EAAE,QAAQ;IAIhD,IAAI,gBAAgB,IAAI,UAAU,EAAE,CAEnC;IAED;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,IAAI,QAAQ;IAIxC;;;;OAIG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC;;;;;OAKG;IACH,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,GAAG,GAAG;IAOnD;;;;;;OAMG;IACH,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,EAAE;IASjE;;;;;OAKG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI;IAIlD;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,GAAG,GAAG,cAAc,EAAE;IAOtD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,wBAAwB,CAChC,OAAO,EAAE,QAAQ,EACjB,gBAAgB,EAAE,cAAc,EAAE,EAClC,IAAI,EAAE,KAAK,GACV,cAAc,EAAE;IAgBnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACH,SAAS,CAAC,gBAAgB,CACxB,IAAI,EAAE,KAAK,EACX,qBAAqB,EAAE,QAAQ,EAC/B,YAAY,EAAE,GAAG,GAChB,QAAQ;IAeL,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA6D/D"}
|
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
import { oAddress, oAddressResolver, oCustomTransport, RestrictedAddresses, } from '@olane/o-core';
|
|
2
2
|
import { oNodeTransport } from '../o-node.transport.js';
|
|
3
|
+
/**
|
|
4
|
+
* Address resolver that searches a registry to find transports for addresses.
|
|
5
|
+
*
|
|
6
|
+
* This resolver queries a registry service to find the transport information
|
|
7
|
+
* for addresses that don't already have transports configured. It's designed
|
|
8
|
+
* to be extensible through subclassing via protected template methods.
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const resolver = new oSearchResolver(nodeAddress);
|
|
13
|
+
* router.addResolver(resolver);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Creating a custom search resolver
|
|
17
|
+
* ```typescript
|
|
18
|
+
* class CustomSearchResolver extends oSearchResolver {
|
|
19
|
+
* // Search a different registry
|
|
20
|
+
* protected getRegistryAddress(): oAddress {
|
|
21
|
+
* return new oAddress('o://my-custom-registry');
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* // Use round-robin selection instead of first result
|
|
25
|
+
* private currentIndex = 0;
|
|
26
|
+
* protected selectResult(results: any[]): any | null {
|
|
27
|
+
* if (results.length === 0) return null;
|
|
28
|
+
* const result = results[this.currentIndex % results.length];
|
|
29
|
+
* this.currentIndex++;
|
|
30
|
+
* return result;
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* // Add custom filtering logic
|
|
34
|
+
* protected filterSearchResults(results: any[], node: oCore): any[] {
|
|
35
|
+
* return super.filterSearchResults(results, node).filter(
|
|
36
|
+
* result => result.status === 'active'
|
|
37
|
+
* );
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Implement custom routing logic with transport setup
|
|
41
|
+
* protected determineNextHop(
|
|
42
|
+
* node: oCore,
|
|
43
|
+
* resolvedTargetAddress: oAddress,
|
|
44
|
+
* searchResult: any
|
|
45
|
+
* ): oAddress {
|
|
46
|
+
* // Always route directly to target, bypassing hierarchy
|
|
47
|
+
* const targetTransports = this.mapTransports(searchResult);
|
|
48
|
+
* resolvedTargetAddress.setTransports(targetTransports);
|
|
49
|
+
* return resolvedTargetAddress;
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* ## Extension Points
|
|
55
|
+
*
|
|
56
|
+
* The following protected methods can be overridden to customize behavior:
|
|
57
|
+
*
|
|
58
|
+
* - `getRegistryAddress()` - Change which registry to search
|
|
59
|
+
* - `getSearchMethod()` - Change the registry method to call
|
|
60
|
+
* - `buildSearchParams()` - Customize search parameters
|
|
61
|
+
* - `filterSearchResults()` - Add custom filtering logic
|
|
62
|
+
* - `selectResult()` - Implement custom result selection (e.g., load balancing)
|
|
63
|
+
* - `mapTransports()` - Customize how transports are mapped from results
|
|
64
|
+
* - `determineNextHop()` - Implement custom routing logic to determine the next hop address
|
|
65
|
+
* - `resolveNextHopTransports()` - Customize transport resolution for the next hop
|
|
66
|
+
*/
|
|
3
67
|
export class oSearchResolver extends oAddressResolver {
|
|
4
68
|
constructor(address) {
|
|
5
69
|
super(address);
|
|
@@ -8,8 +72,144 @@ export class oSearchResolver extends oAddressResolver {
|
|
|
8
72
|
get customTransports() {
|
|
9
73
|
return [new oCustomTransport('/search')];
|
|
10
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the address of the registry to search.
|
|
77
|
+
* Override this method to search a different registry.
|
|
78
|
+
* @returns The registry address to query
|
|
79
|
+
*/
|
|
80
|
+
getRegistryAddress() {
|
|
81
|
+
return new oAddress(RestrictedAddresses.REGISTRY);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns the method name to call on the registry.
|
|
85
|
+
* Override this method to use a different search method.
|
|
86
|
+
* @returns The method name to call
|
|
87
|
+
*/
|
|
88
|
+
getSearchMethod() {
|
|
89
|
+
return 'search';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Builds the search parameters for the registry query.
|
|
93
|
+
* Override this method to customize search parameters.
|
|
94
|
+
* @param address - The address being resolved
|
|
95
|
+
* @returns Parameters to pass to the registry search method
|
|
96
|
+
*/
|
|
97
|
+
buildSearchParams(address) {
|
|
98
|
+
return {
|
|
99
|
+
staticAddress: address.toRootAddress().toString(),
|
|
100
|
+
address: address.toString(),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Filters the search results from the registry.
|
|
105
|
+
* Override this method to apply custom filtering logic.
|
|
106
|
+
* @param results - Raw results from the registry
|
|
107
|
+
* @param node - The current node context
|
|
108
|
+
* @returns Filtered array of results
|
|
109
|
+
*/
|
|
110
|
+
filterSearchResults(results, node) {
|
|
111
|
+
return results.filter(
|
|
112
|
+
// filter out the items that may cause infinite looping
|
|
113
|
+
(result) => result.staticAddress !== RestrictedAddresses.REGISTRY &&
|
|
114
|
+
result.address !== node.address);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Selects which result to use from the filtered results.
|
|
118
|
+
* Override this method to implement custom selection logic (e.g., load balancing).
|
|
119
|
+
* @param results - Filtered search results
|
|
120
|
+
* @returns The selected result, or null if no suitable result
|
|
121
|
+
*/
|
|
122
|
+
selectResult(results) {
|
|
123
|
+
return results.length > 0 ? results[0] : null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Maps the transport data from the search result to oNodeTransport instances.
|
|
127
|
+
* Override this method to customize transport mapping.
|
|
128
|
+
* @param result - The selected search result
|
|
129
|
+
* @returns Array of oNodeTransport instances
|
|
130
|
+
*/
|
|
131
|
+
mapTransports(result) {
|
|
132
|
+
return result.transports.map((t) => new oNodeTransport(t.value));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Resolves the transports for the next hop address.
|
|
136
|
+
* This handles the logic of determining which transports to use based on
|
|
137
|
+
* whether the next hop is the leader, a known child, or a new target.
|
|
138
|
+
*
|
|
139
|
+
* Override this method to customize transport resolution logic.
|
|
140
|
+
*
|
|
141
|
+
* @param nextHop - The next hop address
|
|
142
|
+
* @param targetTransports - The transports from the registry search result
|
|
143
|
+
* @param node - The current node context
|
|
144
|
+
* @returns Array of transports to use for the next hop
|
|
145
|
+
*/
|
|
146
|
+
resolveNextHopTransports(nextHop, targetTransports, node) {
|
|
147
|
+
// If next hop is the leader, use leader transports
|
|
148
|
+
if (nextHop.value === RestrictedAddresses.LEADER) {
|
|
149
|
+
return (node.leader?.transports || []);
|
|
150
|
+
}
|
|
151
|
+
// Check if next hop is a known child in the hierarchy
|
|
152
|
+
const childAddress = node?.hierarchyManager.getChild(nextHop);
|
|
153
|
+
if (childAddress?.transports) {
|
|
154
|
+
return childAddress.transports;
|
|
155
|
+
}
|
|
156
|
+
// Fall back to target transports from registry
|
|
157
|
+
return targetTransports;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Determines the next hop address for routing to the target and sets up its transports.
|
|
161
|
+
*
|
|
162
|
+
* This method implements the complete routing logic including:
|
|
163
|
+
* 1. Determining the next address in the path (using `oAddress.next()`)
|
|
164
|
+
* 2. Mapping transports from the search result
|
|
165
|
+
* 3. Resolving and setting transports on the next hop address
|
|
166
|
+
* 4. Setting transports on the target address
|
|
167
|
+
*
|
|
168
|
+
* The default implementation:
|
|
169
|
+
* - Uses `oAddress.next()` for standard hierarchy-based routing
|
|
170
|
+
* - Maps transports from the registry search result
|
|
171
|
+
* - Resolves next hop transports based on leader/hierarchy
|
|
172
|
+
* - Configures both next hop and target with appropriate transports
|
|
173
|
+
*
|
|
174
|
+
* Override this method to implement custom routing logic, such as:
|
|
175
|
+
* - Direct peer-to-peer routing
|
|
176
|
+
* - Custom hierarchy traversal
|
|
177
|
+
* - Alternative transport selection strategies
|
|
178
|
+
* - Bypass leader for certain routes
|
|
179
|
+
*
|
|
180
|
+
* @param node - The current node context
|
|
181
|
+
* @param resolvedTargetAddress - The resolved target address to route to
|
|
182
|
+
* @param searchResult - The raw search result from the registry containing transport data
|
|
183
|
+
* @returns The next hop address with transports configured
|
|
184
|
+
*
|
|
185
|
+
* @example Custom direct routing
|
|
186
|
+
* ```typescript
|
|
187
|
+
* class DirectSearchResolver extends oSearchResolver {
|
|
188
|
+
* protected determineNextHop(
|
|
189
|
+
* node: oCore,
|
|
190
|
+
* resolvedTargetAddress: oAddress,
|
|
191
|
+
* searchResult: any
|
|
192
|
+
* ): oAddress {
|
|
193
|
+
* // Always route directly to the target, bypassing hierarchy
|
|
194
|
+
* const targetTransports = this.mapTransports(searchResult);
|
|
195
|
+
* resolvedTargetAddress.setTransports(targetTransports);
|
|
196
|
+
* return resolvedTargetAddress;
|
|
197
|
+
* }
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
determineNextHop(node, resolvedTargetAddress, searchResult) {
|
|
202
|
+
// Determine next hop using standard hierarchy logic
|
|
203
|
+
const nextHopAddress = oAddress.next(node.address, resolvedTargetAddress);
|
|
204
|
+
// Map transports from search result
|
|
205
|
+
const targetTransports = this.mapTransports(searchResult);
|
|
206
|
+
// Set transports on the next hop based on routing logic
|
|
207
|
+
nextHopAddress.setTransports(this.resolveNextHopTransports(nextHopAddress, targetTransports, node));
|
|
208
|
+
return nextHopAddress;
|
|
209
|
+
}
|
|
11
210
|
async resolve(request) {
|
|
12
211
|
const { address, node, request: resolveRequest, targetAddress } = request;
|
|
212
|
+
// Early return: if address already has transports, no search needed
|
|
13
213
|
if (address.transports.length > 0) {
|
|
14
214
|
return {
|
|
15
215
|
nextHopAddress: address,
|
|
@@ -17,43 +217,36 @@ export class oSearchResolver extends oAddressResolver {
|
|
|
17
217
|
requestOverride: resolveRequest,
|
|
18
218
|
};
|
|
19
219
|
}
|
|
20
|
-
//
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
address: address.toString(),
|
|
27
|
-
};
|
|
28
|
-
const registrySearchResults = await node.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
29
|
-
method: 'search',
|
|
30
|
-
params: params,
|
|
220
|
+
// Perform registry search
|
|
221
|
+
const searchParams = this.buildSearchParams(address);
|
|
222
|
+
const registryAddress = this.getRegistryAddress();
|
|
223
|
+
const searchResponse = await node.use(registryAddress, {
|
|
224
|
+
method: this.getSearchMethod(),
|
|
225
|
+
params: searchParams,
|
|
31
226
|
});
|
|
32
|
-
//
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (registrySearchResultsArray.length > 0) {
|
|
38
|
-
const registrySearchResult = registrySearchResultsArray[0];
|
|
39
|
-
// we know the final destination, so let's return it + the next hop
|
|
40
|
-
const targetAddress = new oAddress(registrySearchResult.address + extraParams);
|
|
41
|
-
const nextHopAddress = oAddress.next(node.address, targetAddress);
|
|
42
|
-
const targetTransports = registrySearchResult.transports.map((t) => new oNodeTransport(t.value));
|
|
43
|
-
const childAddress = node?.hierarchyManager.getChild(nextHopAddress);
|
|
44
|
-
nextHopAddress.setTransports(nextHopAddress.value === RestrictedAddresses.LEADER
|
|
45
|
-
? node.leader?.transports
|
|
46
|
-
: childAddress?.transports || targetTransports);
|
|
47
|
-
targetAddress.setTransports(targetTransports);
|
|
227
|
+
// Filter and select result
|
|
228
|
+
const filteredResults = this.filterSearchResults(searchResponse.result.data, node);
|
|
229
|
+
const selectedResult = this.selectResult(filteredResults);
|
|
230
|
+
// Early return: if no result found, return original address
|
|
231
|
+
if (!selectedResult) {
|
|
48
232
|
return {
|
|
49
|
-
nextHopAddress:
|
|
233
|
+
nextHopAddress: address,
|
|
50
234
|
targetAddress: targetAddress,
|
|
51
235
|
requestOverride: resolveRequest,
|
|
52
236
|
};
|
|
53
237
|
}
|
|
238
|
+
// Build route from search result
|
|
239
|
+
const extraParams = address
|
|
240
|
+
.toString()
|
|
241
|
+
.replace(address.toRootAddress().toString(), '');
|
|
242
|
+
const resolvedTargetAddress = new oAddress(selectedResult.address + extraParams);
|
|
243
|
+
// Set transports on the target address
|
|
244
|
+
resolvedTargetAddress.setTransports(this.mapTransports(selectedResult));
|
|
245
|
+
// Determine next hop and configure transports
|
|
246
|
+
const nextHopAddress = this.determineNextHop(node, resolvedTargetAddress, selectedResult);
|
|
54
247
|
return {
|
|
55
|
-
nextHopAddress:
|
|
56
|
-
targetAddress:
|
|
248
|
+
nextHopAddress: nextHopAddress,
|
|
249
|
+
targetAddress: resolvedTargetAddress,
|
|
57
250
|
requestOverride: resolveRequest,
|
|
58
251
|
};
|
|
59
252
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"typescript": "5.4.5"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@olane/o-config": "^0.7.
|
|
60
|
-
"@olane/o-core": "^0.7.
|
|
61
|
-
"@olane/o-protocol": "^0.7.
|
|
62
|
-
"@olane/o-tool": "^0.7.
|
|
59
|
+
"@olane/o-config": "^0.7.6",
|
|
60
|
+
"@olane/o-core": "^0.7.6",
|
|
61
|
+
"@olane/o-protocol": "^0.7.6",
|
|
62
|
+
"@olane/o-tool": "^0.7.6"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"debug": "^4.4.1",
|