@olane/o-node 0.7.40 → 0.7.42
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/index.d.ts +1 -1
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +1 -1
- package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts +8 -0
- package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/o-node-connection-stream.config.js +1 -0
- package/dist/src/connection/o-node-connection-stream.d.ts +34 -0
- package/dist/src/connection/o-node-connection-stream.d.ts.map +1 -0
- package/dist/src/connection/o-node-connection-stream.js +68 -0
- package/dist/src/connection/o-node-connection.d.ts +10 -4
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +51 -34
- package/dist/src/connection/o-node-connection.manager.d.ts +4 -0
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +24 -0
- package/dist/src/connection/stream-handler.d.ts +1 -59
- package/dist/src/connection/stream-handler.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.js +104 -179
- package/dist/src/o-node.tool.d.ts +3 -1
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +44 -11
- package/dist/src/router/o-node.address.d.ts +1 -0
- package/dist/src/router/o-node.address.d.ts.map +1 -1
- package/dist/src/router/o-node.address.js +4 -0
- package/dist/src/utils/connection.utils.d.ts +9 -0
- package/dist/src/utils/connection.utils.d.ts.map +1 -0
- package/dist/src/utils/connection.utils.js +48 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -0
- package/dist/test/astream-reuse.spec.d.ts +2 -0
- package/dist/test/astream-reuse.spec.d.ts.map +1 -0
- package/dist/test/astream-reuse.spec.js +107 -0
- package/dist/test/connection-management.spec.js +1 -0
- package/dist/test/helpers/network-builder.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/src/connection/o-managed-stream.d.ts +0 -57
- package/dist/src/connection/o-managed-stream.d.ts.map +0 -1
- package/dist/src/connection/o-managed-stream.js +0 -76
- package/dist/test/o-managed-stream.spec.d.ts +0 -2
- package/dist/test/o-managed-stream.spec.d.ts.map +0 -1
- package/dist/test/o-managed-stream.spec.js +0 -122
- package/dist/test/stream-handler-caching.spec.d.ts +0 -2
- package/dist/test/stream-handler-caching.spec.d.ts.map +0 -1
- package/dist/test/stream-handler-caching.spec.js +0 -261
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { oRequest, oResponse, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
|
|
2
2
|
import { lpStream } from '@olane/o-config';
|
|
3
3
|
import JSON5 from 'json5';
|
|
4
|
-
import { oManagedStream } from './o-managed-stream.js';
|
|
5
4
|
/**
|
|
6
5
|
* StreamHandler centralizes all stream-related functionality including:
|
|
7
6
|
* - Message type detection (request vs response)
|
|
@@ -12,7 +11,6 @@ import { oManagedStream } from './o-managed-stream.js';
|
|
|
12
11
|
*/
|
|
13
12
|
export class StreamHandler {
|
|
14
13
|
constructor(logger) {
|
|
15
|
-
this.streamCache = new Map();
|
|
16
14
|
this.logger = logger ?? new Logger('StreamHandler');
|
|
17
15
|
}
|
|
18
16
|
/**
|
|
@@ -85,161 +83,110 @@ export class StreamHandler {
|
|
|
85
83
|
const addresses = [callerAddress.value, receiverAddress.value].sort();
|
|
86
84
|
return `${addresses[0]}↔${addresses[1]}`;
|
|
87
85
|
}
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (cachedStream?.isReusable) {
|
|
193
|
-
this.logger.debug('Reusing cached stream by address', {
|
|
194
|
-
cacheKey,
|
|
195
|
-
streamId: cachedStream.stream.id,
|
|
196
|
-
direction: cachedStream.direction,
|
|
197
|
-
});
|
|
198
|
-
cachedStream.updateLastUsed();
|
|
199
|
-
return cachedStream.stream;
|
|
200
|
-
}
|
|
201
|
-
else if (cachedStream) {
|
|
202
|
-
// Stream exists but not reusable, remove from cache
|
|
203
|
-
this.logger.debug('Removing non-reusable stream from cache', {
|
|
204
|
-
cacheKey,
|
|
205
|
-
status: cachedStream.stream.status,
|
|
206
|
-
});
|
|
207
|
-
this.streamCache.delete(cacheKey);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
this.logger.debug('No reusable cached stream found, checking connection streams', connection.streams.map((s) => ({
|
|
211
|
-
status: s.status,
|
|
212
|
-
protocol: s.protocol,
|
|
213
|
-
writeStatus: s.writeStatus,
|
|
214
|
-
remoteReadStatus: s.remoteReadStatus,
|
|
215
|
-
id: s.id,
|
|
216
|
-
})));
|
|
217
|
-
// Fallback to protocol-based check (legacy behavior)
|
|
218
|
-
if (reusePolicy === 'reuse' && !streamAddresses) {
|
|
219
|
-
const existingStream = connection.streams.find((stream) => stream.status === 'open' &&
|
|
220
|
-
stream.protocol === protocol &&
|
|
221
|
-
stream.writeStatus === 'writable' &&
|
|
222
|
-
stream.remoteReadStatus === 'readable');
|
|
223
|
-
if (existingStream) {
|
|
224
|
-
this.logger.debug('Reusing existing stream by protocol (legacy)', existingStream.id, existingStream.direction);
|
|
225
|
-
return existingStream;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
// Create new stream
|
|
229
|
-
this.logger.debug('Creating new stream', { protocol });
|
|
230
|
-
const stream = await connection.newStream(protocol, {
|
|
231
|
-
signal: config.signal,
|
|
232
|
-
maxOutboundStreams: config.maxOutboundStreams ?? 1000,
|
|
233
|
-
runOnLimitedConnection: config.runOnLimitedConnection ?? false,
|
|
234
|
-
});
|
|
235
|
-
// Cache the stream if reuse is enabled and addresses are provided
|
|
236
|
-
if (reusePolicy === 'reuse' && streamAddresses) {
|
|
237
|
-
const managedStream = new oManagedStream(stream, streamAddresses.callerAddress, streamAddresses.receiverAddress, streamAddresses.direction);
|
|
238
|
-
this.cacheStream(managedStream);
|
|
239
|
-
this.setupStreamCleanup(stream);
|
|
240
|
-
}
|
|
241
|
-
return stream;
|
|
242
|
-
}
|
|
86
|
+
// /**
|
|
87
|
+
// * Gets an existing open stream or creates a new one based on reuse policy
|
|
88
|
+
// *
|
|
89
|
+
// * @param connection - The libp2p connection
|
|
90
|
+
// * @param protocol - The protocol to use for the stream
|
|
91
|
+
// * @param config - Stream handler configuration
|
|
92
|
+
// * @param streamAddresses - Optional addresses for address-based stream reuse
|
|
93
|
+
// */
|
|
94
|
+
// async getOrCreateStream(
|
|
95
|
+
// connection: Connection,
|
|
96
|
+
// protocol: string,
|
|
97
|
+
// config: StreamHandlerConfig = {},
|
|
98
|
+
// streamAddresses?: {
|
|
99
|
+
// callerAddress: oAddress;
|
|
100
|
+
// receiverAddress: oAddress;
|
|
101
|
+
// direction: 'inbound' | 'outbound';
|
|
102
|
+
// },
|
|
103
|
+
// ): Promise<Stream> {
|
|
104
|
+
// this.logger.debug(
|
|
105
|
+
// `Getting or creating stream for protocol: ${protocol}, connection`,
|
|
106
|
+
// {
|
|
107
|
+
// status: connection.status,
|
|
108
|
+
// remoteAddr: connection.remoteAddr.toString(),
|
|
109
|
+
// streamCount: connection.streams.length,
|
|
110
|
+
// reusePolicy: config.reusePolicy ?? 'none',
|
|
111
|
+
// hasAddresses: !!streamAddresses,
|
|
112
|
+
// },
|
|
113
|
+
// );
|
|
114
|
+
// if (connection.status !== 'open') {
|
|
115
|
+
// throw new oError(oErrorCodes.INVALID_STATE, 'Connection not open');
|
|
116
|
+
// }
|
|
117
|
+
// const reusePolicy = config.reusePolicy ?? 'none';
|
|
118
|
+
// // Check address-based cache if reuse is enabled and addresses provided
|
|
119
|
+
// if (reusePolicy === 'reuse' && streamAddresses) {
|
|
120
|
+
// const cacheKey = this.buildCacheKey(
|
|
121
|
+
// streamAddresses.callerAddress,
|
|
122
|
+
// streamAddresses.receiverAddress,
|
|
123
|
+
// );
|
|
124
|
+
// const cachedStream = this.streamCache.get(cacheKey);
|
|
125
|
+
// if (cachedStream?.isReusable) {
|
|
126
|
+
// this.logger.debug('Reusing cached stream by address', {
|
|
127
|
+
// cacheKey,
|
|
128
|
+
// streamId: cachedStream.stream.id,
|
|
129
|
+
// direction: cachedStream.direction,
|
|
130
|
+
// });
|
|
131
|
+
// cachedStream.updateLastUsed();
|
|
132
|
+
// return cachedStream.stream;
|
|
133
|
+
// } else if (cachedStream) {
|
|
134
|
+
// // Stream exists but not reusable, remove from cache
|
|
135
|
+
// this.logger.debug('Removing non-reusable stream from cache', {
|
|
136
|
+
// cacheKey,
|
|
137
|
+
// status: cachedStream.stream.status,
|
|
138
|
+
// });
|
|
139
|
+
// this.streamCache.delete(cacheKey);
|
|
140
|
+
// }
|
|
141
|
+
// }
|
|
142
|
+
// this.logger.debug(
|
|
143
|
+
// 'No reusable cached stream found, checking connection streams',
|
|
144
|
+
// connection.streams.map((s) => ({
|
|
145
|
+
// status: s.status,
|
|
146
|
+
// protocol: s.protocol,
|
|
147
|
+
// writeStatus: s.writeStatus,
|
|
148
|
+
// remoteReadStatus: s.remoteReadStatus,
|
|
149
|
+
// id: s.id,
|
|
150
|
+
// })),
|
|
151
|
+
// );
|
|
152
|
+
// // Fallback to protocol-based check (legacy behavior)
|
|
153
|
+
// if (reusePolicy === 'reuse' && !streamAddresses) {
|
|
154
|
+
// const existingStream = connection.streams.find(
|
|
155
|
+
// (stream) =>
|
|
156
|
+
// stream.status === 'open' &&
|
|
157
|
+
// stream.protocol === protocol &&
|
|
158
|
+
// stream.writeStatus === 'writable' &&
|
|
159
|
+
// stream.remoteReadStatus === 'readable',
|
|
160
|
+
// );
|
|
161
|
+
// if (existingStream) {
|
|
162
|
+
// this.logger.debug(
|
|
163
|
+
// 'Reusing existing stream by protocol (legacy)',
|
|
164
|
+
// existingStream.id,
|
|
165
|
+
// existingStream.direction,
|
|
166
|
+
// );
|
|
167
|
+
// return existingStream;
|
|
168
|
+
// }
|
|
169
|
+
// }
|
|
170
|
+
// // Create new stream
|
|
171
|
+
// this.logger.debug('Creating new stream', { protocol });
|
|
172
|
+
// const stream = await connection.newStream(protocol, {
|
|
173
|
+
// signal: config.signal,
|
|
174
|
+
// maxOutboundStreams: config.maxOutboundStreams ?? 1000,
|
|
175
|
+
// runOnLimitedConnection: config.runOnLimitedConnection ?? false,
|
|
176
|
+
// });
|
|
177
|
+
// // Cache the stream if reuse is enabled and addresses are provided
|
|
178
|
+
// if (reusePolicy === 'reuse' && streamAddresses) {
|
|
179
|
+
// const managedStream = new oNodeConnectionStream(
|
|
180
|
+
// stream,
|
|
181
|
+
// streamAddresses.callerAddress,
|
|
182
|
+
// streamAddresses.receiverAddress,
|
|
183
|
+
// streamAddresses.direction,
|
|
184
|
+
// );
|
|
185
|
+
// this.cacheStream(managedStream);
|
|
186
|
+
// this.setupStreamCleanup(stream);
|
|
187
|
+
// }
|
|
188
|
+
// return stream;
|
|
189
|
+
// }
|
|
243
190
|
/**
|
|
244
191
|
* Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
|
|
245
192
|
* Each message is automatically prefixed with a varint indicating the message length
|
|
@@ -253,28 +200,6 @@ export class StreamHandler {
|
|
|
253
200
|
const lp = lpStream(stream);
|
|
254
201
|
await lp.write(data, { signal: config.signal });
|
|
255
202
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Closes a stream safely with error handling
|
|
258
|
-
*
|
|
259
|
-
* @param stream - The stream to close
|
|
260
|
-
* @param config - Configuration including reuse policy
|
|
261
|
-
*/
|
|
262
|
-
async close(stream, config = {}) {
|
|
263
|
-
// Don't close if reuse policy is enabled
|
|
264
|
-
if (config.reusePolicy === 'reuse') {
|
|
265
|
-
this.logger.debug('Stream reuse enabled, not closing stream');
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
if (stream.status === 'open') {
|
|
269
|
-
try {
|
|
270
|
-
// force the close for now until we can implement a proper close
|
|
271
|
-
await stream.abort(new Error('Stream closed'));
|
|
272
|
-
}
|
|
273
|
-
catch (error) {
|
|
274
|
-
this.logger.debug('Error closing stream:', error.message);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
203
|
/**
|
|
279
204
|
* Handles an incoming stream on the server side using length-prefixed protocol
|
|
280
205
|
* Uses async read loops instead of event listeners (libp2p v3 best practice)
|
|
@@ -9,9 +9,11 @@ declare const oNodeTool_base: typeof oServerNode;
|
|
|
9
9
|
*/
|
|
10
10
|
export declare class oNodeTool extends oNodeTool_base {
|
|
11
11
|
private streamHandler;
|
|
12
|
+
handleProtocolReuse(address: oAddress): Promise<void>;
|
|
12
13
|
handleProtocol(address: oAddress): Promise<void>;
|
|
13
14
|
initialize(): Promise<void>;
|
|
14
|
-
|
|
15
|
+
handleStreamReuse(stream: Stream, connection: Connection): Promise<void>;
|
|
16
|
+
handleStream(stream: Stream, connection: Connection, reuse?: boolean): Promise<void>;
|
|
15
17
|
_tool_identify(): Promise<any>;
|
|
16
18
|
_tool_child_register(request: oRequest): Promise<any>;
|
|
17
19
|
}
|
|
@@ -1 +1 @@
|
|
|
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;;
|
|
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;;AAMrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,mBAAmB,CAAC,OAAO,EAAE,QAAQ;IAgBrC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAoBhC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAwCV,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAgC5D"}
|
package/dist/src/o-node.tool.js
CHANGED
|
@@ -4,25 +4,46 @@ import { oServerNode } from './nodes/server.node.js';
|
|
|
4
4
|
import { oNodeTransport } from './router/o-node.transport.js';
|
|
5
5
|
import { oNodeAddress } from './router/o-node.address.js';
|
|
6
6
|
import { StreamHandler } from './connection/stream-handler.js';
|
|
7
|
+
import { ConnectionUtils } from './utils/connection.utils.js';
|
|
7
8
|
/**
|
|
8
9
|
* oTool is a mixin that extends the base class and implements the oTool interface
|
|
9
10
|
* @param Base - The base class to extend
|
|
10
11
|
* @returns A new class that extends the base class and implements the oTool interface
|
|
11
12
|
*/
|
|
12
13
|
export class oNodeTool extends oTool(oServerNode) {
|
|
14
|
+
async handleProtocolReuse(address) {
|
|
15
|
+
const reuseProtocol = address.protocol + '/reuse';
|
|
16
|
+
const protocols = this.p2pNode.getProtocols();
|
|
17
|
+
if (protocols.find((p) => p === reuseProtocol)) {
|
|
18
|
+
// already handling
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
|
|
22
|
+
? parseInt(process.env.MAX_OUTBOUND_STREAMS)
|
|
23
|
+
: 1000;
|
|
24
|
+
await this.p2pNode.handle(reuseProtocol, this.handleStream.bind(this), {
|
|
25
|
+
maxInboundStreams: 10000,
|
|
26
|
+
maxOutboundStreams: maxOutboundsStreams,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
13
29
|
async handleProtocol(address) {
|
|
14
30
|
const protocols = this.p2pNode.getProtocols();
|
|
15
31
|
if (protocols.find((p) => p === address.protocol)) {
|
|
16
32
|
// already handling
|
|
17
33
|
return;
|
|
18
34
|
}
|
|
19
|
-
|
|
35
|
+
const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
|
|
36
|
+
? parseInt(process.env.MAX_OUTBOUND_STREAMS)
|
|
37
|
+
: 1000;
|
|
38
|
+
this.logger.debug('Handling protocol: ' + address.protocol, {
|
|
39
|
+
maxInboundStreams: 10000,
|
|
40
|
+
maxOutboundStreams: maxOutboundsStreams,
|
|
41
|
+
});
|
|
20
42
|
await this.p2pNode.handle(address.protocol, this.handleStream.bind(this), {
|
|
21
43
|
maxInboundStreams: 10000,
|
|
22
|
-
maxOutboundStreams:
|
|
23
|
-
? parseInt(process.env.MAX_OUTBOUND_STREAMS)
|
|
24
|
-
: 1000,
|
|
44
|
+
maxOutboundStreams: maxOutboundsStreams,
|
|
25
45
|
});
|
|
46
|
+
await this.handleProtocolReuse(address);
|
|
26
47
|
}
|
|
27
48
|
async initialize() {
|
|
28
49
|
await super.initialize();
|
|
@@ -33,12 +54,25 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
33
54
|
await this.handleProtocol(this.staticAddress);
|
|
34
55
|
}
|
|
35
56
|
}
|
|
36
|
-
async
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
async handleStreamReuse(stream, connection) {
|
|
58
|
+
return this.handleStream(stream, connection, true);
|
|
59
|
+
}
|
|
60
|
+
async handleStream(stream, connection, reuse) {
|
|
61
|
+
if (reuse) {
|
|
62
|
+
this.logger.debug('Handle stream with reuse = true');
|
|
63
|
+
}
|
|
64
|
+
// record inbound connection to manager
|
|
65
|
+
const remoteAddress = await ConnectionUtils.addressFromConnection({
|
|
66
|
+
currentNode: this,
|
|
67
|
+
connection: connection,
|
|
68
|
+
});
|
|
69
|
+
this.connectionManager.answer({
|
|
70
|
+
nextHopAddress: remoteAddress,
|
|
71
|
+
address: remoteAddress,
|
|
72
|
+
callerAddress: this.address,
|
|
73
|
+
p2pConnection: connection,
|
|
74
|
+
reuse,
|
|
75
|
+
});
|
|
42
76
|
// Use StreamHandler for consistent stream handling
|
|
43
77
|
// This follows libp2p v3 best practices for length-prefixed streaming
|
|
44
78
|
await this.streamHandler.handleIncomingStream(stream, connection, async (request, stream) => {
|
|
@@ -61,7 +95,6 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
61
95
|
};
|
|
62
96
|
}
|
|
63
97
|
async _tool_child_register(request) {
|
|
64
|
-
this.logger.debug('Child register: ', request.params);
|
|
65
98
|
const { address, transports } = request.params;
|
|
66
99
|
const childAddress = new oNodeAddress(address, transports.map((t) => new oNodeTransport(t)));
|
|
67
100
|
// Add child to hierarchy
|
|
@@ -1 +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;
|
|
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;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAiB,MAAM,eAAe,CAAC;AAExD,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;IAI7C,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY;CAIpD"}
|
|
@@ -26,4 +26,8 @@ export class oNodeAddress extends oAddress {
|
|
|
26
26
|
static fromMultiaddr(ma) {
|
|
27
27
|
return new oAddress(ma.toString().replace('/o/', 'o://'));
|
|
28
28
|
}
|
|
29
|
+
static fromProtocol(protocol) {
|
|
30
|
+
const addressInput = protocol.replace('/o/', 'o://');
|
|
31
|
+
return new oNodeAddress(addressInput);
|
|
32
|
+
}
|
|
29
33
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Connection } from '@olane/o-config';
|
|
2
|
+
import { oObject } from '@olane/o-core';
|
|
3
|
+
export declare class ConnectionUtils extends oObject {
|
|
4
|
+
static addressFromConnection(options: {
|
|
5
|
+
currentNode: any;
|
|
6
|
+
connection: Connection;
|
|
7
|
+
}): Promise<any>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=connection.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/connection.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAuB,OAAO,EAAE,MAAM,eAAe,CAAC;AAI7D,qBAAa,eAAgB,SAAQ,OAAO;WACtB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;CAmEF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { oError, oErrorCodes, oObject } from '@olane/o-core';
|
|
2
|
+
import { oNodeAddress } from '../router/o-node.address.js';
|
|
3
|
+
import { oNodeTransport } from '../router/o-node.transport.js';
|
|
4
|
+
export class ConnectionUtils extends oObject {
|
|
5
|
+
static async addressFromConnection(options) {
|
|
6
|
+
try {
|
|
7
|
+
console.log('[ConnectionUtils] addressFromConnection');
|
|
8
|
+
const { currentNode, connection } = options;
|
|
9
|
+
const p2pNode = currentNode.p2pNode;
|
|
10
|
+
// Extract the actual olane address from the peer store
|
|
11
|
+
const peers = await p2pNode.peerStore.all();
|
|
12
|
+
const remotePeer = peers.find((peer) => peer.id.toString() === connection.remotePeer.toString());
|
|
13
|
+
if (!remotePeer) {
|
|
14
|
+
console.log('Failed to find peer:', remotePeer);
|
|
15
|
+
throw new Error(`Failed to extract remote address, peer ${connection.remotePeer.toString()} not found in peer store.`);
|
|
16
|
+
}
|
|
17
|
+
// Get origin address for comparison
|
|
18
|
+
const originAddress = currentNode.address?.value;
|
|
19
|
+
if (!originAddress) {
|
|
20
|
+
throw new Error('Origin address is not configured');
|
|
21
|
+
}
|
|
22
|
+
const originProtocol = originAddress.toString();
|
|
23
|
+
const oProtocol = remotePeer.protocols.find((p) => p.startsWith('/o/') && p.startsWith(originProtocol) === false);
|
|
24
|
+
if (!oProtocol) {
|
|
25
|
+
throw new Error('Failed to extract remote address, could not find o-protocol in peer protocols.');
|
|
26
|
+
}
|
|
27
|
+
const address = oNodeAddress.fromProtocol(oProtocol);
|
|
28
|
+
if (remotePeer.addresses.length === 0 &&
|
|
29
|
+
address.value === currentNode.leader.value) {
|
|
30
|
+
// leader - use known address
|
|
31
|
+
return currentNode.leader;
|
|
32
|
+
}
|
|
33
|
+
if (remotePeer.addresses.length === 0 &&
|
|
34
|
+
address.value === currentNode.parent.value) {
|
|
35
|
+
// leader - use known address
|
|
36
|
+
return currentNode.parent;
|
|
37
|
+
}
|
|
38
|
+
address.setTransports(remotePeer.addresses.map(({ multiaddr }) => {
|
|
39
|
+
return new oNodeTransport(multiaddr);
|
|
40
|
+
}));
|
|
41
|
+
return address;
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error('Failed to get address from connection:', e);
|
|
45
|
+
throw new oError(oErrorCodes.UNKNOWN, 'Failed to get address from connection');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC"}
|
package/dist/src/utils/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astream-reuse.spec.d.ts","sourceRoot":"","sources":["../../test/astream-reuse.spec.ts"],"names":[],"mappings":""}
|