@olane/o-node 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +1024 -0
  2. package/dist/src/connection/index.d.ts +5 -0
  3. package/dist/src/connection/index.d.ts.map +1 -0
  4. package/dist/src/connection/index.js +4 -0
  5. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +6 -0
  6. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -0
  7. package/dist/src/connection/interfaces/o-node-connection-manager.config.js +1 -0
  8. package/dist/src/connection/interfaces/o-node-connection.config.d.ts +6 -0
  9. package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -0
  10. package/dist/src/connection/interfaces/o-node-connection.config.js +1 -0
  11. package/dist/src/connection/o-node-connection.d.ts +13 -0
  12. package/dist/src/connection/o-node-connection.d.ts.map +1 -0
  13. package/dist/src/connection/o-node-connection.js +51 -0
  14. package/dist/src/connection/o-node-connection.manager.d.ts +17 -0
  15. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -0
  16. package/dist/src/connection/o-node-connection.manager.js +68 -0
  17. package/dist/src/index.d.ts +10 -0
  18. package/dist/src/index.d.ts.map +1 -0
  19. package/dist/src/index.js +9 -0
  20. package/dist/src/interfaces/o-node.config.d.ts +7 -0
  21. package/dist/src/interfaces/o-node.config.d.ts.map +1 -0
  22. package/dist/src/interfaces/o-node.config.js +1 -0
  23. package/dist/src/interfaces/o-node.tool-config.d.ts +4 -0
  24. package/dist/src/interfaces/o-node.tool-config.d.ts.map +1 -0
  25. package/dist/src/interfaces/o-node.tool-config.js +1 -0
  26. package/dist/src/lib/network-activity.lib.d.ts +1 -0
  27. package/dist/src/lib/network-activity.lib.d.ts.map +1 -0
  28. package/dist/src/lib/network-activity.lib.js +34 -0
  29. package/dist/src/nodes/client.node.d.ts +7 -0
  30. package/dist/src/nodes/client.node.d.ts.map +1 -0
  31. package/dist/src/nodes/client.node.js +16 -0
  32. package/dist/src/nodes/index.d.ts +4 -0
  33. package/dist/src/nodes/index.d.ts.map +1 -0
  34. package/dist/src/nodes/index.js +3 -0
  35. package/dist/src/nodes/server.node.d.ts +7 -0
  36. package/dist/src/nodes/server.node.d.ts.map +1 -0
  37. package/dist/src/nodes/server.node.js +20 -0
  38. package/dist/src/nodes/websocket.node.d.ts +7 -0
  39. package/dist/src/nodes/websocket.node.d.ts.map +1 -0
  40. package/dist/src/nodes/websocket.node.js +18 -0
  41. package/dist/src/o-node.d.ts +42 -0
  42. package/dist/src/o-node.d.ts.map +1 -0
  43. package/dist/src/o-node.hierarchy-manager.d.ts +15 -0
  44. package/dist/src/o-node.hierarchy-manager.d.ts.map +1 -0
  45. package/dist/src/o-node.hierarchy-manager.js +15 -0
  46. package/dist/src/o-node.js +242 -0
  47. package/dist/src/o-node.tool.d.ts +16 -0
  48. package/dist/src/o-node.tool.d.ts.map +1 -0
  49. package/dist/src/o-node.tool.js +48 -0
  50. package/dist/src/router/index.d.ts +6 -0
  51. package/dist/src/router/index.d.ts.map +1 -0
  52. package/dist/src/router/index.js +5 -0
  53. package/dist/src/router/interfaces/o-node-router.config.d.ts +3 -0
  54. package/dist/src/router/interfaces/o-node-router.config.d.ts.map +1 -0
  55. package/dist/src/router/interfaces/o-node-router.config.js +1 -0
  56. package/dist/src/router/interfaces/o-node-router.response.d.ts +8 -0
  57. package/dist/src/router/interfaces/o-node-router.response.d.ts.map +1 -0
  58. package/dist/src/router/interfaces/o-node-router.response.js +1 -0
  59. package/dist/src/router/o-node.address.d.ts +18 -0
  60. package/dist/src/router/o-node.address.d.ts.map +1 -0
  61. package/dist/src/router/o-node.address.js +29 -0
  62. package/dist/src/router/o-node.router.d.ts +12 -0
  63. package/dist/src/router/o-node.router.d.ts.map +1 -0
  64. package/dist/src/router/o-node.router.js +109 -0
  65. package/dist/src/router/o-node.transport.d.ts +11 -0
  66. package/dist/src/router/o-node.transport.d.ts.map +1 -0
  67. package/dist/src/router/o-node.transport.js +18 -0
  68. package/dist/src/router/resolvers/index.d.ts +4 -0
  69. package/dist/src/router/resolvers/index.d.ts.map +1 -0
  70. package/dist/src/router/resolvers/index.js +3 -0
  71. package/dist/src/router/resolvers/o-node.child-resolver.d.ts +11 -0
  72. package/dist/src/router/resolvers/o-node.child-resolver.d.ts.map +1 -0
  73. package/dist/src/router/resolvers/o-node.child-resolver.js +58 -0
  74. package/dist/src/router/resolvers/o-node.leader-resolver-fallback.d.ts +8 -0
  75. package/dist/src/router/resolvers/o-node.leader-resolver-fallback.d.ts.map +1 -0
  76. package/dist/src/router/resolvers/o-node.leader-resolver-fallback.js +35 -0
  77. package/dist/src/router/resolvers/o-node.resolver.d.ts +11 -0
  78. package/dist/src/router/resolvers/o-node.resolver.d.ts.map +1 -0
  79. package/dist/src/router/resolvers/o-node.resolver.js +41 -0
  80. package/dist/src/router/resolvers/o-node.search-resolver.d.ts +8 -0
  81. package/dist/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -0
  82. package/dist/src/router/resolvers/o-node.search-resolver.js +60 -0
  83. package/dist/src/router/route.request.d.ts +14 -0
  84. package/dist/src/router/route.request.d.ts.map +1 -0
  85. package/dist/src/router/route.request.js +1 -0
  86. package/dist/src/utils/network.utils.d.ts +20 -0
  87. package/dist/src/utils/network.utils.d.ts.map +1 -0
  88. package/dist/src/utils/network.utils.js +74 -0
  89. package/dist/test/o-node.spec.d.ts +2 -0
  90. package/dist/test/o-node.spec.d.ts.map +1 -0
  91. package/dist/test/o-node.spec.js +20 -0
  92. package/package.json +68 -0
