@seriousme/opifex 1.11.0 → 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.
Files changed (63) hide show
  1. package/README.md +5 -5
  2. package/benchmarks/bombing.ts +35 -0
  3. package/benchmarks/throughputCounter.ts +31 -0
  4. package/benchmarks/utils.ts +32 -0
  5. package/client/client.ts +6 -10
  6. package/client/context.ts +3 -9
  7. package/client/deps.ts +1 -2
  8. package/client/handlers/handlePublish.ts +2 -2
  9. package/client/handlers/handlePubrel.ts +1 -1
  10. package/deno/tcpServer.test.ts +0 -1
  11. package/dev_utils/dummyConn.ts +5 -5
  12. package/dev_utils/mod.ts +1 -0
  13. package/dev_utils/timers.ts +51 -0
  14. package/dist/client/client.d.ts +2 -6
  15. package/dist/client/client.d.ts.map +1 -1
  16. package/dist/client/client.js +6 -9
  17. package/dist/client/client.js.map +1 -1
  18. package/dist/client/context.d.ts +2 -3
  19. package/dist/client/context.d.ts.map +1 -1
  20. package/dist/client/context.js +4 -8
  21. package/dist/client/context.js.map +1 -1
  22. package/dist/client/deps.d.ts +1 -2
  23. package/dist/client/deps.d.ts.map +1 -1
  24. package/dist/client/deps.js +1 -2
  25. package/dist/client/deps.js.map +1 -1
  26. package/dist/client/handlers/handlePublish.js +2 -2
  27. package/dist/client/handlers/handlePublish.js.map +1 -1
  28. package/dist/client/handlers/handlePubrel.js +1 -1
  29. package/dist/client/handlers/handlePubrel.js.map +1 -1
  30. package/dist/mqttConn/mqttConn.d.ts +2 -7
  31. package/dist/mqttConn/mqttConn.d.ts.map +1 -1
  32. package/dist/mqttConn/mqttConn.js +18 -11
  33. package/dist/mqttConn/mqttConn.js.map +1 -1
  34. package/dist/utils/{asyncQueue.d.ts → BufferedAsyncIterable.d.ts} +8 -8
  35. package/dist/utils/BufferedAsyncIterable.d.ts.map +1 -0
  36. package/dist/utils/BufferedAsyncIterable.js +70 -0
  37. package/dist/utils/BufferedAsyncIterable.js.map +1 -0
  38. package/dist/utils/mod.d.ts +1 -2
  39. package/dist/utils/mod.d.ts.map +1 -1
  40. package/dist/utils/mod.js +1 -2
  41. package/dist/utils/mod.js.map +1 -1
  42. package/dist/utils/queue.d.ts +43 -0
  43. package/dist/utils/queue.d.ts.map +1 -0
  44. package/dist/utils/queue.js +63 -0
  45. package/dist/utils/queue.js.map +1 -0
  46. package/examples/tcpServer.test.ts +0 -1
  47. package/mqttConn/mqttConn.test.ts +5 -4
  48. package/mqttConn/mqttConn.ts +19 -15
  49. package/node/tcpServer.test.ts +0 -1
  50. package/package.json +1 -1
  51. package/server/test/handleConnect.test.ts +11 -8
  52. package/utils/BufferedAsyncIterable.ts +76 -0
  53. package/utils/mod.ts +1 -2
  54. package/utils/queue.ts +66 -0
  55. package/dist/utils/asyncQueue.d.ts.map +0 -1
  56. package/dist/utils/asyncQueue.js +0 -65
  57. package/dist/utils/asyncQueue.js.map +0 -1
  58. package/dist/utils/nextTick.d.ts +0 -17
  59. package/dist/utils/nextTick.d.ts.map +0 -1
  60. package/dist/utils/nextTick.js +0 -19
  61. package/dist/utils/nextTick.js.map +0 -1
  62. package/utils/asyncQueue.ts +0 -71
  63. package/utils/nextTick.ts +0 -18
