@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
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { TestEnvironment } from './helpers/index.js';
|
|
3
|
+
import { NetworkTopologies, } from './helpers/network-builder.js';
|
|
4
|
+
import { oNodeAddress } from '../src/router/o-node.address.js';
|
|
5
|
+
describe('Stream Reuse', () => {
|
|
6
|
+
const env = new TestEnvironment();
|
|
7
|
+
let builder;
|
|
8
|
+
afterEach(async () => {
|
|
9
|
+
if (builder) {
|
|
10
|
+
await builder.cleanup();
|
|
11
|
+
}
|
|
12
|
+
await env.cleanup();
|
|
13
|
+
});
|
|
14
|
+
describe('Stream Reuse with reusePolicy="reuse"', () => {
|
|
15
|
+
it('should reuse the same stream across multiple requests', async () => {
|
|
16
|
+
builder = await NetworkTopologies.twoNode();
|
|
17
|
+
const leader = builder.getNode('o://leader');
|
|
18
|
+
const child = builder.getNode('o://child');
|
|
19
|
+
// Track stream IDs
|
|
20
|
+
const streamIds = [];
|
|
21
|
+
// Make first request
|
|
22
|
+
const response1 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
23
|
+
method: 'echo',
|
|
24
|
+
params: { message: 'first' },
|
|
25
|
+
});
|
|
26
|
+
expect(response1.result.success).to.be.true;
|
|
27
|
+
// Get active connection to inspect streams
|
|
28
|
+
const connectionManager = leader.connectionManager;
|
|
29
|
+
const connection = connectionManager.getCachedLibp2pConnection(child.address);
|
|
30
|
+
connection.reusePolicy;
|
|
31
|
+
if (connection) {
|
|
32
|
+
// Store initial stream count and first stream ID
|
|
33
|
+
const initialStreamCount = connection.streams.length;
|
|
34
|
+
if (connection.streams.length > 0) {
|
|
35
|
+
streamIds.push(connection.streams[0].id);
|
|
36
|
+
}
|
|
37
|
+
// Make second request
|
|
38
|
+
const response2 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
39
|
+
method: 'echo',
|
|
40
|
+
params: { message: 'second' },
|
|
41
|
+
});
|
|
42
|
+
expect(response2.result.success).to.be.true;
|
|
43
|
+
// Get stream count after second request
|
|
44
|
+
const finalStreamCount = connection.streams.length;
|
|
45
|
+
if (connection.streams.length > 0) {
|
|
46
|
+
streamIds.push(connection.streams[0].id);
|
|
47
|
+
}
|
|
48
|
+
// With default behavior (reusePolicy='none'), new streams are created
|
|
49
|
+
// This test verifies current behavior
|
|
50
|
+
expect(streamIds.length).to.be.greaterThan(0);
|
|
51
|
+
expect(finalStreamCount).to.be.greaterThan(0);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('Stream Creation with reusePolicy="none"', () => {
|
|
56
|
+
it('should create new streams for each request', async () => {
|
|
57
|
+
builder = await NetworkTopologies.twoNode();
|
|
58
|
+
const leader = builder.getNode('o://leader');
|
|
59
|
+
const child = builder.getNode('o://child');
|
|
60
|
+
// Make multiple requests
|
|
61
|
+
for (let i = 0; i < 3; i++) {
|
|
62
|
+
const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
63
|
+
method: 'echo',
|
|
64
|
+
params: { message: `request-${i}` },
|
|
65
|
+
});
|
|
66
|
+
expect(response.result.success).to.be.true;
|
|
67
|
+
}
|
|
68
|
+
// Get connection to verify stream behavior
|
|
69
|
+
const connectionManager = leader.connectionManager;
|
|
70
|
+
const connection = connectionManager.getCachedLibp2pConnection(child.address);
|
|
71
|
+
// With default reusePolicy='none', streams are closed after each request
|
|
72
|
+
// So we expect minimal open streams
|
|
73
|
+
expect(connection).to.exist;
|
|
74
|
+
if (connection) {
|
|
75
|
+
// The number of open streams should be limited since old ones are closed
|
|
76
|
+
expect(connection.streams.length).to.be.lessThan(10);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('Stream Persistence After Transmission', () => {
|
|
81
|
+
it('should close streams after transmission with reusePolicy="none"', async () => {
|
|
82
|
+
builder = await NetworkTopologies.twoNode();
|
|
83
|
+
const leader = builder.getNode('o://leader');
|
|
84
|
+
const child = builder.getNode('o://child');
|
|
85
|
+
// Make a request
|
|
86
|
+
const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
87
|
+
method: 'echo',
|
|
88
|
+
params: { message: 'test' },
|
|
89
|
+
});
|
|
90
|
+
expect(response.result.success).to.be.true;
|
|
91
|
+
// Get connection
|
|
92
|
+
const connectionManager = leader.connectionManager;
|
|
93
|
+
const connection = connectionManager.getCachedLibp2pConnection(child.address);
|
|
94
|
+
expect(connection).to.exist;
|
|
95
|
+
if (connection) {
|
|
96
|
+
// Make another request to verify new stream can be created
|
|
97
|
+
const response2 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
98
|
+
method: 'echo',
|
|
99
|
+
params: { message: 'test2' },
|
|
100
|
+
});
|
|
101
|
+
expect(response2.result.success).to.be.true;
|
|
102
|
+
// Verify connection is still functional
|
|
103
|
+
expect(connection.status).to.equal('open');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -16,6 +16,7 @@ describe('Connection Management', () => {
|
|
|
16
16
|
describe('Connection Pooling', () => {
|
|
17
17
|
it('should cache and reuse connections', async () => {
|
|
18
18
|
builder = await NetworkTopologies.twoNode();
|
|
19
|
+
console.log('Built the 2 node network, starting test');
|
|
19
20
|
const leader = builder.getNode('o://leader');
|
|
20
21
|
const child = builder.getNode('o://child');
|
|
21
22
|
const spy = createConnectionSpy(leader);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-builder.d.ts","sourceRoot":"","sources":["../../../test/helpers/network-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,qBAAa,QAAS,SAAQ,SAAS;IAC9B,SAAS,SAAK;gBAET,MAAM,EAAE,eAAe,GAAG;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE;IAIzD,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAelC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"network-builder.d.ts","sourceRoot":"","sources":["../../../test/helpers/network-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,qBAAa,QAAS,SAAQ,SAAS;IAC9B,SAAS,SAAK;gBAET,MAAM,EAAE,eAAe,GAAG;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE;IAIzD,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAelC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC/B,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS3C,cAAc,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS9C,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC;CAY5D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,YAAY,CAA0B;IAE9C;;;OAGG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,EACtB,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAC/B,OAAO,CAAC,QAAQ,CAAC;IAqCpB;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB/C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI9C;;OAEG;IACH,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;IAIpC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyC7B;;OAEG;YACW,iBAAiB;IAkB/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B;;;OAGG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;IAO/C;;;OAGG;WACU,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IAQjD;;;;OAIG;WACU,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAUhD;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC;IAOrD;;;;;OAKG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;CAmBhD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.42",
|
|
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.42",
|
|
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.42",
|
|
64
|
+
"@olane/o-core": "0.7.42",
|
|
65
|
+
"@olane/o-protocol": "0.7.42",
|
|
66
|
+
"@olane/o-tool": "0.7.42",
|
|
67
67
|
"debug": "^4.4.1",
|
|
68
68
|
"dotenv": "^16.5.0",
|
|
69
69
|
"json5": "^2.2.3"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "689465b34c2aefe28b6c87e3822d69651f2a49b7"
|
|
72
72
|
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { Stream } from '@libp2p/interface';
|
|
2
|
-
import type { oAddress } from '@olane/o-core';
|
|
3
|
-
/**
|
|
4
|
-
* oManagedStream wraps a libp2p Stream with caller/receiver address metadata
|
|
5
|
-
* to enable proper stream reuse based on address pairs rather than protocol only.
|
|
6
|
-
*
|
|
7
|
-
* Key features:
|
|
8
|
-
* - Bidirectional cache keys: A↔B === B↔A
|
|
9
|
-
* - Automatic reusability checking
|
|
10
|
-
* - Idle time tracking for cleanup
|
|
11
|
-
*/
|
|
12
|
-
export declare class oManagedStream {
|
|
13
|
-
readonly stream: Stream;
|
|
14
|
-
readonly callerAddress: oAddress;
|
|
15
|
-
readonly receiverAddress: oAddress;
|
|
16
|
-
readonly direction: 'inbound' | 'outbound';
|
|
17
|
-
readonly createdAt: number;
|
|
18
|
-
private _lastUsedAt;
|
|
19
|
-
constructor(stream: Stream, callerAddress: oAddress, receiverAddress: oAddress, direction: 'inbound' | 'outbound');
|
|
20
|
-
/**
|
|
21
|
-
* Generates a bidirectional cache key from caller and receiver addresses.
|
|
22
|
-
* The key is symmetric: A↔B === B↔A
|
|
23
|
-
*
|
|
24
|
-
* @returns Cache key string in format "address1↔address2" (sorted)
|
|
25
|
-
*/
|
|
26
|
-
get cacheKey(): string;
|
|
27
|
-
/**
|
|
28
|
-
* Checks if the stream is in a reusable state:
|
|
29
|
-
* - Stream status is 'open'
|
|
30
|
-
* - Write status is 'writable'
|
|
31
|
-
* - Remote read status is 'readable'
|
|
32
|
-
*
|
|
33
|
-
* @returns true if stream can be reused
|
|
34
|
-
*/
|
|
35
|
-
get isReusable(): boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Gets the last used timestamp
|
|
38
|
-
*/
|
|
39
|
-
get lastUsedAt(): number;
|
|
40
|
-
/**
|
|
41
|
-
* Gets the age of the stream in milliseconds
|
|
42
|
-
*/
|
|
43
|
-
get age(): number;
|
|
44
|
-
/**
|
|
45
|
-
* Gets the idle time in milliseconds since last use
|
|
46
|
-
*/
|
|
47
|
-
get idleTime(): number;
|
|
48
|
-
/**
|
|
49
|
-
* Updates the last used timestamp to now
|
|
50
|
-
*/
|
|
51
|
-
updateLastUsed(): void;
|
|
52
|
-
/**
|
|
53
|
-
* Gets a string representation of the managed stream for debugging
|
|
54
|
-
*/
|
|
55
|
-
toString(): string;
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=o-managed-stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"o-managed-stream.d.ts","sourceRoot":"","sources":["../../../src/connection/o-managed-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;;;GAQG;AACH,qBAAa,cAAc;aAKP,MAAM,EAAE,MAAM;aACd,aAAa,EAAE,QAAQ;aACvB,eAAe,EAAE,QAAQ;aACzB,SAAS,EAAE,SAAS,GAAG,UAAU;IAPnD,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,OAAO,CAAC,WAAW,CAAS;gBAGV,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,QAAQ,EACvB,eAAe,EAAE,QAAQ,EACzB,SAAS,EAAE,SAAS,GAAG,UAAU;IAMnD;;;;;OAKG;IACH,IAAI,QAAQ,IAAI,MAAM,CAQrB;IAED;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,OAAO,CAMxB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGnB"}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* oManagedStream wraps a libp2p Stream with caller/receiver address metadata
|
|
3
|
-
* to enable proper stream reuse based on address pairs rather than protocol only.
|
|
4
|
-
*
|
|
5
|
-
* Key features:
|
|
6
|
-
* - Bidirectional cache keys: A↔B === B↔A
|
|
7
|
-
* - Automatic reusability checking
|
|
8
|
-
* - Idle time tracking for cleanup
|
|
9
|
-
*/
|
|
10
|
-
export class oManagedStream {
|
|
11
|
-
constructor(stream, callerAddress, receiverAddress, direction) {
|
|
12
|
-
this.stream = stream;
|
|
13
|
-
this.callerAddress = callerAddress;
|
|
14
|
-
this.receiverAddress = receiverAddress;
|
|
15
|
-
this.direction = direction;
|
|
16
|
-
this.createdAt = Date.now();
|
|
17
|
-
this._lastUsedAt = this.createdAt;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Generates a bidirectional cache key from caller and receiver addresses.
|
|
21
|
-
* The key is symmetric: A↔B === B↔A
|
|
22
|
-
*
|
|
23
|
-
* @returns Cache key string in format "address1↔address2" (sorted)
|
|
24
|
-
*/
|
|
25
|
-
get cacheKey() {
|
|
26
|
-
// Sort addresses to ensure bidirectionality
|
|
27
|
-
const addresses = [
|
|
28
|
-
this.callerAddress.value,
|
|
29
|
-
this.receiverAddress.value,
|
|
30
|
-
].sort();
|
|
31
|
-
return `${addresses[0]}↔${addresses[1]}`;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Checks if the stream is in a reusable state:
|
|
35
|
-
* - Stream status is 'open'
|
|
36
|
-
* - Write status is 'writable'
|
|
37
|
-
* - Remote read status is 'readable'
|
|
38
|
-
*
|
|
39
|
-
* @returns true if stream can be reused
|
|
40
|
-
*/
|
|
41
|
-
get isReusable() {
|
|
42
|
-
return (this.stream.status === 'open' &&
|
|
43
|
-
this.stream.writeStatus === 'writable' &&
|
|
44
|
-
this.stream.remoteReadStatus === 'readable');
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Gets the last used timestamp
|
|
48
|
-
*/
|
|
49
|
-
get lastUsedAt() {
|
|
50
|
-
return this._lastUsedAt;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Gets the age of the stream in milliseconds
|
|
54
|
-
*/
|
|
55
|
-
get age() {
|
|
56
|
-
return Date.now() - this.createdAt;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Gets the idle time in milliseconds since last use
|
|
60
|
-
*/
|
|
61
|
-
get idleTime() {
|
|
62
|
-
return Date.now() - this._lastUsedAt;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Updates the last used timestamp to now
|
|
66
|
-
*/
|
|
67
|
-
updateLastUsed() {
|
|
68
|
-
this._lastUsedAt = Date.now();
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Gets a string representation of the managed stream for debugging
|
|
72
|
-
*/
|
|
73
|
-
toString() {
|
|
74
|
-
return `oManagedStream(${this.cacheKey}, ${this.direction}, ${this.stream.status})`;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"o-managed-stream.spec.d.ts","sourceRoot":"","sources":["../../test/o-managed-stream.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
import { oManagedStream } from '../src/connection/o-managed-stream.js';
|
|
3
|
-
import { oAddress } from '@olane/o-core';
|
|
4
|
-
describe('oManagedStream', () => {
|
|
5
|
-
let mockStream;
|
|
6
|
-
let callerAddress;
|
|
7
|
-
let receiverAddress;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
// Create mock stream
|
|
10
|
-
mockStream = {
|
|
11
|
-
id: 'test-stream-id',
|
|
12
|
-
status: 'open',
|
|
13
|
-
writeStatus: 'writable',
|
|
14
|
-
remoteReadStatus: 'readable',
|
|
15
|
-
direction: 'outbound',
|
|
16
|
-
protocol: '/o/test',
|
|
17
|
-
addEventListener: () => { },
|
|
18
|
-
};
|
|
19
|
-
callerAddress = new oAddress('o://caller');
|
|
20
|
-
receiverAddress = new oAddress('o://receiver');
|
|
21
|
-
});
|
|
22
|
-
describe('Construction', () => {
|
|
23
|
-
it('should create managed stream with correct properties', () => {
|
|
24
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
25
|
-
expect(managedStream.stream).to.equal(mockStream);
|
|
26
|
-
expect(managedStream.callerAddress).to.equal(callerAddress);
|
|
27
|
-
expect(managedStream.receiverAddress).to.equal(receiverAddress);
|
|
28
|
-
expect(managedStream.direction).to.equal('outbound');
|
|
29
|
-
expect(managedStream.createdAt).to.be.a('number');
|
|
30
|
-
expect(managedStream.lastUsedAt).to.equal(managedStream.createdAt);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe('Cache Key Generation', () => {
|
|
34
|
-
it('should generate bidirectional cache key (A→B === B→A)', () => {
|
|
35
|
-
const streamAtoB = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
36
|
-
const streamBtoA = new oManagedStream(mockStream, receiverAddress, callerAddress, 'inbound');
|
|
37
|
-
// Cache keys should be identical regardless of direction
|
|
38
|
-
expect(streamAtoB.cacheKey).to.equal(streamBtoA.cacheKey);
|
|
39
|
-
});
|
|
40
|
-
it('should generate different keys for different address pairs', () => {
|
|
41
|
-
const address1 = new oAddress('o://node-1');
|
|
42
|
-
const address2 = new oAddress('o://node-2');
|
|
43
|
-
const address3 = new oAddress('o://node-3');
|
|
44
|
-
const stream1 = new oManagedStream(mockStream, address1, address2, 'outbound');
|
|
45
|
-
const stream2 = new oManagedStream(mockStream, address1, address3, 'outbound');
|
|
46
|
-
expect(stream1.cacheKey).to.not.equal(stream2.cacheKey);
|
|
47
|
-
});
|
|
48
|
-
it('should create stable, sorted cache keys', () => {
|
|
49
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
50
|
-
const expectedKey = [callerAddress.value, receiverAddress.value]
|
|
51
|
-
.sort()
|
|
52
|
-
.join('↔');
|
|
53
|
-
expect(managedStream.cacheKey).to.equal(expectedKey);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
describe('Reusability Check', () => {
|
|
57
|
-
it('should be reusable when stream is open, writable, and readable', () => {
|
|
58
|
-
mockStream.status = 'open';
|
|
59
|
-
mockStream.writeStatus = 'writable';
|
|
60
|
-
mockStream.remoteReadStatus = 'readable';
|
|
61
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
62
|
-
expect(managedStream.isReusable).to.be.true;
|
|
63
|
-
});
|
|
64
|
-
it('should not be reusable when stream is closed', () => {
|
|
65
|
-
mockStream.status = 'closed';
|
|
66
|
-
mockStream.writeStatus = 'writable';
|
|
67
|
-
mockStream.remoteReadStatus = 'readable';
|
|
68
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
69
|
-
expect(managedStream.isReusable).to.be.false;
|
|
70
|
-
});
|
|
71
|
-
it('should not be reusable when stream is not writable', () => {
|
|
72
|
-
mockStream.status = 'open';
|
|
73
|
-
mockStream.writeStatus = 'closed';
|
|
74
|
-
mockStream.remoteReadStatus = 'readable';
|
|
75
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
76
|
-
expect(managedStream.isReusable).to.be.false;
|
|
77
|
-
});
|
|
78
|
-
it('should not be reusable when remote is not readable', () => {
|
|
79
|
-
mockStream.status = 'open';
|
|
80
|
-
mockStream.writeStatus = 'writable';
|
|
81
|
-
mockStream.remoteReadStatus = 'closed';
|
|
82
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
83
|
-
expect(managedStream.isReusable).to.be.false;
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
describe('Timestamp Management', () => {
|
|
87
|
-
it('should update lastUsedAt when updateLastUsed is called', async () => {
|
|
88
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
89
|
-
const initialLastUsed = managedStream.lastUsedAt;
|
|
90
|
-
// Wait a bit to ensure timestamp difference
|
|
91
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
92
|
-
managedStream.updateLastUsed();
|
|
93
|
-
expect(managedStream.lastUsedAt).to.be.greaterThan(initialLastUsed);
|
|
94
|
-
});
|
|
95
|
-
it('should calculate age correctly', async () => {
|
|
96
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
97
|
-
// Wait a bit
|
|
98
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
99
|
-
expect(managedStream.age).to.be.greaterThan(0);
|
|
100
|
-
expect(managedStream.age).to.be.lessThan(1000); // Should be less than 1 second
|
|
101
|
-
});
|
|
102
|
-
it('should calculate idle time correctly', async () => {
|
|
103
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
104
|
-
// Wait a bit without using
|
|
105
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
106
|
-
expect(managedStream.idleTime).to.be.greaterThan(0);
|
|
107
|
-
// Update and check idle time resets
|
|
108
|
-
managedStream.updateLastUsed();
|
|
109
|
-
expect(managedStream.idleTime).to.be.lessThan(5);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
describe('String Representation', () => {
|
|
113
|
-
it('should provide meaningful toString output', () => {
|
|
114
|
-
const managedStream = new oManagedStream(mockStream, callerAddress, receiverAddress, 'outbound');
|
|
115
|
-
const str = managedStream.toString();
|
|
116
|
-
expect(str).to.include('oManagedStream');
|
|
117
|
-
expect(str).to.include(managedStream.cacheKey);
|
|
118
|
-
expect(str).to.include('outbound');
|
|
119
|
-
expect(str).to.include('open');
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream-handler-caching.spec.d.ts","sourceRoot":"","sources":["../../test/stream-handler-caching.spec.ts"],"names":[],"mappings":""}
|