@olane/o-node 0.7.53 → 0.7.54
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/stream-init-message.d.ts +39 -4
- package/dist/src/connection/interfaces/stream-init-message.d.ts.map +1 -1
- package/dist/src/connection/interfaces/stream-init-message.js +11 -1
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +21 -2
- package/dist/src/connection/o-node-stream.manager.d.ts +24 -5
- package/dist/src/connection/o-node-stream.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-stream.manager.js +119 -12
- package/dist/src/connection/stream-manager.events.d.ts +6 -1
- package/dist/src/connection/stream-manager.events.d.ts.map +1 -1
- package/dist/src/connection/stream-manager.events.js +1 -0
- package/dist/src/o-node.tool.js +1 -1
- package/package.json +7 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Message sent by limited connection clients to identify their dedicated
|
|
3
|
-
* This allows the receiver to identify which
|
|
2
|
+
* Message sent by limited connection clients to identify their dedicated persistent streams
|
|
3
|
+
* This allows the receiver to identify which streams to use for bidirectional communication
|
|
4
4
|
*/
|
|
5
5
|
export interface StreamInitMessage {
|
|
6
6
|
/**
|
|
@@ -9,10 +9,11 @@ export interface StreamInitMessage {
|
|
|
9
9
|
type: 'stream-init';
|
|
10
10
|
/**
|
|
11
11
|
* Role of this stream
|
|
12
|
-
* - 'reader': Dedicated reader stream for receiving requests
|
|
12
|
+
* - 'reader': Dedicated reader stream for receiving requests from receiver
|
|
13
|
+
* - 'writer': Dedicated writer stream for sending responses back to receiver
|
|
13
14
|
* - 'standard': Standard request-response stream
|
|
14
15
|
*/
|
|
15
|
-
role: 'reader' | 'standard';
|
|
16
|
+
role: 'reader' | 'writer' | 'standard';
|
|
16
17
|
/**
|
|
17
18
|
* Timestamp when the stream was created
|
|
18
19
|
*/
|
|
@@ -26,4 +27,38 @@ export interface StreamInitMessage {
|
|
|
26
27
|
* Type guard to check if a message is a StreamInitMessage
|
|
27
28
|
*/
|
|
28
29
|
export declare function isStreamInitMessage(message: any): message is StreamInitMessage;
|
|
30
|
+
/**
|
|
31
|
+
* Acknowledgment message sent by receiver in response to stream-init
|
|
32
|
+
* This confirms that the receiver has processed and registered the stream
|
|
33
|
+
*/
|
|
34
|
+
export interface StreamInitAckMessage {
|
|
35
|
+
/**
|
|
36
|
+
* Message type identifier
|
|
37
|
+
*/
|
|
38
|
+
type: 'stream-init-ack';
|
|
39
|
+
/**
|
|
40
|
+
* Status of the initialization
|
|
41
|
+
*/
|
|
42
|
+
status: 'success' | 'error';
|
|
43
|
+
/**
|
|
44
|
+
* The stream ID that was registered
|
|
45
|
+
*/
|
|
46
|
+
streamId: string;
|
|
47
|
+
/**
|
|
48
|
+
* The role that was registered
|
|
49
|
+
*/
|
|
50
|
+
role: 'reader' | 'writer' | 'standard';
|
|
51
|
+
/**
|
|
52
|
+
* Optional error message if status is 'error'
|
|
53
|
+
*/
|
|
54
|
+
error?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Timestamp when the ack was sent
|
|
57
|
+
*/
|
|
58
|
+
timestamp: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Type guard to check if a message is a StreamInitAckMessage
|
|
62
|
+
*/
|
|
63
|
+
export declare function isStreamInitAckMessage(message: any): message is StreamInitAckMessage;
|
|
29
64
|
//# sourceMappingURL=stream-init-message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-init-message.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/stream-init-message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IAEpB
|
|
1
|
+
{"version":3,"file":"stream-init-message.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/stream-init-message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IAEpB;;;;;OAKG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEvC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,iBAAiB,CAM9E;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,EAAE,iBAAiB,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEvC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,GAAG,GACX,OAAO,IAAI,oBAAoB,CAQjC"}
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export function isStreamInitMessage(message) {
|
|
5
5
|
return (message?.type === 'stream-init' &&
|
|
6
|
-
(message.role === 'reader' || message.role === 'standard') &&
|
|
6
|
+
(message.role === 'reader' || message.role === 'writer' || message.role === 'standard') &&
|
|
7
|
+
typeof message.timestamp === 'number');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Type guard to check if a message is a StreamInitAckMessage
|
|
11
|
+
*/
|
|
12
|
+
export function isStreamInitAckMessage(message) {
|
|
13
|
+
return (message?.type === 'stream-init-ack' &&
|
|
14
|
+
(message.status === 'success' || message.status === 'error') &&
|
|
15
|
+
typeof message.streamId === 'string' &&
|
|
16
|
+
(message.role === 'reader' || message.role === 'writer' || message.role === 'standard') &&
|
|
7
17
|
typeof message.timestamp === 'number');
|
|
8
18
|
}
|
|
@@ -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,EAAU,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,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,qBAAa,eAAgB,SAAQ,WAAW;IAKlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAJrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,kBAAkB,CAAC;gBAEV,MAAM,EAAE,qBAAqB;IAW5D,IAAI,YAAY,qCAEf;IAED,IAAI,UAAU,wCAEb;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,qBAAqB,CAE5C;IAED,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAM/C,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAEK,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAU,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,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,qBAAa,eAAgB,SAAQ,WAAW;IAKlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAJrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,kBAAkB,CAAC;gBAEV,MAAM,EAAE,qBAAqB;IAW5D,IAAI,YAAY,qCAEf;IAED,IAAI,UAAU,wCAEb;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,qBAAqB,CAE5C;IAED,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAM/C,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAEK,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAkF/C,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CASZ"}
|
|
@@ -36,6 +36,7 @@ export class oNodeConnection extends oConnection {
|
|
|
36
36
|
// Build protocol string
|
|
37
37
|
const protocol = this.nextHopAddress.protocol +
|
|
38
38
|
(this.reusePolicy === 'reuse' ? '/reuse' : '');
|
|
39
|
+
this.logger.debug('Transmitting request on limited connection?', this.config.runOnLimitedConnection);
|
|
39
40
|
const streamConfig = {
|
|
40
41
|
signal: this.abortSignal,
|
|
41
42
|
drainTimeoutMs: this.config.drainTimeoutMs,
|
|
@@ -43,7 +44,7 @@ export class oNodeConnection extends oConnection {
|
|
|
43
44
|
maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
|
|
44
45
|
? parseInt(process.env.MAX_OUTBOUND_STREAMS)
|
|
45
46
|
: 1000,
|
|
46
|
-
runOnLimitedConnection: this.config.runOnLimitedConnection ??
|
|
47
|
+
runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
|
|
47
48
|
};
|
|
48
49
|
// Get stream from StreamManager
|
|
49
50
|
const wrappedStream = await this.streamManager.getOrCreateStream(protocol, this.nextHopAddress, streamConfig);
|
|
@@ -53,9 +54,27 @@ export class oNodeConnection extends oConnection {
|
|
|
53
54
|
// Send the request with backpressure handling
|
|
54
55
|
const data = new TextEncoder().encode(request.toString());
|
|
55
56
|
await this.streamManager.sendLengthPrefixed(stream, data, streamConfig);
|
|
57
|
+
// Determine which stream to wait for response on
|
|
58
|
+
// If _streamId is specified, use that stream (for limited connections with persistent writer stream)
|
|
59
|
+
let responseStream = stream;
|
|
60
|
+
if (request.params._streamId) {
|
|
61
|
+
const specifiedStream = this.streamManager.getStreamById(request.params._streamId);
|
|
62
|
+
if (specifiedStream) {
|
|
63
|
+
responseStream = specifiedStream;
|
|
64
|
+
this.logger.debug('Using specified stream for response', {
|
|
65
|
+
requestStreamId: stream.id,
|
|
66
|
+
responseStreamId: specifiedStream.id,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.logger.warn('Specified response stream not found, using request stream', {
|
|
71
|
+
streamId: request.params._streamId,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
56
75
|
// Handle response using StreamManager
|
|
57
76
|
// Pass request ID to enable proper response correlation on shared streams
|
|
58
|
-
const response = await this.streamManager.handleOutgoingStream(
|
|
77
|
+
const response = await this.streamManager.handleOutgoingStream(responseStream, this.emitter, streamConfig, request.id);
|
|
59
78
|
// Handle cleanup of the stream
|
|
60
79
|
await this.postTransmit(wrappedStream);
|
|
61
80
|
return response;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import type { Connection, Stream } from '@libp2p/interface';
|
|
4
|
-
import { oObject, oResponse } from '@olane/o-core';
|
|
4
|
+
import { oObject, oRequest, oResponse } from '@olane/o-core';
|
|
5
5
|
import type { oRouterRequest, oConnection } from '@olane/o-core';
|
|
6
6
|
import { oNodeStream } from './o-node-stream.js';
|
|
7
7
|
import { StreamManagerConfig } from './interfaces/stream-manager.config.js';
|
|
@@ -21,10 +21,11 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
21
21
|
readonly config: StreamManagerConfig;
|
|
22
22
|
private streams;
|
|
23
23
|
protected eventEmitter: EventEmitter;
|
|
24
|
-
|
|
24
|
+
isInitialized: boolean;
|
|
25
25
|
private p2pConnection;
|
|
26
26
|
private activeStreamHandlers;
|
|
27
27
|
protected callerReaderStream?: Stream;
|
|
28
|
+
protected callerWriterStream?: Stream;
|
|
28
29
|
constructor(config: StreamManagerConfig);
|
|
29
30
|
/**
|
|
30
31
|
* Initialize the stream manager
|
|
@@ -65,6 +66,14 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
65
66
|
* @returns Array of wrapped streams
|
|
66
67
|
*/
|
|
67
68
|
getAllStreams(): oNodeStream[];
|
|
69
|
+
/**
|
|
70
|
+
* Gets a stream by its ID
|
|
71
|
+
* Checks persistent caller streams (reader/writer) and tracked streams
|
|
72
|
+
*
|
|
73
|
+
* @param streamId - The ID of the stream to retrieve
|
|
74
|
+
* @returns The libp2p Stream or undefined if not found
|
|
75
|
+
*/
|
|
76
|
+
getStreamById(streamId: string): Stream | undefined;
|
|
68
77
|
/**
|
|
69
78
|
* Emits an async event and waits for the first listener to return a result
|
|
70
79
|
* This enables event-based request handling with async responses
|
|
@@ -88,11 +97,12 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
88
97
|
/**
|
|
89
98
|
* Handles a stream initialization message
|
|
90
99
|
* Stores reference to caller's reader stream for bidirectional communication
|
|
100
|
+
* Sends acknowledgment back to confirm stream registration
|
|
91
101
|
*
|
|
92
102
|
* @param message - The decoded stream init message
|
|
93
103
|
* @param stream - The stream that sent the message
|
|
94
104
|
*/
|
|
95
|
-
protected handleStreamInitMessage(message: StreamInitMessage, stream: Stream): void
|
|
105
|
+
protected handleStreamInitMessage(message: StreamInitMessage, stream: Stream): Promise<void>;
|
|
96
106
|
/**
|
|
97
107
|
* Extracts and parses JSON from various formats including:
|
|
98
108
|
* - Already parsed objects
|
|
@@ -105,7 +115,7 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
105
115
|
* @returns Parsed JSON object
|
|
106
116
|
* @throws Error if JSON parsing fails even with JSON5 fallback
|
|
107
117
|
*/
|
|
108
|
-
|
|
118
|
+
protected extractAndParseJSON(decoded: string | any): any;
|
|
109
119
|
/**
|
|
110
120
|
* Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
|
|
111
121
|
* Each message is automatically prefixed with a varint indicating the message length
|
|
@@ -133,6 +143,15 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
133
143
|
* @param connection - The connection the stream belongs to
|
|
134
144
|
*/
|
|
135
145
|
handleIncomingStream(stream: Stream, connection: Connection): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Determines which stream to use for sending the response
|
|
148
|
+
* Checks for _streamId in request params and routes accordingly
|
|
149
|
+
*
|
|
150
|
+
* @param request - The incoming request
|
|
151
|
+
* @param defaultStream - The stream the request came on (fallback)
|
|
152
|
+
* @returns The stream to use for the response
|
|
153
|
+
*/
|
|
154
|
+
protected getResponseStream(request: oRequest, defaultStream: Stream): Stream;
|
|
136
155
|
/**
|
|
137
156
|
* Handles a request message by emitting an event and sending response
|
|
138
157
|
*
|
|
@@ -140,7 +159,7 @@ export declare class oNodeStreamManager extends oObject {
|
|
|
140
159
|
* @param stream - The stream to send the response on
|
|
141
160
|
* @param connection - The connection the stream belongs to
|
|
142
161
|
*/
|
|
143
|
-
|
|
162
|
+
protected handleRequestMessage(message: any, stream: Stream, connection: Connection): Promise<void>;
|
|
144
163
|
/**
|
|
145
164
|
* Handles an outgoing stream on the client side using length-prefixed protocol
|
|
146
165
|
* Uses async read loops to process responses with proper message boundaries
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-stream.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-stream.manager.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,OAAO,
|
|
1
|
+
{"version":3,"file":"o-node-stream.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-stream.manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -100,7 +100,7 @@ export class oNodeStreamManager extends oObject {
|
|
|
100
100
|
const stream = await this.p2pConnection.newStream(protocol, {
|
|
101
101
|
signal: config.signal,
|
|
102
102
|
maxOutboundStreams: config.maxOutboundStreams ?? 1000,
|
|
103
|
-
runOnLimitedConnection: config.runOnLimitedConnection ??
|
|
103
|
+
runOnLimitedConnection: config.runOnLimitedConnection ?? true,
|
|
104
104
|
});
|
|
105
105
|
// Wrap in oNodeStream with metadata
|
|
106
106
|
const wrappedStream = new oNodeStream(stream, {
|
|
@@ -157,6 +157,26 @@ export class oNodeStreamManager extends oObject {
|
|
|
157
157
|
getAllStreams() {
|
|
158
158
|
return Array.from(this.streams.values());
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Gets a stream by its ID
|
|
162
|
+
* Checks persistent caller streams (reader/writer) and tracked streams
|
|
163
|
+
*
|
|
164
|
+
* @param streamId - The ID of the stream to retrieve
|
|
165
|
+
* @returns The libp2p Stream or undefined if not found
|
|
166
|
+
*/
|
|
167
|
+
getStreamById(streamId) {
|
|
168
|
+
// Check caller writer stream
|
|
169
|
+
if (this.callerWriterStream?.id === streamId) {
|
|
170
|
+
return this.callerWriterStream;
|
|
171
|
+
}
|
|
172
|
+
// Check caller reader stream
|
|
173
|
+
if (this.callerReaderStream?.id === streamId) {
|
|
174
|
+
return this.callerReaderStream;
|
|
175
|
+
}
|
|
176
|
+
// Check tracked streams
|
|
177
|
+
const wrappedStream = this.streams.get(streamId);
|
|
178
|
+
return wrappedStream?.p2pStream;
|
|
179
|
+
}
|
|
160
180
|
/**
|
|
161
181
|
* Emits an async event and waits for the first listener to return a result
|
|
162
182
|
* This enables event-based request handling with async responses
|
|
@@ -194,23 +214,72 @@ export class oNodeStreamManager extends oObject {
|
|
|
194
214
|
/**
|
|
195
215
|
* Handles a stream initialization message
|
|
196
216
|
* Stores reference to caller's reader stream for bidirectional communication
|
|
217
|
+
* Sends acknowledgment back to confirm stream registration
|
|
197
218
|
*
|
|
198
219
|
* @param message - The decoded stream init message
|
|
199
220
|
* @param stream - The stream that sent the message
|
|
200
221
|
*/
|
|
201
|
-
handleStreamInitMessage(message, stream) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
222
|
+
async handleStreamInitMessage(message, stream) {
|
|
223
|
+
try {
|
|
224
|
+
if (message.role === 'reader') {
|
|
225
|
+
this.callerReaderStream = stream;
|
|
226
|
+
this.logger.info('Identified caller reader stream', {
|
|
227
|
+
streamId: stream.id,
|
|
228
|
+
connectionId: message.connectionId,
|
|
229
|
+
});
|
|
230
|
+
this.emit(StreamManagerEvent.StreamIdentified, {
|
|
231
|
+
streamId: stream.id,
|
|
232
|
+
role: message.role,
|
|
233
|
+
connectionId: message.connectionId,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else if (message.role === 'writer') {
|
|
237
|
+
this.callerWriterStream = stream;
|
|
238
|
+
this.logger.info('Identified caller writer stream', {
|
|
239
|
+
streamId: stream.id,
|
|
240
|
+
connectionId: message.connectionId,
|
|
241
|
+
});
|
|
242
|
+
this.emit(StreamManagerEvent.StreamIdentified, {
|
|
243
|
+
streamId: stream.id,
|
|
244
|
+
role: message.role,
|
|
245
|
+
connectionId: message.connectionId,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
// Send acknowledgment back to caller
|
|
249
|
+
const ackMessage = {
|
|
250
|
+
type: 'stream-init-ack',
|
|
251
|
+
status: 'success',
|
|
205
252
|
streamId: stream.id,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
253
|
+
role: message.role,
|
|
254
|
+
timestamp: Date.now(),
|
|
255
|
+
};
|
|
256
|
+
const ackBytes = new TextEncoder().encode(JSON.stringify(ackMessage));
|
|
257
|
+
await this.sendLengthPrefixed(stream, ackBytes, {});
|
|
258
|
+
this.logger.debug('Sent stream-init-ack', {
|
|
209
259
|
streamId: stream.id,
|
|
210
260
|
role: message.role,
|
|
211
|
-
connectionId: message.connectionId,
|
|
212
261
|
});
|
|
213
262
|
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
this.logger.error('Failed to process stream-init message', error);
|
|
265
|
+
// Try to send error acknowledgment
|
|
266
|
+
try {
|
|
267
|
+
const errorAck = {
|
|
268
|
+
type: 'stream-init-ack',
|
|
269
|
+
status: 'error',
|
|
270
|
+
streamId: stream.id,
|
|
271
|
+
role: message.role,
|
|
272
|
+
error: error.message,
|
|
273
|
+
timestamp: Date.now(),
|
|
274
|
+
};
|
|
275
|
+
const errorAckBytes = new TextEncoder().encode(JSON.stringify(errorAck));
|
|
276
|
+
await this.sendLengthPrefixed(stream, errorAckBytes, {});
|
|
277
|
+
}
|
|
278
|
+
catch (ackError) {
|
|
279
|
+
this.logger.error('Failed to send error acknowledgment', ackError);
|
|
280
|
+
}
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
214
283
|
}
|
|
215
284
|
/**
|
|
216
285
|
* Extracts and parses JSON from various formats including:
|
|
@@ -301,7 +370,7 @@ export class oNodeStreamManager extends oObject {
|
|
|
301
370
|
// Parse JSON (handles markdown blocks, mixed content, and JSON5)
|
|
302
371
|
const message = this.extractAndParseJSON(decoded);
|
|
303
372
|
if (this.isStreamInit(message)) {
|
|
304
|
-
this.handleStreamInitMessage(message, stream);
|
|
373
|
+
await this.handleStreamInitMessage(message, stream);
|
|
305
374
|
// Continue reading for subsequent messages on this stream
|
|
306
375
|
}
|
|
307
376
|
else if (this.isRequest(message)) {
|
|
@@ -330,6 +399,42 @@ export class oNodeStreamManager extends oObject {
|
|
|
330
399
|
this.untrackStreamHandler(stream.id);
|
|
331
400
|
}
|
|
332
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Determines which stream to use for sending the response
|
|
404
|
+
* Checks for _streamId in request params and routes accordingly
|
|
405
|
+
*
|
|
406
|
+
* @param request - The incoming request
|
|
407
|
+
* @param defaultStream - The stream the request came on (fallback)
|
|
408
|
+
* @returns The stream to use for the response
|
|
409
|
+
*/
|
|
410
|
+
getResponseStream(request, defaultStream) {
|
|
411
|
+
const streamId = request.params._streamId;
|
|
412
|
+
// If no explicit response stream specified, use the request stream (backward compatibility)
|
|
413
|
+
if (!streamId) {
|
|
414
|
+
return defaultStream;
|
|
415
|
+
}
|
|
416
|
+
// Check if the response stream is the identified caller writer stream
|
|
417
|
+
if (this.callerWriterStream && this.callerWriterStream.id === streamId) {
|
|
418
|
+
this.logger.debug('Routing response to caller writer stream', {
|
|
419
|
+
requestId: request.id,
|
|
420
|
+
streamId,
|
|
421
|
+
});
|
|
422
|
+
return this.callerWriterStream;
|
|
423
|
+
}
|
|
424
|
+
if (this.callerReaderStream && this.callerReaderStream.id === streamId) {
|
|
425
|
+
this.logger.debug('Routing response to caller reader stream', {
|
|
426
|
+
requestId: request.id,
|
|
427
|
+
streamId,
|
|
428
|
+
});
|
|
429
|
+
return this.callerReaderStream;
|
|
430
|
+
}
|
|
431
|
+
// If specified stream not found, warn and fall back to request stream
|
|
432
|
+
this.logger.warn('Specified response stream not found, using request stream', {
|
|
433
|
+
requestId: request.id,
|
|
434
|
+
streamId,
|
|
435
|
+
});
|
|
436
|
+
return defaultStream;
|
|
437
|
+
}
|
|
333
438
|
/**
|
|
334
439
|
* Handles a request message by emitting an event and sending response
|
|
335
440
|
*
|
|
@@ -340,6 +445,8 @@ export class oNodeStreamManager extends oObject {
|
|
|
340
445
|
async handleRequestMessage(message, stream, connection) {
|
|
341
446
|
const request = new oRequest(message);
|
|
342
447
|
const responseBuilder = ResponseBuilder.create();
|
|
448
|
+
// Determine which stream to use for the response
|
|
449
|
+
const responseStream = this.getResponseStream(request, stream);
|
|
343
450
|
try {
|
|
344
451
|
// Emit InboundRequest event and wait for handler to process
|
|
345
452
|
const result = await this.emitAsync(StreamManagerEvent.InboundRequest, {
|
|
@@ -348,13 +455,13 @@ export class oNodeStreamManager extends oObject {
|
|
|
348
455
|
connection,
|
|
349
456
|
});
|
|
350
457
|
const response = await responseBuilder.build(request, result, null);
|
|
351
|
-
await CoreUtils.sendResponse(response,
|
|
458
|
+
await CoreUtils.sendResponse(response, responseStream);
|
|
352
459
|
this.logger.debug(`Successfully processed request: method=${request.method}, id=${request.id}`);
|
|
353
460
|
}
|
|
354
461
|
catch (error) {
|
|
355
462
|
this.logger.error(`Error processing request: method=${request.method}, id=${request.id}`, error);
|
|
356
463
|
const errorResponse = await responseBuilder.buildError(request, error);
|
|
357
|
-
await CoreUtils.sendResponse(errorResponse,
|
|
464
|
+
await CoreUtils.sendResponse(errorResponse, responseStream);
|
|
358
465
|
this.emit(StreamManagerEvent.StreamError, {
|
|
359
466
|
streamId: stream.id,
|
|
360
467
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
@@ -5,6 +5,7 @@ export declare enum StreamManagerEvent {
|
|
|
5
5
|
ManagerInitialized = "manager-initialized",
|
|
6
6
|
ManagerClosed = "manager-closed",
|
|
7
7
|
ReaderStarted = "reader-started",
|
|
8
|
+
WriterStarted = "writer-started",
|
|
8
9
|
ReaderFailed = "reader-failed",
|
|
9
10
|
ReaderRecovered = "reader-recovered",
|
|
10
11
|
RecoveryFailed = "recovery-failed",
|
|
@@ -23,6 +24,9 @@ export interface InitializedData {
|
|
|
23
24
|
export interface ReaderStartedData {
|
|
24
25
|
streamId: string;
|
|
25
26
|
}
|
|
27
|
+
export interface WriterStartedData {
|
|
28
|
+
streamId: string;
|
|
29
|
+
}
|
|
26
30
|
export interface ReaderFailedData {
|
|
27
31
|
error?: string;
|
|
28
32
|
failureCount: number;
|
|
@@ -46,7 +50,7 @@ export interface StreamFailedData {
|
|
|
46
50
|
}
|
|
47
51
|
export interface StreamIdentifiedData {
|
|
48
52
|
streamId: string;
|
|
49
|
-
role: 'reader' | 'standard';
|
|
53
|
+
role: 'reader' | 'writer' | 'standard';
|
|
50
54
|
connectionId?: string;
|
|
51
55
|
}
|
|
52
56
|
export interface InboundRequestData {
|
|
@@ -70,6 +74,7 @@ export type StreamManagerEventData = {
|
|
|
70
74
|
[StreamManagerEvent.ManagerInitialized]: InitializedData;
|
|
71
75
|
[StreamManagerEvent.ManagerClosed]: void;
|
|
72
76
|
[StreamManagerEvent.ReaderStarted]: ReaderStartedData;
|
|
77
|
+
[StreamManagerEvent.WriterStarted]: WriterStartedData;
|
|
73
78
|
[StreamManagerEvent.ReaderFailed]: ReaderFailedData;
|
|
74
79
|
[StreamManagerEvent.ReaderRecovered]: ReaderRecoveredData;
|
|
75
80
|
[StreamManagerEvent.RecoveryFailed]: RecoveryFailedData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-manager.events.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-manager.events.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,kBAAkB;IAC5B,kBAAkB,wBAAwB;IAC1C,aAAa,mBAAmB;IAChC,aAAa,mBAAmB;IAChC,YAAY,kBAAkB;IAC9B,eAAe,qBAAqB;IACpC,cAAc,oBAAoB;IAClC,cAAc,oBAAoB;IAClC,YAAY,kBAAkB;IAC9B,gBAAgB,sBAAsB;IACtC,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,WAAW,iBAAiB;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;CAAG;AAEnC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"stream-manager.events.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-manager.events.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,kBAAkB;IAC5B,kBAAkB,wBAAwB;IAC1C,aAAa,mBAAmB;IAChC,aAAa,mBAAmB;IAChC,aAAa,mBAAmB;IAChC,YAAY,kBAAkB;IAC9B,eAAe,qBAAqB;IACpC,cAAc,oBAAoB;IAClC,cAAc,oBAAoB;IAClC,YAAY,kBAAkB;IAC9B,gBAAgB,sBAAsB;IACtC,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,WAAW,iBAAiB;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;CAAG;AAEnC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,EAAE,eAAe,CAAC;IACzD,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;IACzC,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IACtD,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IACtD,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACpD,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAC1D,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACpD,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IAC5D,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAC1D,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;CACnD,CAAC"}
|
|
@@ -6,6 +6,7 @@ export var StreamManagerEvent;
|
|
|
6
6
|
StreamManagerEvent["ManagerInitialized"] = "manager-initialized";
|
|
7
7
|
StreamManagerEvent["ManagerClosed"] = "manager-closed";
|
|
8
8
|
StreamManagerEvent["ReaderStarted"] = "reader-started";
|
|
9
|
+
StreamManagerEvent["WriterStarted"] = "writer-started";
|
|
9
10
|
StreamManagerEvent["ReaderFailed"] = "reader-failed";
|
|
10
11
|
StreamManagerEvent["ReaderRecovered"] = "reader-recovered";
|
|
11
12
|
StreamManagerEvent["RecoveryFailed"] = "recovery-failed";
|
package/dist/src/o-node.tool.js
CHANGED
|
@@ -25,7 +25,7 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
25
25
|
await this.p2pNode.handle(reuseProtocol, this.handleStreamReuse.bind(this), {
|
|
26
26
|
maxInboundStreams: 10000,
|
|
27
27
|
maxOutboundStreams: maxOutboundsStreams,
|
|
28
|
-
runOnLimitedConnection:
|
|
28
|
+
runOnLimitedConnection: true, // reuse is always on limited connections
|
|
29
29
|
});
|
|
30
30
|
this.logger.debug('Handled protocol reuse: ' + reuseProtocol);
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.54",
|
|
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.54",
|
|
44
44
|
"@tsconfig/node20": "^20.1.6",
|
|
45
45
|
"@types/jest": "^30.0.0",
|
|
46
46
|
"@types/json5": "^2.2.0",
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
"typescript": "5.4.5"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@olane/o-config": "0.7.
|
|
64
|
-
"@olane/o-core": "0.7.
|
|
65
|
-
"@olane/o-protocol": "0.7.
|
|
66
|
-
"@olane/o-tool": "0.7.
|
|
63
|
+
"@olane/o-config": "0.7.54",
|
|
64
|
+
"@olane/o-core": "0.7.54",
|
|
65
|
+
"@olane/o-protocol": "0.7.54",
|
|
66
|
+
"@olane/o-tool": "0.7.54",
|
|
67
67
|
"debug": "^4.4.1",
|
|
68
68
|
"dotenv": "^16.5.0",
|
|
69
69
|
"json5": "^2.2.3"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "8e527a1481c6aeaf0840ea30198500a9baef1e98"
|
|
72
72
|
}
|