@seriousme/opifex 2.2.0 → 2.4.0

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.
Files changed (154) hide show
  1. package/README.md +7 -6
  2. package/bin/mqtt.ts +1 -1
  3. package/client/client.ts +62 -7
  4. package/client/context.ts +2 -2
  5. package/client/deps.ts +3 -3
  6. package/client/mod.ts +2 -2
  7. package/connNext/baseConnNext.ts +123 -0
  8. package/connNext/connNext.ts +44 -0
  9. package/deno/README.md +1 -1
  10. package/deno/denoConnToNext.ts +104 -0
  11. package/deno/tcpClient.ts +8 -24
  12. package/deno/tcpServer.test.ts +14 -103
  13. package/deno/tcpServer.ts +14 -6
  14. package/deno/tlsServer.test.ts +14 -58
  15. package/deno/tlsServer.ts +14 -6
  16. package/deno/wsServer.test.ts +15 -61
  17. package/deno/wsServer.ts +82 -32
  18. package/dev_utils/WebStreamEndpoint.ts +5 -0
  19. package/dev_utils/asyncStreamEndpoint.ts +5 -0
  20. package/dev_utils/asyncStreamPair.ts +109 -0
  21. package/dev_utils/asyncStreamPairToNext.ts +45 -0
  22. package/dev_utils/asyncStreamToNext.ts +64 -0
  23. package/dev_utils/connNextPair.test.ts +179 -0
  24. package/dev_utils/mockConn.ts +59 -29
  25. package/dev_utils/mockServer.ts +3 -4
  26. package/dev_utils/mod.ts +1 -2
  27. package/dev_utils/testClient.ts +64 -0
  28. package/dev_utils/webStreamPair.ts +3 -7
  29. package/dev_utils/webStreamPairToNext.ts +48 -0
  30. package/dev_utils/webStreamToNext.ts +54 -0
  31. package/dist/bin/mqtt.js +1 -1
  32. package/dist/bin/mqtt.js.map +1 -1
  33. package/dist/client/client.d.ts +24 -3
  34. package/dist/client/client.d.ts.map +1 -1
  35. package/dist/client/client.js +45 -5
  36. package/dist/client/client.js.map +1 -1
  37. package/dist/client/context.d.ts +2 -2
  38. package/dist/client/context.d.ts.map +1 -1
  39. package/dist/client/deps.d.ts +1 -1
  40. package/dist/client/deps.d.ts.map +1 -1
  41. package/dist/client/mod.d.ts +1 -1
  42. package/dist/client/mod.d.ts.map +1 -1
  43. package/dist/connNext/baseConnNext.d.ts +20 -0
  44. package/dist/connNext/baseConnNext.d.ts.map +1 -0
  45. package/dist/connNext/baseConnNext.js +95 -0
  46. package/dist/connNext/baseConnNext.js.map +1 -0
  47. package/dist/connNext/connNext.d.ts +43 -0
  48. package/dist/connNext/connNext.d.ts.map +1 -0
  49. package/dist/connNext/connNext.js +2 -0
  50. package/dist/connNext/connNext.js.map +1 -0
  51. package/dist/examples/authHandler.test.js +2 -2
  52. package/dist/examples/authHandler.test.js.map +1 -1
  53. package/dist/examples/mqtt+mqtts.test.d.ts +2 -0
  54. package/dist/examples/mqtt+mqtts.test.d.ts.map +1 -0
  55. package/dist/examples/mqtt+mqtts.test.js +104 -0
  56. package/dist/examples/mqtt+mqtts.test.js.map +1 -0
  57. package/dist/examples/mqtt.test.js +2 -2
  58. package/dist/examples/mqtt.test.js.map +1 -1
  59. package/dist/examples/mqtts.test.js +2 -2
  60. package/dist/examples/mqtts.test.js.map +1 -1
  61. package/dist/mqttConn/mqttConn.d.ts +5 -6
  62. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  63. package/dist/mqttConn/mqttConn.js +2 -3
  64. package/dist/mqttConn/mqttConn.js.map +1 -1
  65. package/dist/node/nodeSocketToNext.d.ts +17 -0
  66. package/dist/node/nodeSocketToNext.d.ts.map +1 -0
  67. package/dist/node/nodeSocketToNext.js +105 -0
  68. package/dist/node/nodeSocketToNext.js.map +1 -0
  69. package/dist/node/tcpClient.d.ts +4 -6
  70. package/dist/node/tcpClient.d.ts.map +1 -1
  71. package/dist/node/tcpClient.js +6 -21
  72. package/dist/node/tcpClient.js.map +1 -1
  73. package/dist/node/tcpServer.d.ts +8 -4
  74. package/dist/node/tcpServer.d.ts.map +1 -1
  75. package/dist/node/tcpServer.js +14 -6
  76. package/dist/node/tcpServer.js.map +1 -1
  77. package/dist/node/tlsServer.d.ts +7 -3
  78. package/dist/node/tlsServer.d.ts.map +1 -1
  79. package/dist/node/tlsServer.js +13 -5
  80. package/dist/node/tlsServer.js.map +1 -1
  81. package/dist/server/context.d.ts +5 -5
  82. package/dist/server/context.d.ts.map +1 -1
  83. package/dist/server/context.js +4 -1
  84. package/dist/server/context.js.map +1 -1
  85. package/dist/server/deps.d.ts +1 -1
  86. package/dist/server/deps.d.ts.map +1 -1
  87. package/dist/server/mod.d.ts +1 -1
  88. package/dist/server/mod.d.ts.map +1 -1
  89. package/dist/server/server.d.ts +3 -3
  90. package/dist/server/server.d.ts.map +1 -1
  91. package/dist/server/server.js +3 -3
  92. package/dist/utils/utils.d.ts +1 -2
  93. package/dist/utils/utils.d.ts.map +1 -1
  94. package/dist/utils/utils.js +3 -2
  95. package/dist/utils/utils.js.map +1 -1
  96. package/dist/web/webSocketToNext.d.ts +20 -0
  97. package/dist/web/webSocketToNext.d.ts.map +1 -0
  98. package/dist/web/webSocketToNext.js +125 -0
  99. package/dist/web/webSocketToNext.js.map +1 -0
  100. package/dist/web/wsClient.d.ts +3 -3
  101. package/dist/web/wsClient.d.ts.map +1 -1
  102. package/dist/web/wsClient.js +22 -7
  103. package/dist/web/wsClient.js.map +1 -1
  104. package/dist/web/wsClient.test.js +15 -0
  105. package/dist/web/wsClient.test.js.map +1 -1
  106. package/examples/README.md +21 -0
  107. package/examples/authHandler.test.ts +2 -2
  108. package/examples/mqtt+mqtts.test.ts +122 -0
  109. package/examples/mqtt.test.ts +2 -2
  110. package/examples/mqtts.test.ts +2 -2
  111. package/examples/webSocket.test.ts +10 -64
  112. package/examples/webSocketServer.ts +98 -0
  113. package/mqttConn/mqttConn.test.ts +6 -6
  114. package/mqttConn/mqttConn.ts +8 -9
  115. package/node/README.md +1 -1
  116. package/node/nodeSocketToNext.ts +124 -0
  117. package/node/tcpClient.ts +13 -27
  118. package/node/tcpServer.test.ts +12 -58
  119. package/node/tcpServer.ts +18 -8
  120. package/node/tlsServer.test.ts +11 -58
  121. package/node/tlsServer.ts +17 -7
  122. package/package.json +4 -3
  123. package/server/context.ts +9 -6
  124. package/server/deps.ts +1 -1
  125. package/server/mod.ts +1 -1
  126. package/server/server.ts +6 -6
  127. package/utils/utils.ts +3 -2
  128. package/web/webSocketToNext.ts +146 -0
  129. package/web/wsClient.test.ts +22 -0
  130. package/web/wsClient.ts +29 -9
  131. package/dev_utils/webStreamPair.test.ts +0 -171
  132. package/dist/node/wrapNodeSocket.d.ts +0 -12
  133. package/dist/node/wrapNodeSocket.d.ts.map +0 -1
  134. package/dist/node/wrapNodeSocket.js +0 -36
  135. package/dist/node/wrapNodeSocket.js.map +0 -1
  136. package/dist/socket/socket.d.ts +0 -58
  137. package/dist/socket/socket.d.ts.map +0 -1
  138. package/dist/socket/socket.js +0 -99
  139. package/dist/socket/socket.js.map +0 -1
  140. package/dist/web/webSocketStream.d.ts +0 -29
  141. package/dist/web/webSocketStream.d.ts.map +0 -1
  142. package/dist/web/webSocketStream.js +0 -69
  143. package/dist/web/webSocketStream.js.map +0 -1
  144. package/dist/web/wrapWebSocket.d.ts +0 -12
  145. package/dist/web/wrapWebSocket.d.ts.map +0 -1
  146. package/dist/web/wrapWebSocket.js +0 -41
  147. package/dist/web/wrapWebSocket.js.map +0 -1
  148. package/node/socket-node-stream.test.ts +0 -322
  149. package/node/socket-node-stream.ts +0 -174
  150. package/node/wrapNodeSocket.ts +0 -44
  151. package/socket/socket.test.ts +0 -91
  152. package/socket/socket.ts +0 -149
  153. package/web/webSocketStream.ts +0 -97
  154. package/web/wrapWebSocket.ts +0 -52
