@seriousme/opifex 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/client.ts +5 -0
- package/connNext/baseConnNext.ts +123 -0
- package/deno/tlsServer.test.ts +1 -1
- package/deno/wsServer.ts +11 -3
- package/dev_utils/WebStreamEndpoint.ts +5 -0
- package/dev_utils/asyncStreamEndpoint.ts +5 -0
- package/dev_utils/asyncStreamPair.ts +4 -9
- package/dev_utils/asyncStreamPairToNext.ts +45 -0
- package/dev_utils/asyncStreamToNext.ts +30 -137
- package/dev_utils/connNextPair.test.ts +2 -2
- package/dev_utils/generateCert.ts +297 -77
- package/dev_utils/mockConn.ts +37 -93
- package/dev_utils/mockServer.ts +1 -1
- package/dev_utils/webStreamPair.ts +3 -7
- package/dev_utils/webStreamPairToNext.ts +48 -0
- package/dev_utils/webStreamToNext.ts +28 -161
- package/dist/client/client.d.ts +4 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +3 -0
- package/dist/client/client.js.map +1 -1
- package/dist/connNext/baseConnNext.d.ts +20 -0
- package/dist/connNext/baseConnNext.d.ts.map +1 -0
- package/dist/connNext/baseConnNext.js +95 -0
- package/dist/connNext/baseConnNext.js.map +1 -0
- package/dist/dev_utils/generateCert.d.ts +5 -4
- package/dist/dev_utils/generateCert.d.ts.map +1 -1
- package/dist/dev_utils/generateCert.js +230 -65
- package/dist/dev_utils/generateCert.js.map +1 -1
- package/dist/examples/mqtt+mqtts.test.js +1 -1
- package/dist/examples/mqtt+mqtts.test.js.map +1 -1
- package/dist/examples/mqtts.test.js +1 -1
- package/dist/examples/mqtts.test.js.map +1 -1
- package/dist/node/nodeSocketToNext.d.ts +10 -13
- package/dist/node/nodeSocketToNext.d.ts.map +1 -1
- package/dist/node/nodeSocketToNext.js +75 -131
- package/dist/node/nodeSocketToNext.js.map +1 -1
- package/dist/web/webSocketToNext.d.ts +18 -1
- package/dist/web/webSocketToNext.d.ts.map +1 -1
- package/dist/web/webSocketToNext.js +92 -127
- package/dist/web/webSocketToNext.js.map +1 -1
- package/dist/web/wsClient.d.ts.map +1 -1
- package/dist/web/wsClient.js +4 -3
- package/dist/web/wsClient.js.map +1 -1
- package/examples/mqtt+mqtts.test.ts +1 -1
- package/examples/mqtts.test.ts +1 -1
- package/node/nodeSocketToNext.ts +85 -148
- package/node/tlsServer.test.ts +1 -1
- package/package.json +2 -4
- package/web/webSocketToNext.ts +108 -145
- package/web/wsClient.ts +10 -3
- package/dev_utils/webStreamPair.test.ts +0 -171
package/client/client.ts
CHANGED
|
@@ -51,6 +51,8 @@ export type ConnectParameters = {
|
|
|
51
51
|
key?: string | undefined;
|
|
52
52
|
/** number of retries before stopping connection attempts */
|
|
53
53
|
numberOfRetries?: number | undefined;
|
|
54
|
+
/** maximum size of receive buffer, only used by webSockets for now */
|
|
55
|
+
maxBufferSize?: number | undefined;
|
|
54
56
|
/** connect options */
|
|
55
57
|
options?: ConnectOptions | undefined;
|
|
56
58
|
};
|
|
@@ -159,6 +161,8 @@ export class Client {
|
|
|
159
161
|
protected key?: string | undefined;
|
|
160
162
|
/** the MQTT clientId */
|
|
161
163
|
protected clientId: string;
|
|
164
|
+
/** the maximum number of bytes buffered by a ws/wss client */
|
|
165
|
+
protected maxBufferSize: number | undefined;
|
|
162
166
|
private ctx: Context;
|
|
163
167
|
private connectPacket?: ConnectPacket;
|
|
164
168
|
|
|
@@ -310,6 +314,7 @@ export class Client {
|
|
|
310
314
|
this.caCerts = params?.caCerts;
|
|
311
315
|
this.cert = params?.cert;
|
|
312
316
|
this.key = params?.key;
|
|
317
|
+
this.maxBufferSize = params?.maxBufferSize;
|
|
313
318
|
const options = Object.assign(
|
|
314
319
|
{
|
|
315
320
|
keepAlive: this.keepAlive,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
|
|
2
|
+
|
|
3
|
+
export abstract class BaseConnNext implements ConnNext {
|
|
4
|
+
abstract remoteAddr?: ConnAddr;
|
|
5
|
+
abstract localAddr?: ConnAddr;
|
|
6
|
+
|
|
7
|
+
protected chunks: Uint8Array[] = [];
|
|
8
|
+
protected queueOffset = 0;
|
|
9
|
+
protected closed = false;
|
|
10
|
+
private isPulling = false;
|
|
11
|
+
|
|
12
|
+
abstract write(data: Uint8Array): Promise<void>;
|
|
13
|
+
abstract close(): void;
|
|
14
|
+
|
|
15
|
+
/** Specifiek per bron: haal pas daadwerkelijk 1 chunk op als de basisklasse erom vraagt */
|
|
16
|
+
protected abstract pullNextChunk(): Promise<Uint8Array | null>;
|
|
17
|
+
|
|
18
|
+
isClosed(): boolean {
|
|
19
|
+
return this.closed;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected getBufferedBytes(): number {
|
|
23
|
+
let total = 0;
|
|
24
|
+
for (let i = 0; i < this.chunks.length; i++) {
|
|
25
|
+
total += i === 0
|
|
26
|
+
? this.chunks[i]!.byteLength - this.queueOffset
|
|
27
|
+
: this.chunks[i]!.byteLength;
|
|
28
|
+
}
|
|
29
|
+
return total;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Zorgt ervoor dat we data ophalen op exact het moment dat het nodig is */
|
|
33
|
+
private async ensureData(length?: number): Promise<void> {
|
|
34
|
+
while (
|
|
35
|
+
!this.closed &&
|
|
36
|
+
(this.getBufferedBytes() === 0 ||
|
|
37
|
+
(length !== undefined && this.getBufferedBytes() < length))
|
|
38
|
+
) {
|
|
39
|
+
if (this.isPulling) {
|
|
40
|
+
// Voorkom gelijktijdige pulls als er al eentje loopt
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.isPulling = true;
|
|
46
|
+
try {
|
|
47
|
+
const chunk = await this.pullNextChunk();
|
|
48
|
+
if (chunk === null || chunk.byteLength === 0) {
|
|
49
|
+
this.closed = true;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
this.chunks.push(chunk);
|
|
53
|
+
} catch {
|
|
54
|
+
this.closed = true;
|
|
55
|
+
} finally {
|
|
56
|
+
this.isPulling = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async read(length?: number): Promise<Uint8Array | null> {
|
|
62
|
+
if (this.closed && this.getBufferedBytes() === 0) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (length === 0) {
|
|
67
|
+
return new Uint8Array(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Pull exact zolang tot we genoeg data hebben voor deze read()
|
|
71
|
+
await this.ensureData(length);
|
|
72
|
+
|
|
73
|
+
if (this.getBufferedBytes() === 0) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Onbegrensd lezen (geen lengte opgegeven)
|
|
78
|
+
if (length === undefined) {
|
|
79
|
+
const firstChunk = this.chunks.shift()!;
|
|
80
|
+
const result = firstChunk.subarray(this.queueOffset);
|
|
81
|
+
this.queueOffset = 0;
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Exacte lengte uitlezen uit de buffer
|
|
86
|
+
const bytesToTake = Math.min(length, this.getBufferedBytes());
|
|
87
|
+
const result = new Uint8Array(bytesToTake);
|
|
88
|
+
let bytesCopied = 0;
|
|
89
|
+
|
|
90
|
+
while (bytesCopied < bytesToTake && this.chunks.length > 0) {
|
|
91
|
+
const currentChunk = this.chunks[0]!;
|
|
92
|
+
const bytesNeeded = bytesToTake - bytesCopied;
|
|
93
|
+
const bytesAvailable = currentChunk.byteLength - this.queueOffset;
|
|
94
|
+
|
|
95
|
+
if (bytesAvailable <= bytesNeeded) {
|
|
96
|
+
result.set(currentChunk.subarray(this.queueOffset), bytesCopied);
|
|
97
|
+
bytesCopied += bytesAvailable;
|
|
98
|
+
this.chunks.shift();
|
|
99
|
+
this.queueOffset = 0;
|
|
100
|
+
} else {
|
|
101
|
+
result.set(
|
|
102
|
+
currentChunk.subarray(
|
|
103
|
+
this.queueOffset,
|
|
104
|
+
this.queueOffset + bytesNeeded,
|
|
105
|
+
),
|
|
106
|
+
bytesCopied,
|
|
107
|
+
);
|
|
108
|
+
bytesCopied += bytesNeeded;
|
|
109
|
+
this.queueOffset += bytesNeeded;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return bytesCopied === 0 ? null : result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async *[Symbol.asyncIterator]() {
|
|
117
|
+
while (true) {
|
|
118
|
+
const chunk = await this.read();
|
|
119
|
+
if (chunk === null) break;
|
|
120
|
+
yield chunk;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
package/deno/tlsServer.test.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { MqttServer } from "../server/mod.ts";
|
|
|
9
9
|
|
|
10
10
|
logger.level(LogLevel.info);
|
|
11
11
|
|
|
12
|
-
const { key, cert, caCert } = generateLocalhostCerts();
|
|
12
|
+
const { key, cert, caCert } = await generateLocalhostCerts();
|
|
13
13
|
|
|
14
14
|
test("Deno: Test pubSub using client and server", async () => {
|
|
15
15
|
const server = new TlsServer(
|
package/deno/wsServer.ts
CHANGED
|
@@ -23,8 +23,9 @@ async function handleWsClient(
|
|
|
23
23
|
socket: WebSocket,
|
|
24
24
|
mqttServer: MqttServer,
|
|
25
25
|
remoteAddr: NetAddr,
|
|
26
|
+
maxBufferSize: number | undefined,
|
|
26
27
|
) {
|
|
27
|
-
const conn = await webSocketToNext(socket, remoteAddr);
|
|
28
|
+
const conn = await webSocketToNext(socket, remoteAddr, maxBufferSize);
|
|
28
29
|
mqttServer.serve(conn);
|
|
29
30
|
logger.debug("serving mqtt");
|
|
30
31
|
}
|
|
@@ -33,6 +34,9 @@ export function mqttOverWS(
|
|
|
33
34
|
mqttServer: MqttServer,
|
|
34
35
|
pathName: string,
|
|
35
36
|
next: RequestHandler,
|
|
37
|
+
opts?: {
|
|
38
|
+
maxBufferSize?: number | undefined;
|
|
39
|
+
},
|
|
36
40
|
): RequestHandler {
|
|
37
41
|
const wsRequestHandler: RequestHandler = (req, info) => {
|
|
38
42
|
const url = new URL(req.url);
|
|
@@ -45,7 +49,7 @@ export function mqttOverWS(
|
|
|
45
49
|
const { socket, response } = Deno.upgradeWebSocket(req);
|
|
46
50
|
logger.debug("upgraded to websocket");
|
|
47
51
|
// do not await on purpose
|
|
48
|
-
handleWsClient(socket, mqttServer, remoteAddr);
|
|
52
|
+
handleWsClient(socket, mqttServer, remoteAddr, opts?.maxBufferSize);
|
|
49
53
|
return response;
|
|
50
54
|
}
|
|
51
55
|
return next(req, info);
|
|
@@ -65,6 +69,7 @@ export class WsServer {
|
|
|
65
69
|
hostname?: string;
|
|
66
70
|
};
|
|
67
71
|
private pathName: string;
|
|
72
|
+
private maxBufferSize: number | undefined;
|
|
68
73
|
|
|
69
74
|
/**
|
|
70
75
|
* Create a new WebSocket server
|
|
@@ -74,12 +79,14 @@ export class WsServer {
|
|
|
74
79
|
port: number;
|
|
75
80
|
hostname?: string;
|
|
76
81
|
pathName?: string;
|
|
82
|
+
maxBufferSize?: number;
|
|
77
83
|
},
|
|
78
84
|
mqttOptions: MqttServerOptions | MqttServer,
|
|
79
85
|
) {
|
|
80
|
-
const { pathName, ...listenOptions } = serverOptions;
|
|
86
|
+
const { pathName, maxBufferSize, ...listenOptions } = serverOptions;
|
|
81
87
|
this.listenOptions = listenOptions;
|
|
82
88
|
this.pathName = pathName ?? "/mqtt";
|
|
89
|
+
this.maxBufferSize = maxBufferSize;
|
|
83
90
|
if (mqttOptions instanceof MqttServer) {
|
|
84
91
|
this.mqttServer = mqttOptions;
|
|
85
92
|
} else {
|
|
@@ -95,6 +102,7 @@ export class WsServer {
|
|
|
95
102
|
this.mqttServer,
|
|
96
103
|
this.pathName,
|
|
97
104
|
pageNotFound,
|
|
105
|
+
{ maxBufferSize: this.maxBufferSize },
|
|
98
106
|
);
|
|
99
107
|
this.server = Deno.serve(this.listenOptions, requestHandler);
|
|
100
108
|
await this.server.finished;
|
|
@@ -2,14 +2,9 @@
|
|
|
2
2
|
* Duplex AsyncStream
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
readable: AsyncIterable<Uint8Array>;
|
|
7
|
-
write: (chunk: Uint8Array) => Promise<void>;
|
|
8
|
-
close: () => void;
|
|
9
|
-
}
|
|
10
|
-
|
|
5
|
+
import type { AsyncStreamEndpoint } from "./asyncStreamEndpoint.ts";
|
|
11
6
|
/**
|
|
12
|
-
*
|
|
7
|
+
* Internal push/pull queue to support AsyncIterable iteration.
|
|
13
8
|
*/
|
|
14
9
|
class AsyncQueue<T> implements AsyncIterable<T> {
|
|
15
10
|
private queue: T[] = [];
|
|
@@ -75,8 +70,8 @@ class AsyncQueue<T> implements AsyncIterable<T> {
|
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
export function createAsyncStreamPair(): {
|
|
78
|
-
input:
|
|
79
|
-
output:
|
|
73
|
+
input: AsyncStreamEndpoint;
|
|
74
|
+
output: AsyncStreamEndpoint;
|
|
80
75
|
} {
|
|
81
76
|
const queueA = new AsyncQueue<Uint8Array>();
|
|
82
77
|
const queueB = new AsyncQueue<Uint8Array>();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
|
|
2
|
+
import { createAsyncStreamPair } from "./asyncStreamPair.ts";
|
|
3
|
+
import { asyncStreamToNext } from "./asyncStreamToNext.ts";
|
|
4
|
+
|
|
5
|
+
export function createConnNextPair(): {
|
|
6
|
+
input: ConnNext;
|
|
7
|
+
output: ConnNext;
|
|
8
|
+
} {
|
|
9
|
+
const { input: asyncInput, output: asyncOutput } = createAsyncStreamPair();
|
|
10
|
+
|
|
11
|
+
const mockAddr: ConnAddr = {
|
|
12
|
+
transport: "tcp",
|
|
13
|
+
hostname: "127.0.0.1",
|
|
14
|
+
port: 1883,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const inputWrapper = asyncStreamToNext(asyncInput);
|
|
18
|
+
const outputWrapper = asyncStreamToNext(asyncOutput);
|
|
19
|
+
|
|
20
|
+
const input: ConnNext = {
|
|
21
|
+
remoteAddr: mockAddr,
|
|
22
|
+
localAddr: mockAddr,
|
|
23
|
+
read: (length: number | undefined) => inputWrapper.read(length),
|
|
24
|
+
write: (data: Uint8Array<ArrayBufferLike>) => inputWrapper.write(data),
|
|
25
|
+
[Symbol.asyncIterator]: () => inputWrapper[Symbol.asyncIterator](),
|
|
26
|
+
close: () => {
|
|
27
|
+
inputWrapper.close();
|
|
28
|
+
outputWrapper.close();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const output: ConnNext = {
|
|
33
|
+
remoteAddr: mockAddr,
|
|
34
|
+
localAddr: mockAddr,
|
|
35
|
+
read: (length: number | undefined) => outputWrapper.read(length),
|
|
36
|
+
write: (data: Uint8Array<ArrayBufferLike>) => outputWrapper.write(data),
|
|
37
|
+
[Symbol.asyncIterator]: () => outputWrapper[Symbol.asyncIterator](),
|
|
38
|
+
close: () => {
|
|
39
|
+
outputWrapper.close();
|
|
40
|
+
inputWrapper.close();
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return { input, output };
|
|
45
|
+
}
|
|
@@ -1,171 +1,64 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { AsyncStreamPairEndpoint } from "./asyncStreamPair.ts";
|
|
1
|
+
import { BaseConnNext } from "../connNext/baseConnNext.ts";
|
|
2
|
+
import type { AsyncStreamEndpoint } from "./asyncStreamEndpoint.ts";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
private endPoint: AsyncStreamPairEndpoint;
|
|
9
|
-
private leftover: Uint8Array = new Uint8Array(0);
|
|
4
|
+
export class AsyncStreamConnNext extends BaseConnNext {
|
|
5
|
+
remoteAddr = undefined;
|
|
6
|
+
localAddr = undefined;
|
|
10
7
|
private reader: AsyncIterator<Uint8Array>;
|
|
8
|
+
private endPoint: AsyncStreamEndpoint;
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
constructor(endPoint: AsyncStreamEndpoint) {
|
|
11
|
+
super();
|
|
14
12
|
this.endPoint = endPoint;
|
|
15
|
-
|
|
13
|
+
// Haal de async iterator op uit de readable stream
|
|
16
14
|
this.reader = endPoint.readable[Symbol.asyncIterator]();
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
21
|
-
*/ async write(chunk: Uint8Array): Promise<void> {
|
|
22
|
-
if (this.closed) {
|
|
23
|
-
return Promise.reject(new Error("Pipe closed"));
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
await this.endPoint.write(chunk);
|
|
27
|
-
return;
|
|
28
|
-
} catch (err) {
|
|
29
|
-
this.closed = true;
|
|
30
|
-
throw err;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Reads data from the stream.
|
|
36
|
-
* If `length` is provided, waits until exact number of bytes are buffered.
|
|
18
|
+
* Haalt op exact moment van aanvragen één nieuwe chunk op via de iterator.
|
|
37
19
|
*/
|
|
38
|
-
async
|
|
39
|
-
if (this.closed
|
|
20
|
+
protected async pullNextChunk(): Promise<Uint8Array | null> {
|
|
21
|
+
if (this.closed) {
|
|
40
22
|
return null;
|
|
41
23
|
}
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
return new Uint8Array(0);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Helper to fetch the next chunk from the underlying iterable
|
|
48
|
-
const fetchNextChunk = async (): Promise<Uint8Array | null> => {
|
|
25
|
+
try {
|
|
49
26
|
const { value, done } = await this.reader.next();
|
|
50
|
-
if (done) {
|
|
27
|
+
if (done || !value) {
|
|
51
28
|
this.closed = true;
|
|
52
29
|
return null;
|
|
53
30
|
}
|
|
54
31
|
return value;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (length === undefined) {
|
|
59
|
-
if (this.leftover.length > 0) {
|
|
60
|
-
const result = this.leftover;
|
|
61
|
-
this.leftover = new Uint8Array(0);
|
|
62
|
-
return result;
|
|
63
|
-
}
|
|
64
|
-
return await fetchNextChunk();
|
|
32
|
+
} catch {
|
|
33
|
+
this.closed = true;
|
|
34
|
+
return null;
|
|
65
35
|
}
|
|
36
|
+
}
|
|
66
37
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
let bytesAccumulated = 0;
|
|
71
|
-
|
|
72
|
-
// Use leftover data first if available
|
|
73
|
-
if (this.leftover.length > 0) {
|
|
74
|
-
const take = Math.min(this.leftover.length, bytesRequested);
|
|
75
|
-
result.set(this.leftover.subarray(0, take), bytesAccumulated);
|
|
76
|
-
bytesAccumulated += take;
|
|
77
|
-
this.leftover = this.leftover.subarray(take);
|
|
38
|
+
async write(chunk: Uint8Array): Promise<void> {
|
|
39
|
+
if (this.closed) {
|
|
40
|
+
return Promise.reject(new Error("Pipe closed"));
|
|
78
41
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (value === null) {
|
|
85
|
-
// Stream ended before collecting required bytes
|
|
86
|
-
if (bytesAccumulated === 0) return null;
|
|
87
|
-
return result.subarray(0, bytesAccumulated);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const needed = bytesRequested - bytesAccumulated;
|
|
91
|
-
|
|
92
|
-
if (value.length <= needed) {
|
|
93
|
-
result.set(value, bytesAccumulated);
|
|
94
|
-
bytesAccumulated += value.length;
|
|
95
|
-
} else {
|
|
96
|
-
result.set(value.subarray(0, needed), bytesAccumulated);
|
|
97
|
-
bytesAccumulated += needed;
|
|
98
|
-
this.leftover = value.subarray(needed);
|
|
99
|
-
}
|
|
42
|
+
try {
|
|
43
|
+
await this.endPoint.write(chunk);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
this.closed = true;
|
|
46
|
+
throw err;
|
|
100
47
|
}
|
|
101
|
-
|
|
102
|
-
return result;
|
|
103
48
|
}
|
|
104
49
|
|
|
105
|
-
/**
|
|
106
|
-
* Closes the reader, writer, and underlying AsyncStream pair endpoint.
|
|
107
|
-
*/
|
|
108
50
|
close(): void {
|
|
109
51
|
if (!this.closed) {
|
|
110
52
|
this.closed = true;
|
|
111
53
|
try {
|
|
112
54
|
this.endPoint.close();
|
|
113
|
-
} catch (_err) {
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
async *[Symbol.asyncIterator]() {
|
|
117
|
-
while (true) {
|
|
118
|
-
const chunk = await this.read();
|
|
119
|
-
if (chunk === null) {
|
|
120
|
-
break;
|
|
55
|
+
} catch (_err) {
|
|
56
|
+
/* swallow */
|
|
121
57
|
}
|
|
122
|
-
yield chunk;
|
|
123
58
|
}
|
|
124
59
|
}
|
|
125
60
|
}
|
|
126
61
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* Offers the exact same API as `createConnNextPair`.
|
|
130
|
-
*/
|
|
131
|
-
export function createConnNextPair(): {
|
|
132
|
-
input: ConnNext;
|
|
133
|
-
output: ConnNext;
|
|
134
|
-
} {
|
|
135
|
-
const { input: asyncInput, output: asyncOutput } = createAsyncStreamPair();
|
|
136
|
-
|
|
137
|
-
const mockAddr: ConnAddr = {
|
|
138
|
-
transport: "tcp",
|
|
139
|
-
hostname: "127.0.0.1",
|
|
140
|
-
port: 1883,
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const inputWrapper = new AsyncStreamConnNextWrapper(asyncInput);
|
|
144
|
-
const outputWrapper = new AsyncStreamConnNextWrapper(asyncOutput);
|
|
145
|
-
|
|
146
|
-
const input: ConnNext = {
|
|
147
|
-
remoteAddr: mockAddr,
|
|
148
|
-
localAddr: mockAddr,
|
|
149
|
-
read: (length) => inputWrapper.read(length),
|
|
150
|
-
write: (data) => inputWrapper.write(data),
|
|
151
|
-
[Symbol.asyncIterator]: () => inputWrapper[Symbol.asyncIterator](),
|
|
152
|
-
close: () => {
|
|
153
|
-
inputWrapper.close();
|
|
154
|
-
outputWrapper.close();
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const output: ConnNext = {
|
|
159
|
-
remoteAddr: mockAddr,
|
|
160
|
-
localAddr: mockAddr,
|
|
161
|
-
read: (length) => outputWrapper.read(length),
|
|
162
|
-
write: (data) => outputWrapper.write(data),
|
|
163
|
-
[Symbol.asyncIterator]: () => outputWrapper[Symbol.asyncIterator](),
|
|
164
|
-
close: () => {
|
|
165
|
-
outputWrapper.close();
|
|
166
|
-
inputWrapper.close();
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
return { input, output };
|
|
62
|
+
export function asyncStreamToNext(endPoint: AsyncStreamEndpoint) {
|
|
63
|
+
return new AsyncStreamConnNext(endPoint);
|
|
171
64
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test } from "node:test";
|
|
2
2
|
import assert from "node:assert";
|
|
3
|
-
import { createConnNextPair as asyncPair } from "./
|
|
4
|
-
import { createConnNextPair as webPair } from "./
|
|
3
|
+
import { createConnNextPair as asyncPair } from "./asyncStreamPairToNext.ts";
|
|
4
|
+
import { createConnNextPair as webPair } from "./webStreamPairToNext.ts";
|
|
5
5
|
|
|
6
6
|
const pairs = {
|
|
7
7
|
asyncStream: asyncPair,
|