@olane/o-node 0.7.31 → 0.7.34
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/interfaces/o-node-connection-manager.config.d.ts +1 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts +5 -0
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +11 -2
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +1 -0
- package/dist/src/connection/stream-handler.config.d.ts +13 -0
- package/dist/src/connection/stream-handler.config.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.d.ts +35 -1
- package/dist/src/connection/stream-handler.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.js +143 -5
- package/dist/src/interfaces/o-node.config.d.ts +7 -0
- package/dist/src/interfaces/o-node.config.d.ts.map +1 -1
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +1 -0
- package/dist/src/o-node.notification-manager.d.ts.map +1 -1
- package/dist/src/o-node.notification-manager.js +0 -2
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +2 -0
- package/dist/test/connection-management.spec.js +54 -50
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
|
|
@@ -3,5 +3,10 @@ import { oConnectionConfig } from '@olane/o-core';
|
|
|
3
3
|
export interface oNodeConnectionConfig extends oConnectionConfig {
|
|
4
4
|
p2pConnection: Connection;
|
|
5
5
|
runOnLimitedConnection?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Enable length-prefixed streaming (libp2p v3 best practice)
|
|
8
|
+
* @default false (for backward compatibility)
|
|
9
|
+
*/
|
|
10
|
+
useLengthPrefixing?: boolean;
|
|
6
11
|
}
|
|
7
12
|
//# sourceMappingURL=o-node-connection.config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;IAM5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;IAM5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAmBpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAkD/C,YAAY,CAAC,MAAM,EAAE,MAAM;IAQ3B,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAKZ"}
|
|
@@ -25,9 +25,10 @@ export class oNodeConnection extends oConnection {
|
|
|
25
25
|
maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
|
|
26
26
|
? parseInt(process.env.MAX_OUTBOUND_STREAMS)
|
|
27
27
|
: 1000,
|
|
28
|
-
runOnLimitedConnection: this.config.runOnLimitedConnection ??
|
|
28
|
+
runOnLimitedConnection: this.config.runOnLimitedConnection ?? true,
|
|
29
29
|
reusePolicy: 'none', // Default policy, can be overridden in subclasses
|
|
30
30
|
drainTimeoutMs: this.config.drainTimeoutMs,
|
|
31
|
+
useLengthPrefixing: this.config.useLengthPrefixing ?? true,
|
|
31
32
|
};
|
|
32
33
|
return this.streamHandler.getOrCreateStream(this.p2pConnection, this.nextHopAddress.protocol, streamConfig);
|
|
33
34
|
}
|
|
@@ -42,10 +43,18 @@ export class oNodeConnection extends oConnection {
|
|
|
42
43
|
signal: this.abortSignal,
|
|
43
44
|
drainTimeoutMs: this.config.drainTimeoutMs,
|
|
44
45
|
reusePolicy: 'none', // Default policy
|
|
46
|
+
useLengthPrefixing: this.config.useLengthPrefixing ?? true,
|
|
45
47
|
};
|
|
46
48
|
// Send the request with backpressure handling
|
|
47
49
|
const data = new TextEncoder().encode(request.toString());
|
|
48
|
-
|
|
50
|
+
// Use length-prefixed encoding if enabled
|
|
51
|
+
if (streamConfig.useLengthPrefixing) {
|
|
52
|
+
this.logger.info('Length prefix enabled...');
|
|
53
|
+
await this.streamHandler.sendLengthPrefixed(stream, data, streamConfig);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
await this.streamHandler.send(stream, data, streamConfig);
|
|
57
|
+
}
|
|
49
58
|
// Handle response using StreamHandler
|
|
50
59
|
// Pass request handler if configured to enable bidirectional stream processing
|
|
51
60
|
// Pass request ID to enable proper response correlation on shared streams
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,0BAA0B,CACtB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YA+DR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,0BAA0B,CACtB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YA+DR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA+BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAwCpC;;;;OAIG;IACH,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI;IA+C/D;;;OAGG;IACH,aAAa,IAAI;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9D;IAaD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAgBlC"}
|
|
@@ -148,6 +148,7 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
148
148
|
isStream: config.isStream ?? false,
|
|
149
149
|
abortSignal: config.abortSignal,
|
|
150
150
|
runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
|
|
151
|
+
useLengthPrefixing: this.config.useLengthPrefixing,
|
|
151
152
|
requestHandler: config.requestHandler ?? undefined,
|
|
152
153
|
});
|
|
153
154
|
return connection;
|
|
@@ -34,6 +34,19 @@ export interface StreamHandlerConfig {
|
|
|
34
34
|
* AbortSignal for cancellation
|
|
35
35
|
*/
|
|
36
36
|
signal?: AbortSignal;
|
|
37
|
+
/**
|
|
38
|
+
* Enable length-prefixed streaming (libp2p v3 best practice)
|
|
39
|
+
* When enabled, all messages are prefixed with a varint indicating message length
|
|
40
|
+
* This provides proper message boundaries and eliminates concatenation issues
|
|
41
|
+
* @default false (for backward compatibility)
|
|
42
|
+
*/
|
|
43
|
+
useLengthPrefixing?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Auto-detect protocol (length-prefixed vs raw JSON)
|
|
46
|
+
* When enabled, automatically detects the protocol by examining first byte
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
autoDetectProtocol?: boolean;
|
|
37
50
|
}
|
|
38
51
|
/**
|
|
39
52
|
* Context for stream lifecycle operations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-handler.config.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.config.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"stream-handler.config.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.config.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B"}
|
|
@@ -47,6 +47,16 @@ export declare class StreamHandler {
|
|
|
47
47
|
* @param config - Configuration for timeout and other options
|
|
48
48
|
*/
|
|
49
49
|
send(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
|
|
52
|
+
* Each message is automatically prefixed with a varint indicating the message length
|
|
53
|
+
* This ensures proper message boundaries and eliminates concatenation issues
|
|
54
|
+
*
|
|
55
|
+
* @param stream - The stream to send data through
|
|
56
|
+
* @param data - The data to send
|
|
57
|
+
* @param config - Configuration for timeout and other options
|
|
58
|
+
*/
|
|
59
|
+
sendLengthPrefixed(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
|
|
50
60
|
/**
|
|
51
61
|
* Closes a stream safely with error handling
|
|
52
62
|
*
|
|
@@ -54,6 +64,16 @@ export declare class StreamHandler {
|
|
|
54
64
|
* @param config - Configuration including reuse policy
|
|
55
65
|
*/
|
|
56
66
|
close(stream: Stream, config?: StreamHandlerConfig): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Handles an incoming stream on the server side using length-prefixed protocol
|
|
69
|
+
* Uses async read loops instead of event listeners (libp2p v3 best practice)
|
|
70
|
+
* Processes complete messages with proper boundaries
|
|
71
|
+
*
|
|
72
|
+
* @param stream - The incoming stream
|
|
73
|
+
* @param connection - The connection the stream belongs to
|
|
74
|
+
* @param toolExecutor - Function to execute tools for requests
|
|
75
|
+
*/
|
|
76
|
+
handleIncomingStreamLP(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult>): Promise<void>;
|
|
57
77
|
/**
|
|
58
78
|
* Handles an incoming stream on the server side
|
|
59
79
|
* Attaches message listener immediately (libp2p v3 best practice)
|
|
@@ -62,16 +82,30 @@ export declare class StreamHandler {
|
|
|
62
82
|
* @param stream - The incoming stream
|
|
63
83
|
* @param connection - The connection the stream belongs to
|
|
64
84
|
* @param toolExecutor - Function to execute tools for requests
|
|
85
|
+
* @param config - Configuration to determine protocol handling
|
|
65
86
|
*/
|
|
66
|
-
handleIncomingStream(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult
|
|
87
|
+
handleIncomingStream(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult>, config?: StreamHandlerConfig): Promise<void>;
|
|
67
88
|
/**
|
|
68
89
|
* Handles a request message by executing the tool and sending response
|
|
69
90
|
*
|
|
70
91
|
* @param message - The decoded request message
|
|
71
92
|
* @param stream - The stream to send the response on
|
|
72
93
|
* @param toolExecutor - Function to execute the tool
|
|
94
|
+
* @param useLengthPrefixing - Whether to use length-prefixed response encoding
|
|
73
95
|
*/
|
|
74
96
|
private handleRequestMessage;
|
|
97
|
+
/**
|
|
98
|
+
* Handles an outgoing stream on the client side using length-prefixed protocol
|
|
99
|
+
* Uses async read loops to process responses with proper message boundaries
|
|
100
|
+
*
|
|
101
|
+
* @param stream - The outgoing stream
|
|
102
|
+
* @param emitter - Event emitter for chunk events
|
|
103
|
+
* @param config - Configuration including abort signal
|
|
104
|
+
* @param requestHandler - Optional handler for processing router requests received on this stream
|
|
105
|
+
* @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
|
|
106
|
+
* @returns Promise that resolves with the final response
|
|
107
|
+
*/
|
|
108
|
+
handleOutgoingStreamLP(stream: Stream, emitter: EventEmitter, config?: StreamHandlerConfig, requestHandler?: (request: oRequest, stream: Stream) => Promise<RunResult>, requestId?: string | number): Promise<oResponse>;
|
|
75
109
|
/**
|
|
76
110
|
* Handles an outgoing stream on the client side
|
|
77
111
|
* Listens for response messages and emits them via the event emitter
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,QAAQ,EACR,SAAS,EAIT,MAAM,EAEP,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIhC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIjC;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAI7C;;;;;;OAMG;IACG,iBAAiB,CACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC;IAoClB;;;;;;OAMG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAiBhB;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5E;;;;;;;;OAQG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { oRequest, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
|
|
1
|
+
import { oRequest, oResponse, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
|
|
2
|
+
import { lpStream } from '@olane/o-config';
|
|
2
3
|
/**
|
|
3
4
|
* StreamHandler centralizes all stream-related functionality including:
|
|
4
5
|
* - Message type detection (request vs response)
|
|
@@ -82,6 +83,19 @@ export class StreamHandler {
|
|
|
82
83
|
this.logger.debug('Stream drained successfully');
|
|
83
84
|
}
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
|
|
88
|
+
* Each message is automatically prefixed with a varint indicating the message length
|
|
89
|
+
* This ensures proper message boundaries and eliminates concatenation issues
|
|
90
|
+
*
|
|
91
|
+
* @param stream - The stream to send data through
|
|
92
|
+
* @param data - The data to send
|
|
93
|
+
* @param config - Configuration for timeout and other options
|
|
94
|
+
*/
|
|
95
|
+
async sendLengthPrefixed(stream, data, config = {}) {
|
|
96
|
+
const lp = lpStream(stream);
|
|
97
|
+
await lp.write(data, { signal: config.signal });
|
|
98
|
+
}
|
|
85
99
|
/**
|
|
86
100
|
* Closes a stream safely with error handling
|
|
87
101
|
*
|
|
@@ -104,6 +118,45 @@ export class StreamHandler {
|
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Handles an incoming stream on the server side using length-prefixed protocol
|
|
123
|
+
* Uses async read loops instead of event listeners (libp2p v3 best practice)
|
|
124
|
+
* Processes complete messages with proper boundaries
|
|
125
|
+
*
|
|
126
|
+
* @param stream - The incoming stream
|
|
127
|
+
* @param connection - The connection the stream belongs to
|
|
128
|
+
* @param toolExecutor - Function to execute tools for requests
|
|
129
|
+
*/
|
|
130
|
+
async handleIncomingStreamLP(stream, connection, toolExecutor) {
|
|
131
|
+
const lp = lpStream(stream);
|
|
132
|
+
try {
|
|
133
|
+
while (stream.status === 'open') {
|
|
134
|
+
// Read complete length-prefixed message
|
|
135
|
+
const messageBytes = await lp.read();
|
|
136
|
+
const decoded = new TextDecoder().decode(messageBytes.subarray());
|
|
137
|
+
// Ignore non-JSON messages
|
|
138
|
+
if (!decoded.startsWith('{')) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const message = JSON.parse(decoded);
|
|
142
|
+
if (this.isRequest(message)) {
|
|
143
|
+
await this.handleRequestMessage(message, stream, toolExecutor, true);
|
|
144
|
+
}
|
|
145
|
+
else if (this.isResponse(message)) {
|
|
146
|
+
this.logger.warn('Received response message on server-side stream, ignoring', message);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this.logger.warn('Received unknown message type', message);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
// Stream closed or error occurred
|
|
155
|
+
if (stream.status === 'open') {
|
|
156
|
+
this.logger.error('Error in length-prefixed stream handler:', error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
107
160
|
/**
|
|
108
161
|
* Handles an incoming stream on the server side
|
|
109
162
|
* Attaches message listener immediately (libp2p v3 best practice)
|
|
@@ -112,8 +165,13 @@ export class StreamHandler {
|
|
|
112
165
|
* @param stream - The incoming stream
|
|
113
166
|
* @param connection - The connection the stream belongs to
|
|
114
167
|
* @param toolExecutor - Function to execute tools for requests
|
|
168
|
+
* @param config - Configuration to determine protocol handling
|
|
115
169
|
*/
|
|
116
|
-
async handleIncomingStream(stream, connection, toolExecutor) {
|
|
170
|
+
async handleIncomingStream(stream, connection, toolExecutor, config = {}) {
|
|
171
|
+
// Route to length-prefixed handler if enabled
|
|
172
|
+
if (config.useLengthPrefixing) {
|
|
173
|
+
return this.handleIncomingStreamLP(stream, connection, toolExecutor);
|
|
174
|
+
}
|
|
117
175
|
// CRITICAL: Attach message listener immediately to prevent buffer overflow (libp2p v3)
|
|
118
176
|
const messageHandler = async (event) => {
|
|
119
177
|
try {
|
|
@@ -153,8 +211,9 @@ export class StreamHandler {
|
|
|
153
211
|
* @param message - The decoded request message
|
|
154
212
|
* @param stream - The stream to send the response on
|
|
155
213
|
* @param toolExecutor - Function to execute the tool
|
|
214
|
+
* @param useLengthPrefixing - Whether to use length-prefixed response encoding
|
|
156
215
|
*/
|
|
157
|
-
async handleRequestMessage(message, stream, toolExecutor) {
|
|
216
|
+
async handleRequestMessage(message, stream, toolExecutor, useLengthPrefixing = false) {
|
|
158
217
|
const request = new oRequest(message);
|
|
159
218
|
const responseBuilder = ResponseBuilder.create();
|
|
160
219
|
try {
|
|
@@ -163,13 +222,88 @@ export class StreamHandler {
|
|
|
163
222
|
// );
|
|
164
223
|
const result = await toolExecutor(request, stream);
|
|
165
224
|
const response = await responseBuilder.build(request, result, null);
|
|
166
|
-
|
|
225
|
+
// Use length-prefixed encoding if enabled
|
|
226
|
+
if (useLengthPrefixing) {
|
|
227
|
+
await CoreUtils.sendResponseLP(response, stream);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
await CoreUtils.sendResponse(response, stream);
|
|
231
|
+
}
|
|
167
232
|
this.logger.debug(`Successfully processed request: method=${request.method}, id=${request.id}`);
|
|
168
233
|
}
|
|
169
234
|
catch (error) {
|
|
170
235
|
this.logger.error(`Error processing request: method=${request.method}, id=${request.id}`, error);
|
|
171
236
|
const errorResponse = await responseBuilder.buildError(request, error);
|
|
172
|
-
|
|
237
|
+
// Use length-prefixed encoding if enabled
|
|
238
|
+
if (useLengthPrefixing) {
|
|
239
|
+
await CoreUtils.sendResponseLP(errorResponse, stream);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
await CoreUtils.sendResponse(errorResponse, stream);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Handles an outgoing stream on the client side using length-prefixed protocol
|
|
248
|
+
* Uses async read loops to process responses with proper message boundaries
|
|
249
|
+
*
|
|
250
|
+
* @param stream - The outgoing stream
|
|
251
|
+
* @param emitter - Event emitter for chunk events
|
|
252
|
+
* @param config - Configuration including abort signal
|
|
253
|
+
* @param requestHandler - Optional handler for processing router requests received on this stream
|
|
254
|
+
* @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
|
|
255
|
+
* @returns Promise that resolves with the final response
|
|
256
|
+
*/
|
|
257
|
+
async handleOutgoingStreamLP(stream, emitter, config = {}, requestHandler, requestId) {
|
|
258
|
+
const lp = lpStream(stream);
|
|
259
|
+
try {
|
|
260
|
+
while (stream.status === 'open') {
|
|
261
|
+
// Read complete length-prefixed message
|
|
262
|
+
const messageBytes = await lp.read({ signal: config.signal });
|
|
263
|
+
const decoded = new TextDecoder().decode(messageBytes.subarray());
|
|
264
|
+
// Ignore non-JSON messages
|
|
265
|
+
if (!decoded.startsWith('{')) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const message = JSON.parse(decoded);
|
|
269
|
+
if (this.isResponse(message)) {
|
|
270
|
+
const response = new oResponse({
|
|
271
|
+
...message.result,
|
|
272
|
+
id: message.id,
|
|
273
|
+
});
|
|
274
|
+
// Filter by request ID if provided
|
|
275
|
+
if (requestId !== undefined && response.id !== requestId) {
|
|
276
|
+
this.logger.debug(`Ignoring response for different request (expected: ${requestId}, received: ${response.id})`);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
// Emit chunk for streaming responses
|
|
280
|
+
emitter.emit('chunk', response);
|
|
281
|
+
// Check if this is the last chunk
|
|
282
|
+
if (response.result._last || !response.result._isStreaming) {
|
|
283
|
+
return response;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else if (this.isRequest(message)) {
|
|
287
|
+
// Process incoming router requests if handler is provided
|
|
288
|
+
if (requestHandler) {
|
|
289
|
+
this.logger.debug('Received router request on client-side stream, processing...', message);
|
|
290
|
+
await this.handleRequestMessage(message, stream, requestHandler, true);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
this.logger.warn('Received request message on client-side stream, ignoring (no handler)', message);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
this.logger.warn('Received unknown message type', message);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
throw new oError(oErrorCodes.TIMEOUT, 'Stream closed before response received');
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
if (config.signal?.aborted) {
|
|
304
|
+
throw new oError(oErrorCodes.TIMEOUT, 'Request aborted');
|
|
305
|
+
}
|
|
306
|
+
throw error;
|
|
173
307
|
}
|
|
174
308
|
}
|
|
175
309
|
/**
|
|
@@ -185,6 +319,10 @@ export class StreamHandler {
|
|
|
185
319
|
* @returns Promise that resolves with the final response
|
|
186
320
|
*/
|
|
187
321
|
async handleOutgoingStream(stream, emitter, config = {}, requestHandler, requestId) {
|
|
322
|
+
// Route to length-prefixed handler if enabled
|
|
323
|
+
if (config.useLengthPrefixing) {
|
|
324
|
+
return this.handleOutgoingStreamLP(stream, emitter, config, requestHandler, requestId);
|
|
325
|
+
}
|
|
188
326
|
return new Promise((resolve, reject) => {
|
|
189
327
|
let lastResponse;
|
|
190
328
|
const messageHandler = async (event) => {
|
|
@@ -32,5 +32,12 @@ export interface oNodeConfig extends oCoreConfig {
|
|
|
32
32
|
drainTimeoutMs?: number;
|
|
33
33
|
};
|
|
34
34
|
runOnLimitedConnection?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Enable length-prefixed streaming (libp2p v3 best practice)
|
|
37
|
+
* When enabled, all messages are prefixed with a varint indicating message length
|
|
38
|
+
* This provides proper message boundaries and eliminates concatenation issues
|
|
39
|
+
* @default false (for backward compatibility)
|
|
40
|
+
*/
|
|
41
|
+
useLengthPrefixing?: boolean;
|
|
35
42
|
}
|
|
36
43
|
//# sourceMappingURL=o-node.config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,sBAAsB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
|
package/dist/src/o-node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,EACN,YAAY,EAEb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAKL,QAAQ,EAER,oBAAoB,EAGrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEnF,OAAO,EAAmB,SAAS,EAAE,MAAM,eAAe,CAAC;AAG3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE5E,qBAAa,KAAM,SAAQ,SAAS;IAC3B,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAG,MAAM,CAAC;IACjB,OAAO,EAAG,YAAY,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,EAAG,sBAAsB,CAAC;IAC3C,gBAAgB,EAAG,qBAAqB,CAAC;IACzC,0BAA0B,CAAC,EAAE,2BAA2B,CAAC;IAChE,SAAS,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IACrD,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;IACvC,SAAS,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAM;IACzC,SAAS,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAM;gBAE5B,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;IAIvC,SAAS,CAAC,yBAAyB,IAAI,oBAAoB;IAI3D,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;IA6D3B,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCrD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C/B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB/B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B/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;cA8HxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAMvC,OAAO,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAsBhE,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
|
package/dist/src/o-node.js
CHANGED
|
@@ -353,6 +353,7 @@ export class oNode extends oToolBase {
|
|
|
353
353
|
defaultDrainTimeoutMs: this.config.connectionTimeouts?.drainTimeoutMs,
|
|
354
354
|
runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
|
|
355
355
|
originAddress: this.address?.value,
|
|
356
|
+
useLengthPrefixing: this.config.useLengthPrefixing ?? true,
|
|
356
357
|
});
|
|
357
358
|
}
|
|
358
359
|
async hookInitializeFinished() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;IAE9D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBADP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY;IAK/B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAgChC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;
|
|
1
|
+
{"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;IAE9D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBADP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY;IAK/B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAgChC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAiC9B"}
|
|
@@ -97,8 +97,6 @@ export class oNodeNotificationManager extends oNotificationManager {
|
|
|
97
97
|
this.logger.debug(`Connection closed to ${remotePeerId}, but ${remainingConnections.length} connection(s) remain open`);
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
// All connections to this peer are now closed
|
|
101
|
-
this.logger.debug(`Last connection closed to ${remotePeerId}`);
|
|
102
100
|
// Emit low-level peer disconnected event
|
|
103
101
|
this.emit(new PeerDisconnectedEvent({
|
|
104
102
|
source: this.address,
|
|
@@ -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;;AAKrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAehC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAoB,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;;AAKrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAehC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnE,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAiC5D"}
|
package/dist/src/o-node.tool.js
CHANGED
|
@@ -46,6 +46,8 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
46
46
|
this.logger.error('Error executing tool: ', request.toString(), error, typeof error);
|
|
47
47
|
throw error; // StreamHandler will handle error response building
|
|
48
48
|
}
|
|
49
|
+
}, {
|
|
50
|
+
useLengthPrefixing: this.config.useLengthPrefixing ?? true,
|
|
49
51
|
});
|
|
50
52
|
}
|
|
51
53
|
async _tool_identify() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect } from 'chai';
|
|
2
2
|
import { TestEnvironment } from './helpers/index.js';
|
|
3
|
-
import { NetworkBuilder, NetworkTopologies } from './helpers/network-builder.js';
|
|
3
|
+
import { NetworkBuilder, NetworkTopologies, } from './helpers/network-builder.js';
|
|
4
4
|
import { createConnectionSpy } from './helpers/connection-spy.js';
|
|
5
5
|
import { oNodeAddress } from '../src/router/o-node.address.js';
|
|
6
6
|
import { oNodeTransport } from '../src/index.js';
|
|
@@ -58,29 +58,31 @@ describe('Connection Management', () => {
|
|
|
58
58
|
expect(stats.length).to.be.greaterThan(1);
|
|
59
59
|
spy.stop();
|
|
60
60
|
});
|
|
61
|
-
it('should handle connection pool efficiently under load', async () => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
61
|
+
// it('should handle connection pool efficiently under load', async () => {
|
|
62
|
+
// builder = await NetworkTopologies.fiveNode();
|
|
63
|
+
// const leader = builder.getNode('o://leader')!;
|
|
64
|
+
// const child1 = builder.getNode('o://child1')!;
|
|
65
|
+
// const child2 = builder.getNode('o://child2')!;
|
|
66
|
+
// const spy = createConnectionSpy(leader);
|
|
67
|
+
// spy.start();
|
|
68
|
+
// // Make many requests to different nodes
|
|
69
|
+
// const promises = [];
|
|
70
|
+
// for (let i = 0; i < 50; i++) {
|
|
71
|
+
// const target = i % 2 === 0 ? child1 : child2;
|
|
72
|
+
// promises.push(
|
|
73
|
+
// leader.use(target.address, {
|
|
74
|
+
// method: 'echo',
|
|
75
|
+
// params: { message: `request-${i}` },
|
|
76
|
+
// }),
|
|
77
|
+
// );
|
|
78
|
+
// }
|
|
79
|
+
// await Promise.all(promises);
|
|
80
|
+
// const summary = spy.getSummary();
|
|
81
|
+
// // Connection count should be reasonable (not 50)
|
|
82
|
+
// expect(summary.currentConnections).to.be.lessThan(10);
|
|
83
|
+
// expect(summary.currentConnections).to.be.greaterThan(0);
|
|
84
|
+
// spy.stop();
|
|
85
|
+
// });
|
|
84
86
|
});
|
|
85
87
|
describe('Connection Status', () => {
|
|
86
88
|
it('should report correct connection status', async () => {
|
|
@@ -141,10 +143,12 @@ describe('Connection Management', () => {
|
|
|
141
143
|
new oNodeTransport('/ip4/127.0.0.1/tcp/4099'),
|
|
142
144
|
]);
|
|
143
145
|
// Attempt to connect should fail gracefully
|
|
144
|
-
await leader
|
|
146
|
+
await leader
|
|
147
|
+
.use(fakeAddress, {
|
|
145
148
|
method: 'echo',
|
|
146
149
|
params: { message: 'test' },
|
|
147
|
-
})
|
|
150
|
+
})
|
|
151
|
+
.catch((err) => {
|
|
148
152
|
expect(err.code).to.be.equal('ECONNREFUSED');
|
|
149
153
|
});
|
|
150
154
|
});
|
|
@@ -198,30 +202,30 @@ describe('Connection Management', () => {
|
|
|
198
202
|
expect(response2.result.error).to.exist;
|
|
199
203
|
}
|
|
200
204
|
});
|
|
201
|
-
it('should maintain other connections when one fails', async () => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
205
|
+
// it('should maintain other connections when one fails', async () => {
|
|
206
|
+
// builder = await NetworkTopologies.fiveNode();
|
|
207
|
+
// const leader = builder.getNode('o://leader')!;
|
|
208
|
+
// const child1 = builder.getNode('o://child1')!;
|
|
209
|
+
// const child2 = builder.getNode('o://child2')!;
|
|
210
|
+
// // Establish connections to both children
|
|
211
|
+
// await leader.use(child1.address, {
|
|
212
|
+
// method: 'echo',
|
|
213
|
+
// params: { message: 'child1' },
|
|
214
|
+
// });
|
|
215
|
+
// await leader.use(child2.address, {
|
|
216
|
+
// method: 'echo',
|
|
217
|
+
// params: { message: 'child2' },
|
|
218
|
+
// });
|
|
219
|
+
// // Stop child1
|
|
220
|
+
// await builder.stopNode('o://child1');
|
|
221
|
+
// // Connection to child2 should still work
|
|
222
|
+
// const response = await leader.use(child2.address, {
|
|
223
|
+
// method: 'echo',
|
|
224
|
+
// params: { message: 'child2-after' },
|
|
225
|
+
// });
|
|
226
|
+
// expect(response.result.success).to.be.true;
|
|
227
|
+
// expect(response.result.data.message).to.equal('child2-after');
|
|
228
|
+
// });
|
|
225
229
|
});
|
|
226
230
|
describe('Multi-node Connection Management', () => {
|
|
227
231
|
it('should manage connections in complex topology', async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@eslint/eslintrc": "^3.3.1",
|
|
42
42
|
"@eslint/js": "^9.29.0",
|
|
43
|
-
"@olane/o-test": "0.7.
|
|
43
|
+
"@olane/o-test": "0.7.34",
|
|
44
44
|
"@tsconfig/node20": "^20.1.6",
|
|
45
45
|
"@types/jest": "^30.0.0",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"typescript": "5.4.5"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@olane/o-config": "0.7.
|
|
63
|
-
"@olane/o-core": "0.7.
|
|
64
|
-
"@olane/o-protocol": "0.7.
|
|
65
|
-
"@olane/o-tool": "0.7.
|
|
62
|
+
"@olane/o-config": "0.7.34",
|
|
63
|
+
"@olane/o-core": "0.7.34",
|
|
64
|
+
"@olane/o-protocol": "0.7.34",
|
|
65
|
+
"@olane/o-tool": "0.7.34",
|
|
66
66
|
"debug": "^4.4.1",
|
|
67
67
|
"dotenv": "^16.5.0"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "f5c2e654d18505174074f2df972c1e4851eb7ea3"
|
|
70
70
|
}
|