@seriousme/opifex 2.1.0 → 2.3.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 (147) hide show
  1. package/README.md +7 -6
  2. package/bin/mqtt.ts +1 -1
  3. package/client/client.ts +58 -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/connNext.ts +44 -0
  8. package/deno/README.md +1 -1
  9. package/deno/denoConnToNext.ts +104 -0
  10. package/deno/mod.ts +7 -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 +77 -35
  18. package/dev_utils/asyncStreamPair.ts +114 -0
  19. package/dev_utils/asyncStreamToNext.ts +171 -0
  20. package/dev_utils/connNextPair.test.ts +179 -0
  21. package/dev_utils/mockConn.ts +115 -29
  22. package/dev_utils/mockServer.ts +3 -4
  23. package/dev_utils/mod.ts +1 -2
  24. package/dev_utils/testClient.ts +64 -0
  25. package/dev_utils/webStreamToNext.ts +187 -0
  26. package/dist/bin/mqtt.js +1 -1
  27. package/dist/bin/mqtt.js.map +1 -1
  28. package/dist/client/client.d.ts +21 -3
  29. package/dist/client/client.d.ts.map +1 -1
  30. package/dist/client/client.js +43 -5
  31. package/dist/client/client.js.map +1 -1
  32. package/dist/client/context.d.ts +2 -2
  33. package/dist/client/context.d.ts.map +1 -1
  34. package/dist/client/deps.d.ts +1 -1
  35. package/dist/client/deps.d.ts.map +1 -1
  36. package/dist/client/mod.d.ts +1 -1
  37. package/dist/client/mod.d.ts.map +1 -1
  38. package/dist/connNext/connNext.d.ts +43 -0
  39. package/dist/connNext/connNext.d.ts.map +1 -0
  40. package/dist/connNext/connNext.js +2 -0
  41. package/dist/connNext/connNext.js.map +1 -0
  42. package/dist/examples/authHandler.test.js +2 -2
  43. package/dist/examples/authHandler.test.js.map +1 -1
  44. package/dist/examples/mqtt+mqtts.test.d.ts +2 -0
  45. package/dist/examples/mqtt+mqtts.test.d.ts.map +1 -0
  46. package/dist/examples/mqtt+mqtts.test.js +104 -0
  47. package/dist/examples/mqtt+mqtts.test.js.map +1 -0
  48. package/dist/examples/mqtt.test.js +2 -2
  49. package/dist/examples/mqtt.test.js.map +1 -1
  50. package/dist/examples/mqtts.test.js +2 -2
  51. package/dist/examples/mqtts.test.js.map +1 -1
  52. package/dist/mqttConn/mqttConn.d.ts +5 -6
  53. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  54. package/dist/mqttConn/mqttConn.js +2 -3
  55. package/dist/mqttConn/mqttConn.js.map +1 -1
  56. package/dist/mqttPacket/protocolLevels.d.ts +2 -0
  57. package/dist/mqttPacket/protocolLevels.d.ts.map +1 -1
  58. package/dist/node/nodeSocketToNext.d.ts +20 -0
  59. package/dist/node/nodeSocketToNext.d.ts.map +1 -0
  60. package/dist/node/nodeSocketToNext.js +161 -0
  61. package/dist/node/nodeSocketToNext.js.map +1 -0
  62. package/dist/node/tcpClient.d.ts +4 -6
  63. package/dist/node/tcpClient.d.ts.map +1 -1
  64. package/dist/node/tcpClient.js +6 -21
  65. package/dist/node/tcpClient.js.map +1 -1
  66. package/dist/node/tcpServer.d.ts +8 -4
  67. package/dist/node/tcpServer.d.ts.map +1 -1
  68. package/dist/node/tcpServer.js +14 -6
  69. package/dist/node/tcpServer.js.map +1 -1
  70. package/dist/node/tlsServer.d.ts +7 -3
  71. package/dist/node/tlsServer.d.ts.map +1 -1
  72. package/dist/node/tlsServer.js +13 -5
  73. package/dist/node/tlsServer.js.map +1 -1
  74. package/dist/server/context.d.ts +5 -5
  75. package/dist/server/context.d.ts.map +1 -1
  76. package/dist/server/context.js +4 -1
  77. package/dist/server/context.js.map +1 -1
  78. package/dist/server/deps.d.ts +1 -1
  79. package/dist/server/deps.d.ts.map +1 -1
  80. package/dist/server/mod.d.ts +1 -1
  81. package/dist/server/mod.d.ts.map +1 -1
  82. package/dist/server/server.d.ts +3 -3
  83. package/dist/server/server.d.ts.map +1 -1
  84. package/dist/server/server.js +3 -3
  85. package/dist/utils/utils.d.ts +1 -2
  86. package/dist/utils/utils.d.ts.map +1 -1
  87. package/dist/utils/utils.js +3 -2
  88. package/dist/utils/utils.js.map +1 -1
  89. package/dist/web/webSocketToNext.d.ts +3 -0
  90. package/dist/web/webSocketToNext.d.ts.map +1 -0
  91. package/dist/web/webSocketToNext.js +160 -0
  92. package/dist/web/webSocketToNext.js.map +1 -0
  93. package/dist/web/wsClient.d.ts +8 -3
  94. package/dist/web/wsClient.d.ts.map +1 -1
  95. package/dist/web/wsClient.js +20 -6
  96. package/dist/web/wsClient.js.map +1 -1
  97. package/dist/web/wsClient.test.js +15 -0
  98. package/dist/web/wsClient.test.js.map +1 -1
  99. package/examples/README.md +21 -0
  100. package/examples/authHandler.test.ts +2 -2
  101. package/examples/mqtt+mqtts.test.ts +122 -0
  102. package/examples/mqtt.test.ts +2 -2
  103. package/examples/mqtts.test.ts +2 -2
  104. package/examples/webSocket.test.ts +10 -64
  105. package/examples/webSocketServer.ts +98 -0
  106. package/mqttConn/mqttConn.test.ts +6 -6
  107. package/mqttConn/mqttConn.ts +8 -9
  108. package/mqttPacket/protocolLevels.ts +2 -0
  109. package/node/README.md +1 -1
  110. package/node/mod.ts +7 -0
  111. package/node/{socket-node-stream.ts → nodeSocketToNext.ts} +78 -65
  112. package/node/tcpClient.ts +13 -27
  113. package/node/tcpServer.test.ts +12 -58
  114. package/node/tcpServer.ts +18 -8
  115. package/node/tlsServer.test.ts +11 -58
  116. package/node/tlsServer.ts +17 -7
  117. package/package.json +8 -2
  118. package/server/context.ts +9 -6
  119. package/server/deps.ts +1 -1
  120. package/server/mod.ts +1 -1
  121. package/server/server.ts +6 -6
  122. package/utils/utils.ts +3 -2
  123. package/web/webSocketToNext.ts +183 -0
  124. package/web/wsClient.test.ts +22 -0
  125. package/web/wsClient.ts +22 -9
  126. package/dist/node/wrapNodeSocket.d.ts +0 -12
  127. package/dist/node/wrapNodeSocket.d.ts.map +0 -1
  128. package/dist/node/wrapNodeSocket.js +0 -36
  129. package/dist/node/wrapNodeSocket.js.map +0 -1
  130. package/dist/socket/socket.d.ts +0 -40
  131. package/dist/socket/socket.d.ts.map +0 -1
  132. package/dist/socket/socket.js +0 -94
  133. package/dist/socket/socket.js.map +0 -1
  134. package/dist/web/webSocketStream.d.ts +0 -29
  135. package/dist/web/webSocketStream.d.ts.map +0 -1
  136. package/dist/web/webSocketStream.js +0 -69
  137. package/dist/web/webSocketStream.js.map +0 -1
  138. package/dist/web/wrapWebSocket.d.ts +0 -12
  139. package/dist/web/wrapWebSocket.d.ts.map +0 -1
  140. package/dist/web/wrapWebSocket.js +0 -41
  141. package/dist/web/wrapWebSocket.js.map +0 -1
  142. package/node/socket-node-stream.test.ts +0 -322
  143. package/node/wrapNodeSocket.ts +0 -44
  144. package/socket/socket.test.ts +0 -91
  145. package/socket/socket.ts +0 -124
  146. package/web/webSocketStream.ts +0 -97
  147. package/web/wrapWebSocket.ts +0 -52
