@seriousme/opifex 1.10.1 → 1.11.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/README.md +5 -5
- package/benchmarks/bombing.ts +35 -0
- package/benchmarks/throughputCounter.ts +31 -0
- package/benchmarks/utils.ts +32 -0
- package/bin/mqtt.ts +1 -1
- package/client/client.ts +33 -17
- package/client/context.ts +33 -18
- package/client/deps.ts +1 -2
- package/client/handlers/handlePublish.ts +2 -2
- package/client/handlers/handlePubrel.ts +1 -1
- package/deno/tcpClient.ts +1 -1
- package/deno/tcpServer.test.ts +0 -1
- package/dev_utils/dummyConn.ts +5 -5
- package/dev_utils/mod.ts +1 -0
- package/dev_utils/timers.ts +51 -0
- package/dist/bin/mqtt.js +1 -1
- package/dist/bin/mqtt.js.map +1 -1
- package/dist/client/client.d.ts +11 -7
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +26 -16
- package/dist/client/client.js.map +1 -1
- package/dist/client/context.d.ts +7 -5
- package/dist/client/context.d.ts.map +1 -1
- package/dist/client/context.js +28 -16
- package/dist/client/context.js.map +1 -1
- package/dist/client/deps.d.ts +1 -2
- package/dist/client/deps.d.ts.map +1 -1
- package/dist/client/deps.js +1 -2
- package/dist/client/deps.js.map +1 -1
- package/dist/client/handlers/handlePublish.js +2 -2
- package/dist/client/handlers/handlePublish.js.map +1 -1
- package/dist/client/handlers/handlePubrel.js +1 -1
- package/dist/client/handlers/handlePubrel.js.map +1 -1
- package/dist/mqttConn/mqttConn.d.ts +2 -7
- package/dist/mqttConn/mqttConn.d.ts.map +1 -1
- package/dist/mqttConn/mqttConn.js +18 -11
- package/dist/mqttConn/mqttConn.js.map +1 -1
- package/dist/mqttPacket/auth.d.ts +6 -6
- package/dist/mqttPacket/auth.d.ts.map +1 -1
- package/dist/mqttPacket/auth.js.map +1 -1
- package/dist/mqttPacket/connack.d.ts +4 -4
- package/dist/mqttPacket/connack.d.ts.map +1 -1
- package/dist/mqttPacket/connect.d.ts +3 -3
- package/dist/mqttPacket/connect.d.ts.map +1 -1
- package/dist/mqttPacket/disconnect.d.ts +4 -4
- package/dist/mqttPacket/disconnect.d.ts.map +1 -1
- package/dist/mqttPacket/mod.d.ts +1 -0
- package/dist/mqttPacket/mod.d.ts.map +1 -1
- package/dist/mqttPacket/mod.js +1 -0
- package/dist/mqttPacket/mod.js.map +1 -1
- package/dist/mqttPacket/protocolLevels.d.ts +5 -4
- package/dist/mqttPacket/protocolLevels.d.ts.map +1 -1
- package/dist/mqttPacket/protocolLevels.js +1 -1
- package/dist/mqttPacket/protocolLevels.js.map +1 -1
- package/dist/mqttPacket/pubblishAcks.d.ts +15 -8
- package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -1
- package/dist/mqttPacket/pubblishAcks.js.map +1 -1
- package/dist/mqttPacket/suback.d.ts +4 -4
- package/dist/mqttPacket/suback.d.ts.map +1 -1
- package/dist/mqttPacket/subscribe.d.ts +3 -3
- package/dist/mqttPacket/subscribe.d.ts.map +1 -1
- package/dist/mqttPacket/types.d.ts +3 -0
- package/dist/mqttPacket/types.d.ts.map +1 -1
- package/dist/mqttPacket/unsuback.d.ts +4 -4
- package/dist/mqttPacket/unsuback.d.ts.map +1 -1
- package/dist/mqttPacket/unsubscribe.d.ts +3 -3
- package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
- package/dist/mqttPacket/validators.d.ts +15 -0
- package/dist/mqttPacket/validators.d.ts.map +1 -1
- package/dist/mqttPacket/validators.js +15 -0
- package/dist/mqttPacket/validators.js.map +1 -1
- package/dist/node/tcpClient.js +1 -1
- package/dist/node/tcpClient.js.map +1 -1
- package/dist/persistence/memory/memoryPersistence.js +1 -1
- package/dist/persistence/memory/memoryPersistence.js.map +1 -1
- package/dist/utils/{asyncQueue.d.ts → BufferedAsyncIterable.d.ts} +9 -11
- package/dist/utils/BufferedAsyncIterable.d.ts.map +1 -0
- package/dist/utils/BufferedAsyncIterable.js +70 -0
- package/dist/utils/BufferedAsyncIterable.js.map +1 -0
- package/dist/utils/logger.d.ts +5 -15
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +7 -8
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/mod.d.ts +1 -2
- package/dist/utils/mod.d.ts.map +1 -1
- package/dist/utils/mod.js +1 -2
- package/dist/utils/mod.js.map +1 -1
- package/dist/utils/queue.d.ts +43 -0
- package/dist/utils/queue.d.ts.map +1 -0
- package/dist/utils/queue.js +63 -0
- package/dist/utils/queue.js.map +1 -0
- package/dist/utils/utils.d.ts +2 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +6 -0
- package/dist/utils/utils.js.map +1 -0
- package/examples/tcpServer.test.ts +0 -1
- package/mqttConn/mqttConn.test.ts +5 -4
- package/mqttConn/mqttConn.ts +19 -15
- package/mqttPacket/auth.ts +6 -7
- package/mqttPacket/connack.ts +4 -4
- package/mqttPacket/connect.ts +3 -3
- package/mqttPacket/disconnect.ts +4 -4
- package/mqttPacket/mod.ts +1 -0
- package/mqttPacket/protocolLevels.ts +2 -2
- package/mqttPacket/pubblishAcks.ts +15 -9
- package/mqttPacket/suback.ts +4 -4
- package/mqttPacket/subscribe.ts +3 -3
- package/mqttPacket/types.ts +3 -0
- package/mqttPacket/unsuback.ts +4 -4
- package/mqttPacket/unsubscribe.ts +3 -3
- package/mqttPacket/validators.ts +15 -0
- package/node/tcpClient.ts +1 -1
- package/node/tcpServer.test.ts +0 -1
- package/package.json +1 -1
- package/persistence/memory/memoryPersistence.ts +1 -1
- package/server/test/handleConnect.test.ts +11 -8
- package/utils/BufferedAsyncIterable.ts +76 -0
- package/utils/logger.ts +12 -11
- package/utils/mod.ts +1 -2
- package/utils/queue.ts +66 -0
- package/utils/utils.ts +6 -0
- package/dist/utils/asyncQueue.d.ts.map +0 -1
- package/dist/utils/asyncQueue.js +0 -70
- package/dist/utils/asyncQueue.js.map +0 -1
- package/dist/utils/nextTick.d.ts +0 -17
- package/dist/utils/nextTick.d.ts.map +0 -1
- package/dist/utils/nextTick.js +0 -19
- package/dist/utils/nextTick.js.map +0 -1
- package/utils/asyncQueue.ts +0 -75
- package/utils/nextTick.ts +0 -18
package/dist/utils/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../utils/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../utils/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple queue implementation using an array.
|
|
3
|
+
* This implementation optimizes for O(1) enqueue and dequeue operations
|
|
4
|
+
* by avoiding array shifts, which are O(n).
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ```ts
|
|
8
|
+
* const queue = new ArrayQueue<number>();
|
|
9
|
+
* queue.enqueue(1);
|
|
10
|
+
* queue.enqueue(2);
|
|
11
|
+
* console.log(queue.dequeue()); // 1
|
|
12
|
+
* console.log(queue.size()); // 1
|
|
13
|
+
* console.log(queue.isEmpty()); // false
|
|
14
|
+
* queue.dequeue();
|
|
15
|
+
* console.log(queue.isEmpty()); // true
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class ArrayQueue<T> {
|
|
19
|
+
private items;
|
|
20
|
+
private headIndex;
|
|
21
|
+
/**
|
|
22
|
+
* size is the difference between the actual array length and the index offset
|
|
23
|
+
* @returns the number of items in the queue
|
|
24
|
+
*/
|
|
25
|
+
size(): number;
|
|
26
|
+
/**
|
|
27
|
+
* isEmpty checks if the queue has no items
|
|
28
|
+
* @returns true if the queue is empty
|
|
29
|
+
*/
|
|
30
|
+
isEmpty(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* enqueue adds an item to the end of the queue
|
|
33
|
+
* O(1) - Push to the end is highly optimized in V8.
|
|
34
|
+
*/
|
|
35
|
+
enqueue(data: T): void;
|
|
36
|
+
/**
|
|
37
|
+
* dequeue removes and returns the item at the front of the queue
|
|
38
|
+
* O(1) - Avoids array shifting by incrementing the index.
|
|
39
|
+
* @returns the item at the front of the queue or undefined if the queue is empty
|
|
40
|
+
*/
|
|
41
|
+
dequeue(): T | undefined;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../utils/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,SAAS,CAAa;IAE9B;;;OAGG;IACI,IAAI,IAAI,MAAM;IAGrB;;;OAGG;IACI,OAAO,IAAI,OAAO;IAGzB;;;OAGG;IACI,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAG7B;;;;OAIG;IACI,OAAO,IAAI,CAAC,GAAG,SAAS;CAiBhC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple queue implementation using an array.
|
|
3
|
+
* This implementation optimizes for O(1) enqueue and dequeue operations
|
|
4
|
+
* by avoiding array shifts, which are O(n).
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ```ts
|
|
8
|
+
* const queue = new ArrayQueue<number>();
|
|
9
|
+
* queue.enqueue(1);
|
|
10
|
+
* queue.enqueue(2);
|
|
11
|
+
* console.log(queue.dequeue()); // 1
|
|
12
|
+
* console.log(queue.size()); // 1
|
|
13
|
+
* console.log(queue.isEmpty()); // false
|
|
14
|
+
* queue.dequeue();
|
|
15
|
+
* console.log(queue.isEmpty()); // true
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class ArrayQueue {
|
|
19
|
+
items = [];
|
|
20
|
+
headIndex = 0; // Tracks the front of the queue
|
|
21
|
+
/**
|
|
22
|
+
* size is the difference between the actual array length and the index offset
|
|
23
|
+
* @returns the number of items in the queue
|
|
24
|
+
*/
|
|
25
|
+
size() {
|
|
26
|
+
return this.items.length - this.headIndex;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* isEmpty checks if the queue has no items
|
|
30
|
+
* @returns true if the queue is empty
|
|
31
|
+
*/
|
|
32
|
+
isEmpty() {
|
|
33
|
+
return this.size() === 0;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* enqueue adds an item to the end of the queue
|
|
37
|
+
* O(1) - Push to the end is highly optimized in V8.
|
|
38
|
+
*/
|
|
39
|
+
enqueue(data) {
|
|
40
|
+
this.items.push(data);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* dequeue removes and returns the item at the front of the queue
|
|
44
|
+
* O(1) - Avoids array shifting by incrementing the index.
|
|
45
|
+
* @returns the item at the front of the queue or undefined if the queue is empty
|
|
46
|
+
*/
|
|
47
|
+
dequeue() {
|
|
48
|
+
if (this.isEmpty()) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const item = this.items[this.headIndex];
|
|
52
|
+
this.headIndex++; // Move the "front" marker forward
|
|
53
|
+
// Optimization: Periodically "clean up" the dead space
|
|
54
|
+
// when the empty space (headIndex) exceeds a threshold.
|
|
55
|
+
// This amortizes the cost, keeping average time closer to O(1).
|
|
56
|
+
if (this.headIndex > 2000 && this.headIndex > this.items.length / 4) {
|
|
57
|
+
this.items = this.items.slice(this.headIndex);
|
|
58
|
+
this.headIndex = 0;
|
|
59
|
+
}
|
|
60
|
+
return item;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../utils/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,OAAO,UAAU;IACb,KAAK,GAAQ,EAAE,CAAC;IAChB,SAAS,GAAW,CAAC,CAAC,CAAC,gCAAgC;IAE/D;;;OAGG;IACI,IAAI;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5C,CAAC;IACD;;;OAGG;IACI,OAAO;QACZ,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD;;;OAGG;IACI,OAAO,CAAC,IAAO;QACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD;;;;OAIG;IACI,OAAO;QACZ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,kCAAkC;QAEpD,uDAAuD;QACvD,wDAAwD;QACxD,gEAAgE;QAChE,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9C,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,IAAI,YAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC"}
|
|
@@ -56,7 +56,7 @@ test("MqttConn should act as asyncIterator", async () => {
|
|
|
56
56
|
);
|
|
57
57
|
const mqttConn = new MqttConn({ conn, protocolLevel: 4 });
|
|
58
58
|
|
|
59
|
-
const packets = [];
|
|
59
|
+
const packets: AnyPacket[] = [];
|
|
60
60
|
for await (const packet of mqttConn) {
|
|
61
61
|
packets.push(packet);
|
|
62
62
|
}
|
|
@@ -71,7 +71,7 @@ test("MqttConn should close on malformed length", async () => {
|
|
|
71
71
|
const conn = makeDummySockConn([new Uint8Array([1, 175])], new Uint8Array());
|
|
72
72
|
const mqttConn = new MqttConn({ conn });
|
|
73
73
|
|
|
74
|
-
const packets = [];
|
|
74
|
+
const packets: AnyPacket[] = [];
|
|
75
75
|
for await (const packet of mqttConn) {
|
|
76
76
|
packets.push(packet);
|
|
77
77
|
}
|
|
@@ -89,7 +89,7 @@ test("MqttConn should close on failed packets", async () => {
|
|
|
89
89
|
const conn = makeDummySockConn([connect, brokenPublish], new Uint8Array());
|
|
90
90
|
const mqttConn = new MqttConn({ conn });
|
|
91
91
|
|
|
92
|
-
const packets = [];
|
|
92
|
+
const packets: AnyPacket[] = [];
|
|
93
93
|
for await (const packet of mqttConn) {
|
|
94
94
|
packets.push(packet);
|
|
95
95
|
}
|
|
@@ -105,7 +105,8 @@ test("MqttConn should close on packets too large", async () => {
|
|
|
105
105
|
|
|
106
106
|
const conn = makeDummySockConn([connect], new Uint8Array());
|
|
107
107
|
const mqttConn = new MqttConn({ conn, maxIncomingPacketSize: 20 });
|
|
108
|
-
|
|
108
|
+
|
|
109
|
+
const packets: AnyPacket[] = [];
|
|
109
110
|
for await (const packet of mqttConn) {
|
|
110
111
|
packets.push(packet);
|
|
111
112
|
}
|
package/mqttConn/mqttConn.ts
CHANGED
|
@@ -41,8 +41,6 @@ export interface IMqttConn extends AsyncIterable<AnyPacket> {
|
|
|
41
41
|
readonly isClosed: boolean;
|
|
42
42
|
/** Reason for connection closure if any */
|
|
43
43
|
readonly reason: string | undefined;
|
|
44
|
-
/** Async iterator for receiving packets */
|
|
45
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<AnyPacket>;
|
|
46
44
|
/** Send an MQTT packet */
|
|
47
45
|
send(data: AnyPacket): Promise<void>;
|
|
48
46
|
/** Close the connection */
|
|
@@ -166,27 +164,33 @@ export class MqttConn implements IMqttConn {
|
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
167
|
+
* Returns incoming MQTT packages until the connection is closed. Note that
|
|
168
|
+
* the connection will close automatically upon receiving an invalid packet.
|
|
169
|
+
*
|
|
170
|
+
* @returns a Promise that resolves to AnyPacket if the connection is open
|
|
171
|
+
* and working nominally, undefined otherwise.
|
|
171
172
|
*/
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
yield await readPacket(
|
|
176
|
-
this.conn,
|
|
177
|
-
this.codecOpts,
|
|
178
|
-
);
|
|
179
|
-
} catch (err) {
|
|
173
|
+
#receive(): Promise<AnyPacket | undefined> {
|
|
174
|
+
if (!this._isClosed) {
|
|
175
|
+
return readPacket(this.conn, this.codecOpts).catch((err) => {
|
|
180
176
|
if (err instanceof Error) {
|
|
181
177
|
if (err.name === "PartialReadError") {
|
|
182
178
|
err.message = MqttConnError.UnexpectedEof;
|
|
183
179
|
}
|
|
184
180
|
this._reason = err.message;
|
|
185
181
|
}
|
|
186
|
-
// packet too large, malformed packet or connection closed
|
|
182
|
+
// packet too large, malformed packet or connection closed.
|
|
187
183
|
this.close();
|
|
188
|
-
|
|
189
|
-
}
|
|
184
|
+
return undefined;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return Promise.resolve(undefined);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async *[Symbol.asyncIterator](): AsyncIterator<AnyPacket> {
|
|
191
|
+
let packet: AnyPacket | undefined;
|
|
192
|
+
while ((packet = await this.#receive()) !== undefined) {
|
|
193
|
+
yield packet;
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
|
package/mqttPacket/auth.ts
CHANGED
|
@@ -5,13 +5,6 @@ import { Decoder, DecoderError, hasEmptyFlags } from "./decoder.ts";
|
|
|
5
5
|
import type { TReasonCode } from "./ReasonCode.ts";
|
|
6
6
|
import type { AuthProperties } from "./Properties.ts";
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* An AUTH packet is sent from Client to Server or Server to Client as part of an extended
|
|
10
|
-
* authentication exchange, such as challenge / response authentication.
|
|
11
|
-
* It is a Protocol Error for the Client or Server to send an AUTH packet
|
|
12
|
-
* if the CONNECT packet did not contain the same Authentication Method.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
8
|
// AuthPacket does not exist on protocol levels < 5
|
|
16
9
|
export type AuthPacketV5 = {
|
|
17
10
|
type: TPacketType;
|
|
@@ -20,6 +13,12 @@ export type AuthPacketV5 = {
|
|
|
20
13
|
properties?: AuthProperties;
|
|
21
14
|
};
|
|
22
15
|
|
|
16
|
+
/**
|
|
17
|
+
* An AUTH packet is sent from Client to Server or Server to Client as part of an extended
|
|
18
|
+
* authentication exchange, such as challenge / response authentication.
|
|
19
|
+
* It is a Protocol Error for the Client or Server to send an AUTH packet
|
|
20
|
+
* if the CONNECT packet did not contain the same Authentication Method.
|
|
21
|
+
*/
|
|
23
22
|
export type AuthPacket = AuthPacketV5;
|
|
24
23
|
|
|
25
24
|
export const auth: {
|
package/mqttPacket/connack.ts
CHANGED
|
@@ -17,10 +17,6 @@ import { AuthenticationResultByNumber } from "./AuthenticationResult.ts";
|
|
|
17
17
|
import type { TReasonCode } from "./ReasonCode.ts";
|
|
18
18
|
import type { ConnackProperties } from "./Properties.ts";
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* ConnackPacket is sent from the server to the client in response to a connect packet.
|
|
22
|
-
* It indicates that the connect is accepted.
|
|
23
|
-
*/
|
|
24
20
|
export type ConnackPacketV4 = {
|
|
25
21
|
type: TPacketType;
|
|
26
22
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -36,6 +32,10 @@ export type ConnackPacketV5 = {
|
|
|
36
32
|
properties?: ConnackProperties;
|
|
37
33
|
};
|
|
38
34
|
|
|
35
|
+
/**
|
|
36
|
+
* ConnackPacket is sent from the server to the client in response to a connect packet.
|
|
37
|
+
* It indicates that the connect is accepted.
|
|
38
|
+
*/
|
|
39
39
|
export type ConnackPacket = ConnackPacketV4 | ConnackPacketV5;
|
|
40
40
|
|
|
41
41
|
export const connack: {
|
package/mqttPacket/connect.ts
CHANGED
|
@@ -20,9 +20,6 @@ import {
|
|
|
20
20
|
hasEmptyFlags,
|
|
21
21
|
} from "./decoder.ts";
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
* ConnectPacket is sent from the client to the server to initiate a connection.
|
|
25
|
-
*/
|
|
26
23
|
export type ConnectPacketV4 = {
|
|
27
24
|
type: TPacketType;
|
|
28
25
|
protocolName?: string;
|
|
@@ -61,6 +58,9 @@ export type ConnectPacketV5 = {
|
|
|
61
58
|
properties?: ConnectProperties;
|
|
62
59
|
};
|
|
63
60
|
|
|
61
|
+
/**
|
|
62
|
+
* ConnectPacket is sent from the client to the server to initiate a connection.
|
|
63
|
+
*/
|
|
64
64
|
export type ConnectPacket = ConnectPacketV4 | ConnectPacketV5;
|
|
65
65
|
|
|
66
66
|
function invalidProtocolName(version: number, name: string): boolean {
|
package/mqttPacket/disconnect.ts
CHANGED
|
@@ -10,10 +10,6 @@ import type { DisconnectProperties } from "./Properties.ts";
|
|
|
10
10
|
import { Encoder } from "./encoder.ts";
|
|
11
11
|
import { ReasonCode } from "./ReasonCode.ts";
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* DisconnectPacket is the final control packet sent from the client to the server.
|
|
15
|
-
* It indicates that the client is disconnecting cleanly.
|
|
16
|
-
*/
|
|
17
13
|
export type DisconnectPacketv4 = {
|
|
18
14
|
type: TPacketType;
|
|
19
15
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -26,6 +22,10 @@ export type DisconnectPacketv5 = {
|
|
|
26
22
|
properties?: DisconnectProperties;
|
|
27
23
|
};
|
|
28
24
|
|
|
25
|
+
/**
|
|
26
|
+
* DisconnectPacket is the final control packet sent from the client to the server.
|
|
27
|
+
* It indicates that the client is disconnecting cleanly.
|
|
28
|
+
*/
|
|
29
29
|
export type DisconnectPacket = DisconnectPacketv4 | DisconnectPacketv5;
|
|
30
30
|
|
|
31
31
|
const DISCONNECT_PACKET = new Uint8Array([PacketType.disconnect << 4, 0]);
|
package/mqttPacket/mod.ts
CHANGED
|
@@ -209,6 +209,7 @@ export function decodePayload(
|
|
|
209
209
|
/**
|
|
210
210
|
* @function decode
|
|
211
211
|
* @description Decodes a complete MQTT packet from binary format into a packet object
|
|
212
|
+
*
|
|
212
213
|
* @param {Uint8Array} buffer - The binary buffer containing the complete MQTT packet
|
|
213
214
|
* @param {CodecOpts} codecOpts - the options for the decoder
|
|
214
215
|
* @returns {AnyPacket} The decoded MQTT packet object
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ProtocolLevel } from "./types.ts";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** available MQTT Protocol levels */
|
|
8
8
|
export const MQTTLevel = {
|
|
9
9
|
unknown: undefined as ProtocolLevel,
|
|
10
10
|
v3: 3 as ProtocolLevel,
|
|
11
11
|
v4: 4 as ProtocolLevel,
|
|
12
12
|
v5: 5 as ProtocolLevel,
|
|
13
|
-
};
|
|
13
|
+
} as const;
|
|
@@ -10,14 +10,6 @@ import { PacketType } from "./PacketType.ts";
|
|
|
10
10
|
import { Decoder, DecoderError } from "./decoder.ts";
|
|
11
11
|
import { Encoder } from "./encoder.ts";
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* PubackPacket is sent to indicate publish complete (QoS 1)
|
|
15
|
-
* Pubrec is sent to indicate publish received (QoS 2)
|
|
16
|
-
* Pubrel is sent to indicate publish release (QoS 2)
|
|
17
|
-
* Pubcomp is sent to indicate publish complete (QoS 2)
|
|
18
|
-
*
|
|
19
|
-
* all 4 packets are identical except for packet type
|
|
20
|
-
*/
|
|
21
13
|
export type AckPacketV4<T> = {
|
|
22
14
|
type: TPacketType;
|
|
23
15
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -31,11 +23,25 @@ export type AckPacketV5<T> = {
|
|
|
31
23
|
reasonCode?: TReasonCode;
|
|
32
24
|
properties?: PubackProperties;
|
|
33
25
|
};
|
|
34
|
-
|
|
26
|
+
/**
|
|
27
|
+
* all 4 ack packets are identical except for packet type and flags of Pubrel
|
|
28
|
+
*/
|
|
35
29
|
export type AckPacket<T> = AckPacketV4<T> | AckPacketV5<T>;
|
|
30
|
+
/**
|
|
31
|
+
* PubackPacket is sent to indicate publish complete (QoS 1)
|
|
32
|
+
*/
|
|
36
33
|
export type PubackPacket = AckPacket<typeof PacketType.puback>;
|
|
34
|
+
/**
|
|
35
|
+
* Pubrec is sent to indicate publish received (QoS 2)
|
|
36
|
+
*/
|
|
37
37
|
export type PubrecPacket = AckPacket<typeof PacketType.pubrec>;
|
|
38
|
+
/**
|
|
39
|
+
* Pubrel is sent to indicate publish release (QoS 2)
|
|
40
|
+
*/
|
|
38
41
|
export type PubrelPacket = AckPacket<typeof PacketType.pubrel>;
|
|
42
|
+
/**
|
|
43
|
+
* Pubcomp is sent to indicate publish complete (QoS 2)
|
|
44
|
+
*/
|
|
39
45
|
export type PubcompPacket = AckPacket<typeof PacketType.pubcomp>;
|
|
40
46
|
|
|
41
47
|
export type AnyAckPacket =
|
package/mqttPacket/suback.ts
CHANGED
|
@@ -12,10 +12,6 @@ import { Encoder } from "./encoder.ts";
|
|
|
12
12
|
import { Decoder, DecoderError } from "./decoder.ts";
|
|
13
13
|
const validReturnCodes = [0x00, 0x01, 0x02, 0x80];
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* SubackPacket is sent by the server to the client to confirm receipt and
|
|
17
|
-
* processing of a SubscribePacket.
|
|
18
|
-
*/
|
|
19
15
|
export type SubackPacketV4 = {
|
|
20
16
|
type: TPacketType;
|
|
21
17
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -31,6 +27,10 @@ export type SubackPacketV5 = {
|
|
|
31
27
|
reasonCodes: Array<TReasonCode>;
|
|
32
28
|
};
|
|
33
29
|
|
|
30
|
+
/**
|
|
31
|
+
* SubackPacket is sent by the server to the client to confirm receipt and
|
|
32
|
+
* processing of a SubscribePacket.
|
|
33
|
+
*/
|
|
34
34
|
export type SubackPacket = SubackPacketV4 | SubackPacketV5;
|
|
35
35
|
|
|
36
36
|
export const suback: {
|
package/mqttPacket/subscribe.ts
CHANGED
|
@@ -13,9 +13,6 @@ import { BitMask } from "./BitMask.ts";
|
|
|
13
13
|
import { Encoder } from "./encoder.ts";
|
|
14
14
|
import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* SubscribePacket is sent from client to server to subscribe to topics
|
|
18
|
-
*/
|
|
19
16
|
export type SubscribePacketV4 = {
|
|
20
17
|
type: TPacketType;
|
|
21
18
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -31,6 +28,9 @@ export type SubscribePacketV5 = {
|
|
|
31
28
|
subscriptions: Array<SubscriptionV5>;
|
|
32
29
|
};
|
|
33
30
|
|
|
31
|
+
/**
|
|
32
|
+
* SubscribePacket is sent from client to server to subscribe to topics
|
|
33
|
+
*/
|
|
34
34
|
export type SubscribePacket = SubscribePacketV4 | SubscribePacketV5;
|
|
35
35
|
/**
|
|
36
36
|
* The topic to subscribe to and the associated QoS
|
package/mqttPacket/types.ts
CHANGED
package/mqttPacket/unsuback.ts
CHANGED
|
@@ -10,10 +10,6 @@ import { PacketType } from "./PacketType.ts";
|
|
|
10
10
|
import { Decoder, hasEmptyFlags } from "./decoder.ts";
|
|
11
11
|
import { Encoder } from "./encoder.ts";
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* UnsubackPacket is sent by the server to the client to confirm receipt
|
|
15
|
-
* of an UnsubscribePacket.
|
|
16
|
-
*/
|
|
17
13
|
export type UnsubackPacketV4 = {
|
|
18
14
|
type: TPacketType;
|
|
19
15
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -28,6 +24,10 @@ export type UnsubackPacketV5 = {
|
|
|
28
24
|
reasonCodes: Array<TReasonCode>;
|
|
29
25
|
};
|
|
30
26
|
|
|
27
|
+
/**
|
|
28
|
+
* UnsubackPacket is sent by the server to the client to confirm receipt
|
|
29
|
+
* of an UnsubscribePacket.
|
|
30
|
+
*/
|
|
31
31
|
export type UnsubackPacket = UnsubackPacketV4 | UnsubackPacketV5;
|
|
32
32
|
|
|
33
33
|
export const unsuback: {
|
|
@@ -11,9 +11,6 @@ import { PacketType } from "./PacketType.ts";
|
|
|
11
11
|
import { Encoder } from "./encoder.ts";
|
|
12
12
|
import { Decoder, DecoderError } from "./decoder.ts";
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* UnsubscribePacket is sent from client to server to unsubscribe from topics
|
|
16
|
-
*/
|
|
17
14
|
export type UnsubscribePacketV4 = {
|
|
18
15
|
type: TPacketType;
|
|
19
16
|
protocolLevel: ProtocolLevelNoV5;
|
|
@@ -29,6 +26,9 @@ export type UnsubscribePacketV5 = {
|
|
|
29
26
|
topicFilters: TopicFilter[];
|
|
30
27
|
};
|
|
31
28
|
|
|
29
|
+
/**
|
|
30
|
+
* UnsubscribePacket is sent from client to server to unsubscribe from topics
|
|
31
|
+
*/
|
|
32
32
|
export type UnsubscribePacket = UnsubscribePacketV4 | UnsubscribePacketV5;
|
|
33
33
|
|
|
34
34
|
export const unsubscribe: {
|
package/mqttPacket/validators.ts
CHANGED
|
@@ -7,14 +7,29 @@ const invalidTopicRegEx = new RegExp(/^$|\+|#|\x00|\uFFFD/);
|
|
|
7
7
|
// deno-lint-ignore no-control-regex
|
|
8
8
|
const invalidTopicFilterRegEx = new RegExp(/^$|#.|[^\/]\+|\+[^\/]|\x00|\uFFFD/);
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* check for invalid UTF-8 characters
|
|
12
|
+
* @param value string to test
|
|
13
|
+
* @returns true if the string contains invalid UTF-8 characters
|
|
14
|
+
*/
|
|
10
15
|
export function invalidUTF8(value: string): boolean {
|
|
11
16
|
return invalidUTF8regEx.test(value);
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* check for invalid topic characters
|
|
21
|
+
* @param value
|
|
22
|
+
* @returns true if the topic is invalid
|
|
23
|
+
*/
|
|
14
24
|
export function invalidTopic(value: Topic): boolean {
|
|
15
25
|
return invalidTopicRegEx.test(value);
|
|
16
26
|
}
|
|
17
27
|
|
|
28
|
+
/**
|
|
29
|
+
* check for invalid topic filter characters
|
|
30
|
+
* @param value topic filter to test
|
|
31
|
+
* @returns true if the topic filter is invalid
|
|
32
|
+
*/
|
|
18
33
|
export function invalidTopicFilter(value: TopicFilter): boolean {
|
|
19
34
|
return invalidTopicFilterRegEx.test(value);
|
|
20
35
|
}
|
package/node/tcpClient.ts
CHANGED
package/node/tcpServer.test.ts
CHANGED
package/package.json
CHANGED
|
@@ -134,7 +134,7 @@ export class MemoryPersistence implements IPersistence {
|
|
|
134
134
|
newPacket.qos = qos;
|
|
135
135
|
// logger.debug(`publish ${topic} to client ${clientId}`);
|
|
136
136
|
const client = this.clientList.get(clientId);
|
|
137
|
-
client?.handler(
|
|
137
|
+
client?.handler(newPacket);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { test } from "node:test";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
makeDummyQueueSockConn,
|
|
5
|
+
resolveNextTick,
|
|
6
|
+
} from "../../dev_utils/mod.ts";
|
|
4
7
|
import {
|
|
5
8
|
type AnyPacket,
|
|
6
9
|
AuthenticationResult,
|
|
7
10
|
PacketType,
|
|
8
11
|
} from "../../mqttPacket/mod.ts";
|
|
9
|
-
import {
|
|
12
|
+
import { BufferedAsyncIterable } from "../../utils/mod.ts";
|
|
10
13
|
import { MqttConn, MQTTLevel } from "../deps.ts";
|
|
11
14
|
import { MqttServer } from "../mod.ts";
|
|
12
15
|
import { handlers } from "./test-handlers.ts";
|
|
@@ -34,11 +37,11 @@ const disconnectPacket: AnyPacket = {
|
|
|
34
37
|
const mqttServer = new MqttServer({ handlers });
|
|
35
38
|
|
|
36
39
|
function startServer(): {
|
|
37
|
-
reader:
|
|
40
|
+
reader: AsyncIterator<AnyPacket>;
|
|
38
41
|
mqttConn: MqttConn;
|
|
39
42
|
} {
|
|
40
|
-
const reader = new
|
|
41
|
-
const writer = new
|
|
43
|
+
const reader = new BufferedAsyncIterable<Uint8Array>();
|
|
44
|
+
const writer = new BufferedAsyncIterable<Uint8Array>();
|
|
42
45
|
|
|
43
46
|
const outputConn = makeDummyQueueSockConn(writer, reader);
|
|
44
47
|
const mqttConn = new MqttConn({ conn: outputConn });
|
|
@@ -66,7 +69,7 @@ test("Authentication with valid username and password works", async () => {
|
|
|
66
69
|
);
|
|
67
70
|
}
|
|
68
71
|
mqttConn.send(disconnectPacket);
|
|
69
|
-
await
|
|
72
|
+
await resolveNextTick();
|
|
70
73
|
assert.deepStrictEqual(
|
|
71
74
|
mqttConn.isClosed,
|
|
72
75
|
true,
|
|
@@ -92,7 +95,7 @@ test("Authentication with invalid username fails", async () => {
|
|
|
92
95
|
"Expected badUsernameOrPassword",
|
|
93
96
|
);
|
|
94
97
|
}
|
|
95
|
-
await
|
|
98
|
+
await resolveNextTick();
|
|
96
99
|
assert.deepStrictEqual(
|
|
97
100
|
mqttConn.isClosed,
|
|
98
101
|
true,
|
|
@@ -118,7 +121,7 @@ test("Authentication with invalid password fails", async () => {
|
|
|
118
121
|
"Expected badUsernameOrPassword",
|
|
119
122
|
);
|
|
120
123
|
}
|
|
121
|
-
await
|
|
124
|
+
await resolveNextTick();
|
|
122
125
|
assert.deepStrictEqual(
|
|
123
126
|
mqttConn.isClosed,
|
|
124
127
|
true,
|