@@ -0,0 +1,242 @@
1
+ import { bootstrap, createNode, defaultLibp2pConfig, } from '@olane/o-config';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { oNodeRouter } from './router/o-node.router.js';
4
+ import { oNodeHierarchyManager } from './o-node.hierarchy-manager.js';
5
+ import { oNodeTransport } from './router/o-node.transport.js';
6
+ import { CoreUtils, NodeState, NodeType, oAddress, RestrictedAddresses, } from '@olane/o-core';
7
+ import { oNodeAddress } from './router/o-node.address.js';
8
+ import { oNodeConnectionManager } from './connection/o-node-connection.manager.js';
9
+ import { oNodeResolver } from './router/resolvers/o-node.resolver.js';
10
+ import { NetworkUtils } from './utils/network.utils.js';
11
+ import { oMethodResolver, oToolBase } from '@olane/o-tool';
12
+ import { oLeaderResolverFallback } from './router/index.js';
13
+ export class oNode extends oToolBase {
14
+ constructor(config) {
15
+ super(config);
16
+ this.didRegister = false;
17
+ this.config = config;
18
+ }
19
+ get leader() {
20
+ return this.isLeader ? this.address : this.config?.leader || null;
21
+ }
22
+ get networkConfig() {
23
+ return this.config.network || defaultLibp2pConfig;
24
+ }
25
+ get parentPeerId() {
26
+ if (!this.parent || this.parent?.transports?.length === 0) {
27
+ return null;
28
+ }
29
+ const transport = this.parent?.transports[0];
30
+ const peerId = transport.toPeerId();
31
+ return peerId;
32
+ }
33
+ configureTransports() {
34
+ return [...(defaultLibp2pConfig.transports || [])];
35
+ }
36
+ async initializeRouter() {
37
+ this.hierarchyManager = new oNodeHierarchyManager({
38
+ leaders: this.config.leader ? [this.config.leader] : [],
39
+ parents: this.config.parent ? [this.config.parent] : [],
40
+ children: [],
41
+ });
42
+ this.router = new oNodeRouter();
43
+ }
44
+ get staticAddress() {
45
+ return this.config.address;
46
+ }
47
+ get parentTransports() {
48
+ return this.config.parent?.transports || [];
49
+ }
50
+ get transports() {
51
+ return this.p2pNode
52
+ .getMultiaddrs()
53
+ .map((multiaddr) => new oNodeTransport(multiaddr.toString()));
54
+ }
55
+ async unregister() {
56
+ if (this.type === NodeType.LEADER) {
57
+ this.logger.debug('Skipping unregistration, node is leader');
58
+ return;
59
+ }
60
+ if (!this.config.leader) {
61
+ this.logger.debug('No leader found, skipping unregistration');
62
+ return;
63
+ }
64
+ const address = new oNodeAddress(RestrictedAddresses.REGISTRY);
65
+ // attempt to unregister from the network
66
+ const params = {
67
+ method: 'remove',
68
+ params: {
69
+ peerId: this.peerId.toString(),
70
+ },
71
+ };
72
+ await this.use(address, params);
73
+ }
74
+ async register() {
75
+ if (this.type === NodeType.LEADER) {
76
+ this.logger.debug('Skipping registration, node is leader');
77
+ return;
78
+ }
79
+ if (this.didRegister) {
80
+ this.logger.debug('Node already registered, skipping registration');
81
+ return;
82
+ }
83
+ this.didRegister = true;
84
+ this.logger.debug('Registering node...');
85
+ // register with the leader global registry
86
+ if (!this.config.leader) {
87
+ this.logger.warn('No leaders found, skipping registration');
88
+ return;
89
+ }
90
+ else {
91
+ this.logger.debug('Registering node with leader...');
92
+ }
93
+ const address = oAddress.registry();
94
+ const params = {
95
+ method: 'commit',
96
+ params: {
97
+ peerId: this.peerId.toString(),
98
+ address: this.address.toString(),
99
+ protocols: this.p2pNode.getProtocols(),
100
+ transports: this.transports,
101
+ staticAddress: this.staticAddress.toString(),
102
+ },
103
+ };
104
+ await this.use(address, params);
105
+ this.logger.debug('Registration successful');
106
+ }
107
+ extractMethod(address) {
108
+ return address.protocol.split('/').pop() || '';
109
+ }
110
+ async start() {
111
+ await super.start();
112
+ await NetworkUtils.advertiseToNetwork(this.address, this.staticAddress, this.p2pNode);
113
+ }
114
+ async validateJoinRequest(request) {
115
+ return true;
116
+ }
117
+ /**
118
+ * Configure the libp2p node
119
+ * @returns The libp2p config
120
+ */
121
+ async configure() {
122
+ const params = {
123
+ ...this.networkConfig,
124
+ transports: this.configureTransports(),
125
+ connectionManager: {
126
+ ...(this.networkConfig.connectionManager || {}),
127
+ },
128
+ listeners: (this.config.network?.listeners ||
129
+ defaultLibp2pConfig.listeners ||
130
+ []).concat(`/memory/${uuidv4()}`), // ensure we allow for local in-memory communication
131
+ };
132
+ // if the seed is provided, use it to generate the private key
133
+ if (this.config.seed) {
134
+ this.logger.debug('Seed provided, generating private key...');
135
+ const privateKey = await CoreUtils.generatePrivateKey(this.config.seed);
136
+ params.privateKey = privateKey;
137
+ }
138
+ else {
139
+ this.logger.debug('No seed provided, generating private key...');
140
+ this.logger.debug('Without providing a seed, this node peer id will be destroyed after the node shuts down.');
141
+ // TODO: add a link to documentation about how to setup a seed
142
+ }
143
+ // this is a child node of the network, so communication is heavily restricted
144
+ if (this.parentTransports.length > 0) {
145
+ // peer discovery is only allowed through the parent transports
146
+ const transports = this.parentTransports.map((t) => t.toMultiaddr().toString()) || [];
147
+ this.logger.debug('Parent transports: ', transports);
148
+ params.peerDiscovery = [
149
+ bootstrap({
150
+ list: transports.concat(this.leader?.libp2pTransports.map((t) => t.toString()) || []),
151
+ }),
152
+ ...(defaultLibp2pConfig.peerDiscovery || []),
153
+ ];
154
+ // // let's make sure we only allow communication through the parent transports
155
+ params.connectionGater = {
156
+ // who can call us?
157
+ denyInboundEncryptedConnection: (peerId, maConn) => {
158
+ // deny all inbound connections unless they are from a parent transport
159
+ if (this.parentPeerId === peerId.toString()) {
160
+ return false;
161
+ }
162
+ if (this.hierarchyManager.children.some((c) => c.libp2pTransports.some((t) => t.toPeerId() === peerId.toString()))) {
163
+ return false;
164
+ }
165
+ // allow leader inbounds
166
+ if (this.config.type === NodeType.LEADER) {
167
+ return false;
168
+ }
169
+ // deny everything else
170
+ return true;
171
+ },
172
+ // allow the user to override the default connection gater
173
+ ...(this.config.network?.connectionGater || {}),
174
+ };
175
+ }
176
+ // handle the address encapsulation
177
+ if (this.config.leader &&
178
+ !this.address.protocol.includes(this.config.leader.protocol)) {
179
+ const parentAddress = this.config.parent || this.config.leader;
180
+ this.logger.debug('Encapsulating address: ' + this.address.toString(), parentAddress.toString());
181
+ this.address = CoreUtils.childAddress(parentAddress, this.address);
182
+ this.logger.debug('Encapsulated address: ' + this.address.toString());
183
+ }
184
+ return params;
185
+ }
186
+ async connect(nextHopAddress, targetAddress) {
187
+ if (!this.connectionManager) {
188
+ this.logger.error('Connection manager not initialized');
189
+ throw new Error('Node is not ready to connect to other nodes');
190
+ }
191
+ const connection = await this.connectionManager
192
+ .connect({
193
+ address: targetAddress,
194
+ nextHopAddress,
195
+ callerAddress: this.address,
196
+ })
197
+ .catch((error) => {
198
+ // TODO: we need to handle this better and document
199
+ if (error.message === 'Can not dial self') {
200
+ this.logger.error('Make sure you are entering the network not directly through the leader node.');
201
+ }
202
+ throw error;
203
+ });
204
+ if (!connection) {
205
+ throw new Error('Connection failed');
206
+ }
207
+ return connection;
208
+ }
209
+ async initialize() {
210
+ this.logger.debug('Initializing node...');
211
+ if (this.p2pNode && this.state !== NodeState.STOPPED) {
212
+ throw new Error('Node is not in a valid state to be initialized');
213
+ }
214
+ if (!this.address.validate()) {
215
+ throw new Error('Invalid address');
216
+ }
217
+ const params = await this.configure();
218
+ this.p2pNode = await createNode(params);
219
+ await this.initializeRouter();
220
+ this.logger.debug('Node initialized!', this.transports.map((t) => t.toString()));
221
+ this.address.setTransports(this.transports);
222
+ this.peerId = this.p2pNode.peerId;
223
+ // initialize connection manager
224
+ this.connectionManager = new oNodeConnectionManager({
225
+ p2pNode: this.p2pNode,
226
+ });
227
+ // initialize address resolution
228
+ this.router.addResolver(new oMethodResolver(this.address));
229
+ this.router.addResolver(new oNodeResolver(this.address));
230
+ // setup a fallback resolver for non-leader nodes
231
+ if (this.isLeader === false) {
232
+ this.logger.debug('Adding leader resolver fallback...');
233
+ this.router.addResolver(new oLeaderResolverFallback(this.address));
234
+ }
235
+ }
236
+ async teardown() {
237
+ await super.teardown();
238
+ if (this.p2pNode) {
239
+ await this.p2pNode.stop();
240
+ }
241
+ }
242
+ }
@@ -0,0 +1,16 @@
1
+ import { oAddress } from '@olane/o-core';
2
+ import { IncomingStreamData } from '@olane/o-config';
3
+ import { oServerNode } from './nodes/server.node.js';
4
+ declare const oNodeTool_base: typeof oServerNode;
5
+ /**
6
+ * oTool is a mixin that extends the base class and implements the oTool interface
7
+ * @param Base - The base class to extend
8
+ * @returns A new class that extends the base class and implements the oTool interface
9
+ */
10
+ export declare class oNodeTool extends oNodeTool_base {
11
+ handleProtocol(address: oAddress): Promise<void>;
12
+ initialize(): Promise<void>;
13
+ handleStream(streamData: IncomingStreamData): Promise<void>;
14
+ }
15
+ export {};
16
+ //# sourceMappingURL=o-node.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAKT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;;AAErD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IACzC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAKhC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,YAAY,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CAgClE"}
@@ -0,0 +1,48 @@
1
+ import { CoreUtils, oError, oErrorCodes, oRequest, } from '@olane/o-core';
2
+ import { oTool } from '@olane/o-tool';
3
+ import { oServerNode } from './nodes/server.node.js';
4
+ /**
5
+ * oTool is a mixin that extends the base class and implements the oTool interface
6
+ * @param Base - The base class to extend
7
+ * @returns A new class that extends the base class and implements the oTool interface
8
+ */
9
+ export class oNodeTool extends oTool(oServerNode) {
10
+ async handleProtocol(address) {
11
+ this.logger.debug('Handling protocol: ' + address.protocol);
12
+ await this.p2pNode.handle(address.protocol, this.handleStream.bind(this));
13
+ }
14
+ async initialize() {
15
+ await super.initialize();
16
+ await this.handleProtocol(this.address);
17
+ if (this.staticAddress &&
18
+ this.staticAddress?.toString() !== this.address.toString()) {
19
+ await this.handleProtocol(this.staticAddress);
20
+ }
21
+ }
22
+ async handleStream(streamData) {
23
+ const { stream } = streamData;
24
+ const requestConfig = await CoreUtils.processStream(stream);
25
+ const request = new oRequest(requestConfig);
26
+ let success = true;
27
+ const result = await this.execute(request, stream).catch((error) => {
28
+ this.logger.error('Error executing tool: ', error, typeof error);
29
+ success = false;
30
+ const responseError = error instanceof oError
31
+ ? error
32
+ : new oError(oErrorCodes.UNKNOWN, error.message);
33
+ return {
34
+ error: responseError.toJSON(),
35
+ };
36
+ });
37
+ if (success) {
38
+ this.metrics.successCount++;
39
+ }
40
+ else {
41
+ this.metrics.errorCount++;
42
+ }
43
+ // compose the response & add the expected connection + request fields
44
+ const response = CoreUtils.buildResponse(request, result, result?.error);
45
+ // add the request method to the response
46
+ return CoreUtils.sendResponse(response, stream);
47
+ }
48
+ }
@@ -0,0 +1,6 @@
1
+ export * from './o-node.address.js';
2
+ export * from './o-node.router.js';
3
+ export * from './o-node.transport.js';
4
+ export * from './resolvers/index.js';
5
+ export * from './route.request.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/router/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './o-node.address.js';
2
+ export * from './o-node.router.js';
3
+ export * from './o-node.transport.js';
4
+ export * from './resolvers/index.js';
5
+ export * from './route.request.js';
@@ -0,0 +1,3 @@
1
+ export interface oNodeRouterConfig {
2
+ }
3
+ //# sourceMappingURL=o-node-router.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node-router.config.d.ts","sourceRoot":"","sources":["../../../../src/router/interfaces/o-node-router.config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;CAAG"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { oNodeAddress } from '../o-node.address';
2
+ import { oRouterRequest, RouteResponse } from '@olane/o-core';
3
+ export interface oNodeRouterResponse extends RouteResponse {
4
+ nextHopAddress: oNodeAddress;
5
+ targetAddress: oNodeAddress;
6
+ requestOverride?: oRouterRequest;
7
+ }
8
+ //# sourceMappingURL=o-node-router.response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node-router.response.d.ts","sourceRoot":"","sources":["../../../../src/router/interfaces/o-node-router.response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,cAAc,EAAE,YAAY,CAAC;IAC7B,aAAa,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,cAAc,CAAC;CAClC"}
@@ -0,0 +1,18 @@
1
+ import { Multiaddr } from '@olane/o-config';
2
+ import { oNodeTransport } from './o-node.transport.js';
3
+ import { oAddress } from '@olane/o-core';
4
+ export declare class oNodeAddress extends oAddress {
5
+ readonly value: string;
6
+ transports: oNodeTransport[];
7
+ constructor(value: string, transports?: oNodeTransport[]);
8
+ static fromJSON(json: {
9
+ value: string;
10
+ transports: string[] | Multiaddr[];
11
+ }): oNodeAddress;
12
+ get libp2pTransports(): oNodeTransport[];
13
+ get customTransports(): oNodeTransport[];
14
+ toString(): string;
15
+ toMultiaddr(): Multiaddr;
16
+ static fromMultiaddr(ma: Multiaddr): oAddress;
17
+ }
18
+ //# sourceMappingURL=o-node.address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.address.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAqB,QAAQ,EAAiB,MAAM,eAAe,CAAC;AAE3E,qBAAa,YAAa,SAAQ,QAAQ;aAItB,KAAK,EAAE,MAAM;IAHxB,UAAU,EAAE,cAAc,EAAE,CAAM;gBAGvB,KAAK,EAAE,MAAM,EAC7B,UAAU,GAAE,cAAc,EAAO;IAMnC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;KACpC,GAAG,YAAY;IAShB,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,QAAQ,IAAI,MAAM;IAIlB,WAAW,IAAI,SAAS;IAIxB,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,QAAQ;CAG9C"}
@@ -0,0 +1,29 @@
1
+ import { multiaddr } from '@olane/o-config';
2
+ import { oNodeTransport } from './o-node.transport.js';
3
+ import { oAddress, TransportType } from '@olane/o-core';
4
+ export class oNodeAddress extends oAddress {
5
+ constructor(value, transports = []) {
6
+ super(value);
7
+ this.value = value;
8
+ this.transports = [];
9
+ this.transports = transports;
10
+ }
11
+ static fromJSON(json) {
12
+ return new oNodeAddress(json.value, json.transports.map((t) => new oNodeTransport(t)));
13
+ }
14
+ get libp2pTransports() {
15
+ return this.transports.filter((t) => t.type === TransportType.LIBP2P) || [];
16
+ }
17
+ get customTransports() {
18
+ return this.transports.filter((t) => t.type === TransportType.CUSTOM) || [];
19
+ }
20
+ toString() {
21
+ return this.value;
22
+ }
23
+ toMultiaddr() {
24
+ return multiaddr(this.protocol);
25
+ }
26
+ static fromMultiaddr(ma) {
27
+ return new oAddress(ma.toString().replace('/o/', 'o://'));
28
+ }
29
+ }
@@ -0,0 +1,12 @@
1
+ import { oNodeAddress } from './o-node.address.js';
2
+ import { oRouterRequest, RouteResponse } from '@olane/o-core';
3
+ import type { oNode } from '../o-node.js';
4
+ import { oToolRouter } from '@olane/o-tool';
5
+ export declare class oNodeRouter extends oToolRouter {
6
+ constructor();
7
+ protected forward(address: oNodeAddress, request: oRouterRequest, node: oNode): Promise<any>;
8
+ private handleExternalAddress;
9
+ translate(address: oNodeAddress, node: oNode): Promise<RouteResponse>;
10
+ isInternal(addressWithTransports: oNodeAddress, node: oNode): boolean;
11
+ }
12
+ //# sourceMappingURL=o-node.router.d.ts.map
@@ -0,0 +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,EAOL,cAAc,EACd,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAI5C,qBAAa,WAAY,SAAQ,WAAW;;cAK1B,OAAO,CACrB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,KAAK,GACV,OAAO,CAAC,GAAG,CAAC;IAgFf,OAAO,CAAC,qBAAqB;IAsBvB,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IAoB3E,UAAU,CAAC,qBAAqB,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;CAetE"}
@@ -0,0 +1,109 @@
1
+ import { oNodeAddress } from './o-node.address.js';
2
+ import { CoreUtils, oAddress, oError, oErrorCodes, oRequest, } from '@olane/o-core';
3
+ import { oToolRouter } from '@olane/o-tool';
4
+ import { pipe, pushable } from '@olane/o-config';
5
+ export class oNodeRouter extends oToolRouter {
6
+ constructor() {
7
+ super();
8
+ }
9
+ async forward(address, request, node) {
10
+ if (!request.stream) {
11
+ throw new oError(oErrorCodes.INVALID_REQUEST, 'Stream is required');
12
+ }
13
+ const stream = request.stream;
14
+ let nextHopRequest = new oRequest({
15
+ method: request.method,
16
+ params: request.params,
17
+ id: request.id,
18
+ });
19
+ // are we dialing self?
20
+ if (node.address.toString() === address.toString()) {
21
+ const { payload } = request.params;
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 CoreUtils.sendResponse(response, stream);
34
+ }
35
+ // next hop is the destination address
36
+ if (address
37
+ ?.toStaticAddress()
38
+ .equals(new oAddress(request?.params?.address).toStaticAddress())) {
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
+ });
49
+ }
50
+ // dial the target
51
+ try {
52
+ const targetStream = await node?.p2pNode.dialProtocol(address.libp2pTransports.map((t) => t.toMultiaddr()), address.protocol);
53
+ if (!targetStream) {
54
+ throw new oError(oErrorCodes.FAILED_TO_DIAL_TARGET, 'Failed to dial target');
55
+ }
56
+ const pushableStream = pushable();
57
+ pushableStream.push(new TextEncoder().encode(nextHopRequest.toString()));
58
+ pushableStream.end();
59
+ await targetStream.sink(pushableStream);
60
+ await pipe(targetStream.source, stream?.sink);
61
+ }
62
+ catch (error) {
63
+ if (error?.name === 'UnsupportedProtocolError') {
64
+ throw new oError(oErrorCodes.NOT_FOUND, 'Address not found');
65
+ }
66
+ throw error;
67
+ }
68
+ }
69
+ handleExternalAddress(address, node) {
70
+ // determine if this is external
71
+ const isInternal = this.isInternal(address, node);
72
+ if (!isInternal) {
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
+ }
83
+ async translate(address, node) {
84
+ const externalRoute = this.handleExternalAddress(address, node);
85
+ if (externalRoute) {
86
+ return externalRoute;
87
+ }
88
+ const { nextHopAddress, targetAddress, requestOverride } = await this.addressResolution.resolve({
89
+ address,
90
+ node,
91
+ targetAddress: address,
92
+ });
93
+ return {
94
+ nextHopAddress,
95
+ targetAddress: targetAddress,
96
+ requestOverride,
97
+ };
98
+ }
99
+ isInternal(addressWithTransports, node) {
100
+ if (addressWithTransports.paths.indexOf(oAddress.leader().paths) !== -1 && // if the address has a leader
101
+ addressWithTransports.libp2pTransports?.length > 0) {
102
+ // transports are provided, let's see if they match our known leaders
103
+ const isLeaderRef = addressWithTransports.toString() === oAddress.leader().toString();
104
+ const isOurLeaderRef = node.hierarchyManager.leaders.some((l) => l.equals(addressWithTransports));
105
+ return isLeaderRef || isOurLeaderRef;
106
+ }
107
+ return true;
108
+ }
109
+ }
@@ -0,0 +1,11 @@
1
+ import { Multiaddr } from '@olane/o-config';
2
+ import { oTransport, TransportType } from '@olane/o-core';
3
+ export declare class oNodeTransport extends oTransport {
4
+ readonly type: TransportType;
5
+ value: Multiaddr | string;
6
+ constructor(value: Multiaddr | string);
7
+ toMultiaddr(): Multiaddr;
8
+ toString(): string;
9
+ toPeerId(): string;
10
+ }
11
+ //# sourceMappingURL=o-node.transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.transport.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE1D,qBAAa,cAAe,SAAQ,UAAU;IAC5C,SAAgB,IAAI,EAAE,aAAa,CAAwB;IACpD,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;gBAErB,KAAK,EAAE,SAAS,GAAG,MAAM;IAKrC,WAAW,IAAI,SAAS;IAIxB,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;CAGnB"}
@@ -0,0 +1,18 @@
1
+ import { multiaddr } from '@olane/o-config';
2
+ import { oTransport, TransportType } from '@olane/o-core';
3
+ export class oNodeTransport extends oTransport {
4
+ constructor(value) {
5
+ super(value);
6
+ this.type = TransportType.LIBP2P;
7
+ this.value = value;
8
+ }
9
+ toMultiaddr() {
10
+ return multiaddr(this.toString());
11
+ }
12
+ toString() {
13
+ return this.value.toString();
14
+ }
15
+ toPeerId() {
16
+ return this.value.toString().split('/p2p/')[1];
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ export * from './o-node.search-resolver.js';
2
+ export * from './o-node.resolver.js';
3
+ export * from './o-node.leader-resolver-fallback.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/router/resolvers/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './o-node.search-resolver.js';
2
+ export * from './o-node.resolver.js';
3
+ export * from './o-node.leader-resolver-fallback.js';
@@ -0,0 +1,11 @@
1
+ import { oAddressResolver, TransportType } from '@olane/o-core';
2
+ import { oNodeAddress } from '../o-node.address.js';
3
+ import { oNodeRouterResponse } from '../interfaces/o-node-router.response.js';
4
+ import { ResolveRequest } from '@olane/o-core';
5
+ export declare class oNodeChildResolver extends oAddressResolver {
6
+ protected readonly address: oNodeAddress;
7
+ constructor(address: oNodeAddress);
8
+ get supportedTransports(): TransportType[];
9
+ resolve(routeRequest: ResolveRequest): Promise<oNodeRouterResponse>;
10
+ }
11
+ //# sourceMappingURL=o-node.child-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.child-resolver.d.ts","sourceRoot":"","sources":["../../../../src/router/resolvers/o-node.child-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAEhB,aAAa,EAEd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,qBAAa,kBAAmB,SAAQ,gBAAgB;IAC1C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY;gBAArB,OAAO,EAAE,YAAY;IAIpD,IAAI,mBAAmB,IAAI,aAAa,EAAE,CAEzC;IAEK,OAAO,CAAC,YAAY,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC;CA4D1E"}