@@ -0,0 +1,179 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert";
3
+ import { createConnNextPair as asyncPair } from "./asyncStreamToNext.ts";
4
+ import { createConnNextPair as webPair } from "./webStreamToNext.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,122 @@
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;
10
-
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
- }
1
+ import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
23
2
 
24
- export function createMockSockConn(
3
+ /**
4
+ * Creates an in-memory mock ConnNext object for unit testing.
5
+ *
6
+ * @param readerBuffs List of Uint8Arrays containing incoming test data
7
+ * @param writerBuf Buffer where outgoing data should be written
8
+ * @param close Optional callback executed on closure
9
+ */
10
+ export function createMockConn(
25
11
  readerBuffs: Uint8Array[],
26
12
  writerBuf: Uint8Array,
27
13
  close = () => {},
28
- ) {
29
- const readable = ReadableStream.from(readerBuffs);
30
- const writable = new WritableStream(new Uint8Writer(writerBuf));
14
+ ): ConnNext {
15
+ let readIndex = 0;
16
+ let readOffset = 0;
17
+ let writerPos = 0;
18
+ let isClosed = false;
19
+
20
+ // Helper function to calculate total remaining bytes across readerBuffs
21
+ const getRemainingBytes = (): number => {
22
+ let total = 0;
23
+ for (let i = readIndex; i < readerBuffs.length; i++) {
24
+ total += i === readIndex
25
+ ? readerBuffs[i].byteLength - readOffset
26
+ : readerBuffs[i].byteLength;
27
+ }
28
+ return total;
29
+ };
30
+
31
+ const mockAddr: ConnAddr = {
32
+ transport: "tcp",
33
+ hostname: "127.0.0.1",
34
+ port: 1883,
35
+ };
36
+
31
37
  return {
32
- readable,
33
- writable,
34
- close,
38
+ remoteAddr: mockAddr,
39
+ localAddr: mockAddr,
40
+
41
+ /**
42
+ * Read exactly 'length' bytes from the provided readerBuffs
43
+ */
44
+ read(length?: number): Promise<Uint8Array | null> {
45
+ if (isClosed) return Promise.resolve(null);
46
+
47
+ // No specific length requested: return the next available chunk immediately
48
+ if (length === undefined) {
49
+ if (readIndex >= readerBuffs.length) Promise.resolve(null);
50
+ const chunk = readerBuffs[readIndex].subarray(readOffset);
51
+ readIndex++;
52
+ readOffset = 0;
53
+ Promise.resolve(chunk);
54
+ }
55
+
56
+ length = length ?? 0;
57
+
58
+ // EOF reached / not enough remaining bytes in the mock buffers
59
+ if (getRemainingBytes() < length) {
60
+ return Promise.resolve(null);
61
+ }
62
+
63
+ const result = new Uint8Array(length);
64
+ let bytesCopied = 0;
65
+
66
+ while (bytesCopied < length && readIndex < readerBuffs.length) {
67
+ const current = readerBuffs[readIndex];
68
+ const available = current.byteLength - readOffset;
69
+ const needed = length - bytesCopied;
70
+
71
+ if (available <= needed) {
72
+ result.set(current.subarray(readOffset), bytesCopied);
73
+ bytesCopied += available;
74
+ readIndex++;
75
+ readOffset = 0;
76
+ } else {
77
+ result.set(
78
+ current.subarray(readOffset, readOffset + needed),
79
+ bytesCopied,
80
+ );
81
+ bytesCopied += needed;
82
+ readOffset += needed;
83
+ }
84
+ }
85
+
86
+ return Promise.resolve(result);
87
+ },
88
+
89
+ /**
90
+ * Write data directly at the current offset in writerBuf
91
+ */
92
+ write(data: Uint8Array): Promise<void> {
93
+ if (isClosed) {
94
+ throw new Error("Connection closed");
95
+ }
96
+ writerBuf.set(data, writerPos);
97
+ writerPos += data.byteLength;
98
+ return Promise.resolve();
99
+ },
100
+
101
+ /**
102
+ * Close the mock connection
103
+ */
104
+ close(): void {
105
+ if (!isClosed) {
106
+ isClosed = true;
107
+ close();
108
+ }
109
+ },
110
+
111
+ /**
112
+ * Async iterator for streaming test scenarios
113
+ */
114
+ async *[Symbol.asyncIterator]() {
115
+ while (true) {
116
+ const chunk = await this.read();
117
+ if (chunk === null) break;
118
+ yield chunk;
119
+ }
120
+ },
35
121
  };
36
122
  }
@@ -1,4 +1,4 @@
1
- import { createWebStreamPair } from "./webStreamPair.ts";
1
+ import { createConnNextPair } from "./webStreamToNext.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
+ }
@@ -0,0 +1,187 @@
1
+ import type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
2
+ import { createWebStreamPair } from "./webStreamPair.ts";
3
+ import type { WebStreamPairEndpoint } from "./webStreamPair.ts";
4
+
5
+ /** wrapper class */
6
+ export class WebStreamConnNextWrapper {
7
+ reader: ReadableStreamDefaultReader<Uint8Array>;
8
+ writer: WritableStreamDefaultWriter<Uint8Array>;
9
+ closed: boolean;
10
+ private endPoint: WebStreamPairEndpoint;
11
+ private leftover: Uint8Array = new Uint8Array(0);
12
+
13
+ /** Create a new ConnNext object from a Webstream */
14
+ constructor(endPoint: WebStreamPairEndpoint) {
15
+ this.endPoint = endPoint;
16
+ this.closed = false;
17
+ this.reader = endPoint.readable.getReader();
18
+ this.writer = endPoint.writable.getWriter();
19
+ this.reader.closed.catch(() => {});
20
+ this.writer.closed.catch(() => {});
21
+ }
22
+
23
+ /**
24
+ * Writes data chunk to the underlying WebStream WritableStream
25
+ */ async write(chunk: Uint8Array): Promise<void> {
26
+ if (this.closed) {
27
+ return Promise.reject(new Error("Pipe closed"));
28
+ }
29
+ try {
30
+ await this.writer.write(chunk);
31
+ return;
32
+ } catch (err) {
33
+ this.closed = true;
34
+ throw err;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Reads data from the stream.
40
+ * If `length` is provided, waits until exact number of bytes are buffered.
41
+ */
42
+ async read(length?: number): Promise<Uint8Array | null> {
43
+ if (this.closed || (length ?? 0) < 0) {
44
+ return null;
45
+ }
46
+
47
+ if (length === 0) {
48
+ return new Uint8Array(0);
49
+ }
50
+ if (length === undefined) {
51
+ if (this.leftover.length > 0) {
52
+ const result = this.leftover;
53
+ this.leftover = new Uint8Array(0);
54
+ return result;
55
+ }
56
+ const { value, done } = await this.reader.read();
57
+ if (value) {
58
+ return value;
59
+ }
60
+ if (done) {
61
+ return null;
62
+ }
63
+ }
64
+
65
+ // Just to please typescript
66
+ const bytesRequested = length === undefined ? 0 : length;
67
+
68
+ const result = new Uint8Array(bytesRequested);
69
+ let bytesAccumulated = 0;
70
+
71
+ // Do we have data from the previous read()
72
+ if (this.leftover.length > 0) {
73
+ const take = Math.min(this.leftover.length, bytesRequested);
74
+ result.set(this.leftover.subarray(0, take), bytesAccumulated);
75
+ bytesAccumulated += take;
76
+ this.leftover = this.leftover.subarray(take);
77
+ }
78
+
79
+ // Keep readin until we have enough data
80
+ while (bytesAccumulated < bytesRequested) {
81
+ const { value, done } = await this.reader.read();
82
+
83
+ if (value) {
84
+ const needed = bytesRequested - bytesAccumulated;
85
+
86
+ if (value.length <= needed) {
87
+ // We need the whole chunk
88
+ result.set(value, bytesAccumulated);
89
+ bytesAccumulated += value.length;
90
+ } else {
91
+ // Chunk is bigger than what we need
92
+ result.set(value.subarray(0, needed), bytesAccumulated);
93
+ bytesAccumulated += needed;
94
+ // Save the rest for the next read() call
95
+ this.leftover = value.subarray(needed);
96
+ }
97
+ }
98
+ if (done) {
99
+ // if the stream closed and not enough data was returned, return null
100
+ return null;
101
+ }
102
+ }
103
+ return result;
104
+ }
105
+
106
+ /**
107
+ * Closes the reader, writer, and underlying WebStream pair endpoint.
108
+ */
109
+ close(): void {
110
+ if (!this.closed) {
111
+ this.closed = true;
112
+
113
+ try {
114
+ void this.reader.cancel().catch(() => {
115
+ // ignore duplicate/late cancel attempts; the stream may already be closed
116
+ });
117
+ this.reader?.releaseLock();
118
+ // deno-coverage-ignore
119
+ } catch (_err) { /* swallow */ }
120
+
121
+ // deno-coverage-ignore-start
122
+ void this.writer.close().catch(() => {
123
+ // ignore duplicate/late close attempts; the stream may already be closed
124
+ });
125
+ // deno-coverage-ignore-stop
126
+
127
+ try {
128
+ this.endPoint.close();
129
+ } catch (_err) { /* swallow */ }
130
+ }
131
+ }
132
+ async *[Symbol.asyncIterator]() {
133
+ while (true) {
134
+ const chunk = await this.read();
135
+ if (chunk === null) {
136
+ break;
137
+ }
138
+ yield chunk;
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Creates a pair of cross-connected ConnNext sockets backed by WebStreams.
145
+ * Offers the exact same API as `createConnNextPair`.
146
+ */
147
+ export function createConnNextPair(): {
148
+ input: ConnNext;
149
+ output: ConnNext;
150
+ } {
151
+ const { input: webInput, output: webOutput } = createWebStreamPair();
152
+
153
+ const mockAddr: ConnAddr = {
154
+ transport: "tcp",
155
+ hostname: "127.0.0.1",
156
+ port: 1883,
157
+ };
158
+
159
+ const inputWrapper = new WebStreamConnNextWrapper(webInput);
160
+ const outputWrapper = new WebStreamConnNextWrapper(webOutput);
161
+
162
+ const input: ConnNext = {
163
+ remoteAddr: mockAddr,
164
+ localAddr: mockAddr,
165
+ read: (length) => inputWrapper.read(length),
166
+ write: (data) => inputWrapper.write(data),
167
+ [Symbol.asyncIterator]: () => inputWrapper[Symbol.asyncIterator](),
168
+ close: () => {
169
+ inputWrapper.close();
170
+ outputWrapper.close();
171
+ },
172
+ };
173
+
174
+ const output: ConnNext = {
175
+ remoteAddr: mockAddr,
176
+ localAddr: mockAddr,
177
+ read: (length) => outputWrapper.read(length),
178
+ write: (data) => outputWrapper.write(data),
179
+ [Symbol.asyncIterator]: () => outputWrapper[Symbol.asyncIterator](),
180
+ close: () => {
181
+ outputWrapper.close();
182
+ inputWrapper.close();
183
+ },
184
+ };
185
+
186
+ return { input, output };
187
+ }
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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"}