@@ -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
+ }
@@ -0,0 +1,64 @@
1
+ import { BaseConnNext } from "../connNext/baseConnNext.ts";
2
+ import type { AsyncStreamEndpoint } from "./asyncStreamEndpoint.ts";
3
+
4
+ export class AsyncStreamConnNext extends BaseConnNext {
5
+ remoteAddr = undefined;
6
+ localAddr = undefined;
7
+ private reader: AsyncIterator<Uint8Array>;
8
+ private endPoint: AsyncStreamEndpoint;
9
+
10
+ constructor(endPoint: AsyncStreamEndpoint) {
11
+ super();
12
+ this.endPoint = endPoint;
13
+ // Haal de async iterator op uit de readable stream
14
+ this.reader = endPoint.readable[Symbol.asyncIterator]();
15
+ }
16
+
17
+ /**
18
+ * Haalt op exact moment van aanvragen één nieuwe chunk op via de iterator.
19
+ */
20
+ protected async pullNextChunk(): Promise<Uint8Array | null> {
21
+ if (this.closed) {
22
+ return null;
23
+ }
24
+
25
+ try {
26
+ const { value, done } = await this.reader.next();
27
+ if (done || !value) {
28
+ this.closed = true;
29
+ return null;
30
+ }
31
+ return value;
32
+ } catch {
33
+ this.closed = true;
34
+ return null;
35
+ }
36
+ }
37
+
38
+ async write(chunk: Uint8Array): Promise<void> {
39
+ if (this.closed) {
40
+ return Promise.reject(new Error("Pipe closed"));
41
+ }
42
+ try {
43
+ await this.endPoint.write(chunk);
44
+ } catch (err) {
45
+ this.closed = true;
46
+ throw err;
47
+ }
48
+ }
49
+
50
+ close(): void {
51
+ if (!this.closed) {
52
+ this.closed = true;
53
+ try {
54
+ this.endPoint.close();
55
+ } catch (_err) {
56
+ /* swallow */
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ export function asyncStreamToNext(endPoint: AsyncStreamEndpoint) {
63
+ return new AsyncStreamConnNext(endPoint);
64
+ }
@@ -0,0 +1,179 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert";
3
+ import { createConnNextPair as asyncPair } from "./asyncStreamPairToNext.ts";
4
+ import { createConnNextPair as webPair } from "./webStreamPairToNext.ts";
5
+
6
+ const pairs = {
7
+ asyncStream: asyncPair,
8
+ webStream: webPair,
9
+ };
10
+
11
+ for (const [label, createConnNextPair] of Object.entries(pairs)) {
12
+ test(`[${label}]:`, async (t) => {
13
+ await t.test("Echo server shuts down cleanly when client closes input", async () => {
14
+ const { input, output } = createConnNextPair();
15
+
16
+ // Run a simple background echo server using the Stream Next model
17
+ const echoPromise = (async () => {
18
+ while (true) {
19
+ const chunk = await output.read();
20
+ if (chunk === null) break; // End of stream reached
21
+ await output.write(chunk);
22
+ }
23
+ })();
24
+
25
+ // Client closes their side of the connection
26
+ input.close();
27
+
28
+ // The echo server loop should finish successfully without throwing
29
+ await assert.doesNotReject(echoPromise);
30
+
31
+ // The client's read call should now return null indicating EOF
32
+ const result = await input.read();
33
+ assert.strictEqual(result, null);
34
+ });
35
+
36
+ await t.test("Data written to input.write arrives at input.read", async () => {
37
+ const { input, output } = createConnNextPair();
38
+
39
+ // Background echo server
40
+ const echoPromise = (async () => {
41
+ while (true) {
42
+ const chunk = await output.read();
43
+ if (chunk === null) break;
44
+ await output.write(chunk);
45
+ }
46
+ })();
47
+
48
+ const encoder = new TextEncoder();
49
+ const decoder = new TextDecoder();
50
+ const message = "Hello streaming world!";
51
+
52
+ // Write data from the client side
53
+ await input.write(encoder.encode(message));
54
+
55
+ // Read back the echoed message
56
+ const result = await input.read();
57
+ assert.notStrictEqual(result, null);
58
+ assert.strictEqual(decoder.decode(result!), message);
59
+
60
+ // Close the client side so the echo server finishes cleanly
61
+ input.close();
62
+ await assert.doesNotReject(echoPromise);
63
+ });
64
+
65
+ await t.test("Client detects when the echo server abruptly closes its end", async () => {
66
+ const { input, output } = createConnNextPair();
67
+ const encoder = new TextEncoder();
68
+
69
+ // Run a server loop that can be manually stopped by closing 'output'
70
+ const echoPromise = (async () => {
71
+ while (true) {
72
+ const chunk = await output.read();
73
+ if (chunk === null) break;
74
+ await output.write(chunk);
75
+ }
76
+ })();
77
+
78
+ // --- Simulate Server Shutdown ---
79
+ // The server abruptly closes its end
80
+ output.close();
81
+ await assert.doesNotReject(echoPromise);
82
+
83
+ // Client reading should now receive EOF (null)
84
+ const first = await input.read();
85
+ assert.strictEqual(first, null);
86
+
87
+ // Subsequent write from the client should reject with a closed pipe error
88
+ await assert.rejects(
89
+ () => input.write(encoder.encode("Is anyone there?")),
90
+ /closed/i,
91
+ );
92
+ });
93
+
94
+ await t.test("Data can be written and read sequentially before closing", async () => {
95
+ const { input, output } = createConnNextPair();
96
+
97
+ // Background echo server
98
+ const echoPromise = (async () => {
99
+ while (true) {
100
+ const chunk = await output.read();
101
+ if (chunk === null) break;
102
+ await output.write(chunk);
103
+ }
104
+ })();
105
+
106
+ const encoder = new TextEncoder();
107
+ const decoder = new TextDecoder();
108
+
109
+ // 1. Write & read Chunk 1 sequentially
110
+ await input.write(encoder.encode("Chunk 1"));
111
+ const result1 = await input.read("Chunk 1".length);
112
+ assert.notStrictEqual(result1, null);
113
+ assert.strictEqual(decoder.decode(result1!), "Chunk 1");
114
+
115
+ // 2. Write & read Chunk 2 sequentially
116
+ await input.write(encoder.encode("Chunk 2"));
117
+ const result2 = await input.read("Chunk 2".length);
118
+ assert.notStrictEqual(result2, null);
119
+ assert.strictEqual(decoder.decode(result2!), "Chunk 2");
120
+
121
+ // 3. Close the client side mid-stream
122
+ input.close();
123
+
124
+ // Echo server completes processing gracefully
125
+ await assert.doesNotReject(echoPromise);
126
+
127
+ // 4. Verify that further read returns null (EOF)
128
+ const finalResult = await input.read();
129
+ assert.strictEqual(finalResult, null);
130
+ });
131
+
132
+ await t.test("Client detects when the echo server abruptly closes its end", async () => {
133
+ const { input, output } = createConnNextPair();
134
+ const encoder = new TextEncoder();
135
+
136
+ // Run a server loop that can be manually stopped by closing 'output'
137
+ const echoPromise = (async () => {
138
+ while (true) {
139
+ const chunk = await output.read();
140
+ if (chunk === null) break;
141
+ await output.write(chunk);
142
+ }
143
+ })();
144
+
145
+ // --- Simulate Server Shutdown ---
146
+ // The server abruptly closes its end
147
+ output.close();
148
+ await assert.doesNotReject(echoPromise);
149
+
150
+ // Client reading should now receive EOF (null)
151
+ const first = await input.read();
152
+ assert.strictEqual(first, null);
153
+
154
+ // Subsequent write from the client should reject with a closed pipe error
155
+ await assert.rejects(
156
+ () => input.write(encoder.encode("Is anyone there?")),
157
+ /closed/i,
158
+ );
159
+ });
160
+
161
+ await t.test("Repeated close calls are idempotent and do not throw", async () => {
162
+ const { input, output } = createConnNextPair();
163
+
164
+ // Multiple close calls on either side should complete safely without throwing
165
+ assert.doesNotThrow(() => {
166
+ input.close();
167
+ input.close();
168
+ output.close();
169
+ output.close();
170
+ });
171
+
172
+ const clientRead = await input.read();
173
+ const serverRead = await output.read();
174
+
175
+ assert.strictEqual(clientRead, null);
176
+ assert.strictEqual(serverRead, null);
177
+ });
178
+ });
179
+ }
@@ -1,36 +1,66 @@
1
- class Uint8Writer implements WritableStreamDefaultWriter {
2
- private buff: Uint8Array;
3
- private pos: number;
4
- closed = Promise.resolve(undefined);
5
- close = () => Promise.resolve();
6
- abort = () => Promise.resolve();
7
- ready = Promise.resolve(undefined);
8
- releaseLock = () => {};
9
- desiredSize = 20;
1
+ import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
2
+ import { createAsyncStreamPair } from "./asyncStreamPair.ts";
3
+ import { AsyncStreamConnNext } from "./asyncStreamToNext.ts";
10
4
 
11
- constructor(
12
- buff: Uint8Array,
13
- ) {
14
- this.buff = buff;
15
- this.pos = 0;
16
- }
17
- write(chunk: Uint8Array): Promise<void> {
18
- this.buff.set(chunk, this.pos);
19
- this.pos += chunk.length;
20
- return Promise.resolve();
21
- }
22
- }
23
-
24
- export function createMockSockConn(
5
+ /**
6
+ * Creates an in-memory mock ConnNext object for unit testing.
7
+ *
8
+ * @param readerBuffs List of Uint8Arrays containing incoming test data
9
+ * @param writerBuf Buffer where outgoing data should be written
10
+ * @param close Optional callback executed on closure
11
+ */
12
+ export function createMockConn(
25
13
  readerBuffs: Uint8Array[],
26
14
  writerBuf: Uint8Array,
27
15
  close = () => {},
28
- ) {
29
- const readable = ReadableStream.from(readerBuffs);
30
- const writable = new WritableStream(new Uint8Writer(writerBuf));
16
+ ): ConnNext {
17
+ // Maak een async stream pair aan
18
+ const { input, output } = createAsyncStreamPair();
19
+
20
+ const mockAddr: ConnAddr = {
21
+ transport: "tcp",
22
+ hostname: "127.0.0.1",
23
+ port: 1883,
24
+ };
25
+
26
+ // Push all input directly to the input of the StreamPair
27
+ (async () => {
28
+ try {
29
+ for (const buf of readerBuffs) {
30
+ await input.write(buf);
31
+ }
32
+ input.close();
33
+ } catch {
34
+ // ignore errors
35
+ }
36
+ })();
37
+
38
+ // Capture written data and store it in the write buffer
39
+ (async () => {
40
+ try {
41
+ let writerPos = 0;
42
+ for await (const chunk of input.readable) {
43
+ writerBuf.set(chunk, writerPos);
44
+ writerPos += chunk.byteLength;
45
+ }
46
+ } catch {
47
+ // ignore errors
48
+ }
49
+ })();
50
+
51
+ // Return a ConnNext wrapper connected to the output side
52
+ const wrapper = new AsyncStreamConnNext(output);
53
+
31
54
  return {
32
- readable,
33
- writable,
34
- close,
55
+ remoteAddr: mockAddr,
56
+ localAddr: mockAddr,
57
+ read: (length) => wrapper.read(length),
58
+ write: (data) => wrapper.write(data),
59
+ [Symbol.asyncIterator]: () => wrapper[Symbol.asyncIterator](),
60
+ close: () => {
61
+ wrapper.close();
62
+ output.close();
63
+ close();
64
+ },
35
65
  };
36
66
  }
@@ -1,4 +1,4 @@
1
- import { createWebStreamPair } from "./webStreamPair.ts";
1
+ import { createConnNextPair } from "./asyncStreamPairToNext.ts";
2
2
  import { MqttConn } from "../mqttConn/mqttConn.ts";
3
3
  import { Context, MqttServer } from "../server/mod.ts";
4
4
  import { handlers } from "./test-handlers.ts";
@@ -11,17 +11,16 @@ export function startMockServer(opts: MqttServerOptions = {}): {
11
11
  const serverOpts = { handlers, ...opts };
12
12
  // start with a fresh clientlist
13
13
  Context.clientList.clear();
14
- // create a new MQTT server
15
14
 
16
15
  const mqttServer = new MqttServer(serverOpts);
17
- const { input, output } = createWebStreamPair();
16
+ const { input, output } = createConnNextPair();
18
17
  const mqttConn = new MqttConn({ conn: output });
19
18
  mqttServer.serve(input);
20
19
  return { mqttConn, mqttServer };
21
20
  }
22
21
 
23
22
  export function addMockClient(mqttServer: MqttServer): MqttConn {
24
- const { input, output } = createWebStreamPair();
23
+ const { input, output } = createConnNextPair();
25
24
  const mqttConn = new MqttConn({ conn: output });
26
25
  mqttServer.serve(input);
27
26
  return mqttConn;
package/dev_utils/mod.ts CHANGED
@@ -1,5 +1,4 @@
1
- export { createMockSockConn } from "./mockConn.ts";
2
- export { createWebStreamPair } from "./webStreamPair.ts";
1
+ export { createMockConn } from "./mockConn.ts";
3
2
  export {
4
3
  delay,
5
4
  resolveAsap,
@@ -0,0 +1,64 @@
1
+ import assert from "node:assert/strict";
2
+ import { delay, logger } from "../utils/mod.ts";
3
+ import type { PublishPacket, QoS } from "../mqttPacket/mod.ts";
4
+ import type { Client, ConnectParameters } from "../client/client.ts";
5
+
6
+ export async function testClient(client: Client, params: ConnectParameters) {
7
+ logger.verbose("client parameters: ", params);
8
+ client.onConnected = () =>
9
+ logger.verbose("Client connected to server at:", client.url.toString());
10
+
11
+ await client.connect(params);
12
+
13
+ const publishSet: { topic: string; qos: QoS }[] = [
14
+ { topic: "t0@q0", qos: 0 },
15
+ { topic: "t1@q0", qos: 0 },
16
+ { topic: "t2@q0", qos: 0 },
17
+ { topic: "t0@q1", qos: 1 },
18
+ { topic: "t1@q1", qos: 1 },
19
+ { topic: "t2@q1", qos: 1 },
20
+ { topic: "t0@q2", qos: 2 },
21
+ { topic: "t1@q2", qos: 2 },
22
+ { topic: "t2@q2", qos: 2 },
23
+ ];
24
+
25
+ const subscriptions = publishSet.map((item) => ({
26
+ topicFilter: item.topic,
27
+ qos: item.qos,
28
+ }));
29
+ await client.subscribe({
30
+ subscriptions,
31
+ });
32
+
33
+ // the IIFE ensures message reception runs in parallel
34
+ logger.verbose("Start receiving");
35
+ const received: PublishPacket[] = [];
36
+ (async () => {
37
+ for await (const item of client.messages()) {
38
+ logger.verbose("Receiving:", item.topic, "--", item.qos);
39
+ received.push(item);
40
+ }
41
+ })();
42
+ // end of IIFE
43
+ for (const item of publishSet) {
44
+ logger.verbose("Publishing:", item.topic, "--", item.qos);
45
+ await client.publish({
46
+ topic: item.topic,
47
+ qos: item.qos,
48
+ payload: new Uint8Array([0x01]),
49
+ });
50
+ }
51
+
52
+ await delay(100);
53
+ logger.verbose("Disconnect client");
54
+ await client.disconnect();
55
+
56
+ logger.verbose("Check completeness");
57
+ for (const item of publishSet) {
58
+ const found = received.find((f) =>
59
+ f.topic == item.topic && f.qos === item.qos
60
+ );
61
+ logger.verbose("Found:", item.topic, "--", item.qos);
62
+ assert(found, `${item.topic} -- ${item.qos}`);
63
+ }
64
+ }
@@ -1,12 +1,8 @@
1
- export interface WebStreamPairEndpoint {
2
- readable: ReadableStream<Uint8Array>;
3
- writable: WritableStream<Uint8Array>;
4
- close: () => void;
5
- }
1
+ import type { WebStreamEndpoint } from "./WebStreamEndpoint.ts";
6
2
 
7
3
  export function createWebStreamPair(): {
8
- input: WebStreamPairEndpoint;
9
- output: WebStreamPairEndpoint;
4
+ input: WebStreamEndpoint;
5
+ output: WebStreamEndpoint;
10
6
  } {
11
7
  let aController: ReadableStreamDefaultController | null = null;
12
8
  let bController: ReadableStreamDefaultController | null = null;
@@ -0,0 +1,48 @@
1
+ import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
2
+ import { createWebStreamPair } from "./webStreamPair.ts";
3
+ import { webStreamToNext } from "./webStreamToNext.ts";
4
+
5
+ /**
6
+ * Creates a pair of cross-connected ConnNext sockets backed by WebStreams.
7
+ */
8
+ export function createConnNextPair(): {
9
+ input: ConnNext;
10
+ output: ConnNext;
11
+ } {
12
+ const { input: webInput, output: webOutput } = createWebStreamPair();
13
+
14
+ const mockAddr: ConnAddr = {
15
+ transport: "tcp",
16
+ hostname: "127.0.0.1",
17
+ port: 1883,
18
+ };
19
+
20
+ const inputWrapper = webStreamToNext(webInput);
21
+ const outputWrapper = webStreamToNext(webOutput);
22
+
23
+ const input: ConnNext = {
24
+ remoteAddr: mockAddr,
25
+ localAddr: mockAddr,
26
+ read: (length) => inputWrapper.read(length),
27
+ write: (data) => inputWrapper.write(data),
28
+ [Symbol.asyncIterator]: () => inputWrapper[Symbol.asyncIterator](),
29
+ close: () => {
30
+ inputWrapper.close();
31
+ outputWrapper.close();
32
+ },
33
+ };
34
+
35
+ const output: ConnNext = {
36
+ remoteAddr: mockAddr,
37
+ localAddr: mockAddr,
38
+ read: (length) => outputWrapper.read(length),
39
+ write: (data) => outputWrapper.write(data),
40
+ [Symbol.asyncIterator]: () => outputWrapper[Symbol.asyncIterator](),
41
+ close: () => {
42
+ outputWrapper.close();
43
+ inputWrapper.close();
44
+ },
45
+ };
46
+
47
+ return { input, output };
48
+ }
@@ -0,0 +1,54 @@
1
+ import { BaseConnNext } from "../connNext/baseConnNext.ts";
2
+ import type { WebStreamEndpoint } from "./WebStreamEndpoint.ts";
3
+
4
+ export class WebStreamConnNext extends BaseConnNext {
5
+ remoteAddr = undefined;
6
+ localAddr = undefined;
7
+ private endPoint;
8
+ private reader: ReadableStreamDefaultReader<Uint8Array>;
9
+ private writer: WritableStreamDefaultWriter<Uint8Array>;
10
+
11
+ constructor(endPoint: WebStreamEndpoint) {
12
+ super();
13
+ this.endPoint = endPoint;
14
+ this.reader = endPoint.readable.getReader();
15
+ this.writer = endPoint.writable.getWriter();
16
+ this.reader.closed.catch(() => {});
17
+ this.writer.closed.catch(() => {});
18
+ }
19
+
20
+ protected async pullNextChunk(): Promise<Uint8Array | null> {
21
+ try {
22
+ const { value, done } = await this.reader.read();
23
+ if (done || !value) {
24
+ return null;
25
+ }
26
+ return value;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ async write(chunk: Uint8Array): Promise<void> {
33
+ if (this.closed) throw new Error("Pipe closed");
34
+ await this.writer.write(chunk);
35
+ }
36
+
37
+ close(): void {
38
+ if (!this.closed) {
39
+ this.closed = true;
40
+ try {
41
+ void this.reader.cancel().catch(() => {});
42
+ this.reader.releaseLock();
43
+ } catch { /* swallow */ }
44
+ void this.writer.close().catch(() => {});
45
+ try {
46
+ this.endPoint.close();
47
+ } catch { /* swallow */ }
48
+ }
49
+ }
50
+ }
51
+
52
+ export function webStreamToNext(endPoint: WebStreamEndpoint) {
53
+ return new WebStreamConnNext(endPoint);
54
+ }
package/dist/bin/mqtt.js CHANGED
@@ -232,7 +232,7 @@ async function publish() {
232
232
  qos: parseQos(publishArgs.qos),
233
233
  });
234
234
  logger.debug("Published!");
235
- client.disconnect();
235
+ await client.disconnect();
236
236
  logger.debug("Disconnected !");
237
237
  }
238
238
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"mqtt.js","sourceRoot":"","sources":["../../bin/mqtt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mqtt.js","sourceRoot":"","sources":["../../bin/mqtt.ts"],"names":[],"mappings":"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"}