@@ -20,7 +20,7 @@ export async function handlePubrel(ctx, packet) {
20
20
  if (ctx.store.pendingIncoming.has(id)) {
21
21
  const storedPacket = ctx.store.pendingIncoming.get(id);
22
22
  if (storedPacket) {
23
- ctx.receivePublish(storedPacket);
23
+ await ctx.receivePublish(storedPacket);
24
24
  ctx.store.pendingIncoming.delete(id);
25
25
  await ctx.send({
26
26
  type: PacketType.pubcomp,
@@ -1 +1 @@
1
- {"version":3,"file":"handlePubrel.js","sourceRoot":"","sources":["../../../client/handlers/handlePubrel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAY,EACZ,MAAoB;IAEpB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;IACrB,IAAI,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACtC,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,YAAY,EAAE,CAAC;YACjB,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;YACjC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,GAAG,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,UAAU,CAAC,OAAO;gBACxB,aAAa,EAAE,GAAG,CAAC,aAAa;gBAChC,EAAE;aACH,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"handlePubrel.js","sourceRoot":"","sources":["../../../client/handlers/handlePubrel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAY,EACZ,MAAoB;IAEpB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;IACrB,IAAI,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACtC,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;YACvC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,GAAG,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,UAAU,CAAC,OAAO;gBACxB,aAAa,EAAE,GAAG,CAAC,aAAa;gBAChC,EAAE;aACH,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -22,8 +22,6 @@ export interface IMqttConn extends AsyncIterable<AnyPacket> {
22
22
  readonly isClosed: boolean;
23
23
  /** Reason for connection closure if any */
24
24
  readonly reason: string | undefined;
25
- /** Async iterator for receiving packets */
26
- [Symbol.asyncIterator](): AsyncIterableIterator<AnyPacket>;
27
25
  /** Send an MQTT packet */
28
26
  send(data: AnyPacket): Promise<void>;
29
27
  /** Close the connection */
@@ -41,6 +39,7 @@ export declare function readPacket(conn: Conn, codecOpts: CodecOpts): Promise<An
41
39
  * MQTT Connection class implementing IMqttConn interface
42
40
  */
43
41
  export declare class MqttConn implements IMqttConn {
42
+ #private;
44
43
  /** Underlying connection */
45
44
  readonly conn: Conn;
46
45
  /** codecOpts */
@@ -66,11 +65,7 @@ export declare class MqttConn implements IMqttConn {
66
65
  get reason(): string | undefined;
67
66
  /** Get remoteAdress */
68
67
  get remoteAddress(): string;
69
- /**
70
- * Async iterator for receiving packets
71
- * @yields MQTT packets
72
- */
73
- [Symbol.asyncIterator](): AsyncIterableIterator<AnyPacket>;
68
+ [Symbol.asyncIterator](): AsyncIterator<AnyPacket>;
74
69
  /**
75
70
  * Send an MQTT packet
76
71
  * @param data Packet to send
@@ -1 +1 @@
1
- {"version":3,"file":"mqttConn.d.ts","sourceRoot":"","sources":["../../mqttConn/mqttConn.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EAET,aAAa,EACd,MAAM,sBAAsB,CAAC;AAU9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAIX;;GAEG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa,CAAC,SAAS,CAAC;IACzD,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,2CAA2C;IAC3C,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC3D,0BAA0B;IAC1B,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,2BAA2B;IAC3B,KAAK,IAAI,IAAI,CAAC;CACf;AAgCD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,SAAS,CAAC,CAuBpB;AAED;;GAEG;AACH,qBAAa,QAAS,YAAW,SAAS;IACxC,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAiC;IAChD,mCAAmC;IACnC,OAAO,CAAC,SAAS,CAAS;IAE1B;;;;;;;OAOG;gBACS,EACV,IAAI,EACJ,qBAA8C,EAC9C,aAAiC,GAClC,EAAE;QACD,IAAI,EAAE,QAAQ,CAAC;QACf,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,aAAa,CAAC;KAC/B;IASD,wCAAwC;IACxC,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED,uBAAuB;IACvB,IAAI,aAAa,IAAI,MAAM,CAK1B;IAED;;;OAGG;IACI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,SAAS,CAAC;IAqBjE;;;OAGG;IACG,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1C,mCAAmC;IACnC,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,2BAA2B;IAC3B,KAAK,IAAI,IAAI;CAUd"}
1
+ {"version":3,"file":"mqttConn.d.ts","sourceRoot":"","sources":["../../mqttConn/mqttConn.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EAET,aAAa,EACd,MAAM,sBAAsB,CAAC;AAU9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAIX;;GAEG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa,CAAC,SAAS,CAAC;IACzD,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,0BAA0B;IAC1B,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,2BAA2B;IAC3B,KAAK,IAAI,IAAI,CAAC;CACf;AAgCD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,SAAS,CAAC,CAuBpB;AAED;;GAEG;AACH,qBAAa,QAAS,YAAW,SAAS;;IACxC,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,gBAAgB;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAiC;IAChD,mCAAmC;IACnC,OAAO,CAAC,SAAS,CAAS;IAE1B;;;;;;;OAOG;gBACS,EACV,IAAI,EACJ,qBAA8C,EAC9C,aAAiC,GAClC,EAAE;QACD,IAAI,EAAE,QAAQ,CAAC;QACf,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,aAAa,CAAC;KAC/B;IASD,wCAAwC;IACxC,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED,uBAAuB;IACvB,IAAI,aAAa,IAAI,MAAM,CAK1B;IA0BM,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,CAAC;IAOzD;;;OAGG;IACG,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1C,mCAAmC;IACnC,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,2BAA2B;IAC3B,KAAK,IAAI,IAAI;CAUd"}
@@ -108,25 +108,32 @@ export class MqttConn {
108
108
  return "unknown";
109
109
  }
110
110
  /**
111
- * Async iterator for receiving packets
112
- * @yields MQTT packets
111
+ * Returns incoming MQTT packages until the connection is closed. Note that
112
+ * the connection will close automatically upon receiving an invalid packet.
113
+ *
114
+ * @returns a Promise that resolves to AnyPacket if the connection is open
115
+ * and working nominally, undefined otherwise.
113
116
  */
114
- async *[Symbol.asyncIterator]() {
115
- while (!this._isClosed) {
116
- try {
117
- yield await readPacket(this.conn, this.codecOpts);
118
- }
119
- catch (err) {
117
+ #receive() {
118
+ if (!this._isClosed) {
119
+ return readPacket(this.conn, this.codecOpts).catch((err) => {
120
120
  if (err instanceof Error) {
121
121
  if (err.name === "PartialReadError") {
122
122
  err.message = MqttConnError.UnexpectedEof;
123
123
  }
124
124
  this._reason = err.message;
125
125
  }
126
- // packet too large, malformed packet or connection closed
126
+ // packet too large, malformed packet or connection closed.
127
127
  this.close();
128
- break;
129
- }
128
+ return undefined;
129
+ });
130
+ }
131
+ return Promise.resolve(undefined);
132
+ }
133
+ async *[Symbol.asyncIterator]() {
134
+ let packet;
135
+ while ((packet = await this.#receive()) !== undefined) {
136
+ yield packet;
130
137
  }
131
138
  }
132
139
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"mqttConn.js","sourceRoot":"","sources":["../../mqttConn/mqttConn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mqttConn.js","sourceRoot":"","sources":["../../mqttConn/mqttConn.ts"],"names":[],"mappings":"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"}
@@ -11,16 +11,16 @@
11
11
  * }
12
12
  * ```
13
13
  */
14
- export declare class AsyncQueue<T> {
14
+ export declare class BufferedAsyncIterable<T> implements AsyncIterable<T> {
15
15
  #private;
16
- private queue;
17
- private maxQueueLength;
16
+ private buffer;
17
+ private bufferSize;
18
18
  private done;
19
- constructor(maxQueueLength?: number);
20
- next(): Promise<T>;
21
- close(reason?: string): void;
19
+ constructor(bufferSize?: number);
22
20
  [Symbol.asyncIterator](): AsyncGenerator<Awaited<T>, void, unknown>;
23
- push(item: T): void;
21
+ next(): T | Promise<T>;
22
+ close(reason?: string): void;
23
+ readonly push: (item: T) => void | Promise<void>;
24
24
  get isDone(): boolean;
25
25
  }
26
- //# sourceMappingURL=asyncQueue.d.ts.map
26
+ //# sourceMappingURL=BufferedAsyncIterable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BufferedAsyncIterable.d.ts","sourceRoot":"","sources":["../../utils/BufferedAsyncIterable.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAqB,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;;IAC/D,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,IAAI,CAAS;gBAIT,UAAU,GAAE,MAAa;IAK9B,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC;IAM1E,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYtB,KAAK,CAAC,MAAM,SAAW,GAAG,IAAI;IAO9B,QAAQ,CAAC,IAAI,GAAI,MAAM,CAAC,KAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7C;IAEF,IAAI,MAAM,IAAI,OAAO,CAEpB;CACF"}
@@ -0,0 +1,70 @@
1
+ import { Deferred } from "./deferred.js";
2
+ import { ArrayQueue } from "./queue.js";
3
+ /**
4
+ * An Async Queue is a queue that can be used to push items to it and then wait
5
+ * for them to be consumed.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const queue = new AsyncQueue<string>();
10
+ * queue.push("hello");
11
+ * for await (const item of queue) {
12
+ * console.log(item); // "hello"
13
+ * }
14
+ * ```
15
+ */
16
+ export class BufferedAsyncIterable {
17
+ buffer;
18
+ bufferSize;
19
+ done = false;
20
+ #next;
21
+ constructor(bufferSize = 2048) {
22
+ this.buffer = new ArrayQueue();
23
+ this.bufferSize = bufferSize;
24
+ }
25
+ async *[Symbol.asyncIterator]() {
26
+ while (!this.done) {
27
+ yield this.next();
28
+ }
29
+ }
30
+ next() {
31
+ // await nextTick();
32
+ if (this.buffer.size() > 0) {
33
+ return this.buffer.dequeue();
34
+ }
35
+ else if (this.done) {
36
+ throw new Error("Closed");
37
+ }
38
+ else if (!this.#next) {
39
+ this.#next = new Deferred();
40
+ }
41
+ return this.#next.promise;
42
+ }
43
+ close(reason = "closed") {
44
+ this.done = true;
45
+ if (this.#next) {
46
+ this.#next.reject(new Error(reason));
47
+ }
48
+ }
49
+ push = (item) => {
50
+ if (this.#next) {
51
+ this.#next.resolve(item);
52
+ this.#next = undefined;
53
+ return;
54
+ }
55
+ this.buffer.enqueue(item);
56
+ if (this.buffer.size() > this.bufferSize) {
57
+ // If our current buffer has grown greater than the allowed size we adaptively
58
+ // wait for an amount of milliseconds proportional to the size of the buffer.
59
+ // This ensures backpressure is applied to the producer that is pushing items
60
+ // into the queue. Note that this might be an exceedingly simple heuristic,
61
+ // a PID (Proportional-Integral-Derivative) controller could be used to improve
62
+ // the responsiveness of the system.
63
+ return new Promise((resolve) => setTimeout(resolve, this.buffer.size()));
64
+ }
65
+ };
66
+ get isDone() {
67
+ return this.done;
68
+ }
69
+ }
70
+ //# sourceMappingURL=BufferedAsyncIterable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BufferedAsyncIterable.js","sourceRoot":"","sources":["../../utils/BufferedAsyncIterable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,qBAAqB;IACxB,MAAM,CAAgB;IACtB,UAAU,CAAS;IAEnB,IAAI,GAAG,KAAK,CAAC;IAErB,KAAK,CAAe;IAEpB,YAAY,aAAqB,IAAI;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI;QACF,oBAAoB;QACpB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAG,CAAC;QAChC,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,EAAK,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,MAAM,GAAG,QAAQ;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAEQ,IAAI,GAAG,CAAC,IAAO,EAAwB,EAAE;QAChD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,8EAA8E;YAC9E,6EAA6E;YAC7E,6EAA6E;YAC7E,2EAA2E;YAC3E,+EAA+E;YAC/E,oCAAoC;YACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -5,6 +5,5 @@
5
5
  export { assert } from "./assert.ts";
6
6
  export { Deferred } from "./deferred.ts";
7
7
  export { Logger, logger, LogLevel } from "./logger.ts";
8
- export { AsyncQueue } from "./asyncQueue.ts";
9
- export { nextTick } from "./nextTick.ts";
8
+ export { BufferedAsyncIterable } from "./BufferedAsyncIterable.ts";
10
9
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","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,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","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"}
package/dist/utils/mod.js CHANGED
@@ -5,6 +5,5 @@
5
5
  export { assert } from "./assert.js";
6
6
  export { Deferred } from "./deferred.js";
7
7
  export { Logger, logger, LogLevel } from "./logger.js";
8
- export { AsyncQueue } from "./asyncQueue.js";
9
- export { nextTick } from "./nextTick.js";
8
+ export { BufferedAsyncIterable } from "./BufferedAsyncIterable.js";
10
9
  //# sourceMappingURL=mod.js.map
@@ -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,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
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"}
@@ -72,7 +72,6 @@ test("Test pubSub using client and server", async function () {
72
72
 
73
73
  await sleep(100);
74
74
  logger.verbose(`Disconnect client`);
75
- //client.closeMessages();
76
75
  await client.disconnect();
77
76
 
78
77
  logger.verbose(`Check completeness`);
@@ -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
- const packets = [];
108
+
109
+ const packets: AnyPacket[] = [];
109
110
  for await (const packet of mqttConn) {
110
111
  packets.push(packet);
111
112
  }
@@ -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
- * Async iterator for receiving packets
170
- * @yields MQTT packets
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
- async *[Symbol.asyncIterator](): AsyncIterableIterator<AnyPacket> {
173
- while (!this._isClosed) {
174
- try {
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
- break;
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
 
@@ -72,7 +72,6 @@ test("Test pubSub using client and server", async function () {
72
72
 
73
73
  await sleep(100);
74
74
  logger.verbose(`Disconnect client`);
75
- //client.closeMessages();
76
75
  await client.disconnect();
77
76
 
78
77
  logger.verbose(`Check completeness`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seriousme/opifex",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "MQTT client & server for Deno & NodeJS",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,12 +1,15 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { test } from "node:test";
3
- import { makeDummyQueueSockConn } from "../../dev_utils/mod.ts";
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 { AsyncQueue, nextTick } from "../../utils/mod.ts";
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: AsyncIterableIterator<AnyPacket>;
40
+ reader: AsyncIterator<AnyPacket>;
38
41
  mqttConn: MqttConn;
39
42
  } {
40
- const reader = new AsyncQueue<Uint8Array>();
41
- const writer = new AsyncQueue<Uint8Array>();
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 nextTick();
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 nextTick();
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 nextTick();
124
+ await resolveNextTick();
122
125
  assert.deepStrictEqual(
123
126
  mqttConn.isClosed,
124
127
  true,
@@ -0,0 +1,76 @@
1
+ import { Deferred } from "./deferred.ts";
2
+ import { ArrayQueue } from "./queue.ts";
3
+
4
+ /**
5
+ * An Async Queue is a queue that can be used to push items to it and then wait
6
+ * for them to be consumed.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const queue = new AsyncQueue<string>();
11
+ * queue.push("hello");
12
+ * for await (const item of queue) {
13
+ * console.log(item); // "hello"
14
+ * }
15
+ * ```
16
+ */
17
+ export class BufferedAsyncIterable<T> implements AsyncIterable<T> {
18
+ private buffer: ArrayQueue<T>;
19
+ private bufferSize: number;
20
+
21
+ private done = false;
22
+
23
+ #next?: Deferred<T>;
24
+
25
+ constructor(bufferSize: number = 2048) {
26
+ this.buffer = new ArrayQueue();
27
+ this.bufferSize = bufferSize;
28
+ }
29
+
30
+ async *[Symbol.asyncIterator](): AsyncGenerator<Awaited<T>, void, unknown> {
31
+ while (!this.done) {
32
+ yield this.next();
33
+ }
34
+ }
35
+
36
+ next(): T | Promise<T> {
37
+ // await nextTick();
38
+ if (this.buffer.size() > 0) {
39
+ return this.buffer.dequeue()!;
40
+ } else if (this.done) {
41
+ throw new Error("Closed");
42
+ } else if (!this.#next) {
43
+ this.#next = new Deferred<T>();
44
+ }
45
+ return this.#next.promise;
46
+ }
47
+
48
+ close(reason = "closed"): void {
49
+ this.done = true;
50
+ if (this.#next) {
51
+ this.#next.reject(new Error(reason));
52
+ }
53
+ }
54
+
55
+ readonly push = (item: T): void | Promise<void> => {
56
+ if (this.#next) {
57
+ this.#next.resolve(item);
58
+ this.#next = undefined;
59
+ return;
60
+ }
61
+ this.buffer.enqueue(item);
62
+ if (this.buffer.size() > this.bufferSize) {
63
+ // If our current buffer has grown greater than the allowed size we adaptively
64
+ // wait for an amount of milliseconds proportional to the size of the buffer.
65
+ // This ensures backpressure is applied to the producer that is pushing items
66
+ // into the queue. Note that this might be an exceedingly simple heuristic,
67
+ // a PID (Proportional-Integral-Derivative) controller could be used to improve
68
+ // the responsiveness of the system.
69
+ return new Promise((resolve) => setTimeout(resolve, this.buffer.size()));
70
+ }
71
+ };
72
+
73
+ get isDone(): boolean {
74
+ return this.done;
75
+ }
76
+ }
package/utils/mod.ts CHANGED
@@ -5,5 +5,4 @@
5
5
  export { assert } from "./assert.ts";
6
6
  export { Deferred } from "./deferred.ts";
7
7
  export { Logger, logger, LogLevel } from "./logger.ts";
8
- export { AsyncQueue } from "./asyncQueue.ts";
9
- export { nextTick } from "./nextTick.ts";
8
+ export { BufferedAsyncIterable } from "./BufferedAsyncIterable.ts";