@seriousme/opifex 2.2.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.
- package/README.md +7 -6
- package/bin/mqtt.ts +1 -1
- package/client/client.ts +57 -7
- package/client/context.ts +2 -2
- package/client/deps.ts +3 -3
- package/client/mod.ts +2 -2
- package/connNext/connNext.ts +44 -0
- package/deno/README.md +1 -1
- package/deno/denoConnToNext.ts +104 -0
- package/deno/tcpClient.ts +8 -24
- package/deno/tcpServer.test.ts +14 -103
- package/deno/tcpServer.ts +14 -6
- package/deno/tlsServer.test.ts +14 -58
- package/deno/tlsServer.ts +14 -6
- package/deno/wsServer.test.ts +15 -61
- package/deno/wsServer.ts +74 -32
- package/dev_utils/asyncStreamPair.ts +114 -0
- package/dev_utils/asyncStreamToNext.ts +171 -0
- package/dev_utils/connNextPair.test.ts +179 -0
- package/dev_utils/mockConn.ts +115 -29
- package/dev_utils/mockServer.ts +3 -4
- package/dev_utils/mod.ts +1 -2
- package/dev_utils/testClient.ts +64 -0
- package/dev_utils/webStreamToNext.ts +187 -0
- package/dist/bin/mqtt.js +1 -1
- package/dist/bin/mqtt.js.map +1 -1
- package/dist/client/client.d.ts +20 -3
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +42 -5
- package/dist/client/client.js.map +1 -1
- package/dist/client/context.d.ts +2 -2
- package/dist/client/context.d.ts.map +1 -1
- package/dist/client/deps.d.ts +1 -1
- package/dist/client/deps.d.ts.map +1 -1
- package/dist/client/mod.d.ts +1 -1
- package/dist/client/mod.d.ts.map +1 -1
- package/dist/connNext/connNext.d.ts +43 -0
- package/dist/connNext/connNext.d.ts.map +1 -0
- package/dist/connNext/connNext.js +2 -0
- package/dist/connNext/connNext.js.map +1 -0
- package/dist/examples/authHandler.test.js +2 -2
- package/dist/examples/authHandler.test.js.map +1 -1
- package/dist/examples/mqtt+mqtts.test.d.ts +2 -0
- package/dist/examples/mqtt+mqtts.test.d.ts.map +1 -0
- package/dist/examples/mqtt+mqtts.test.js +104 -0
- package/dist/examples/mqtt+mqtts.test.js.map +1 -0
- package/dist/examples/mqtt.test.js +2 -2
- package/dist/examples/mqtt.test.js.map +1 -1
- package/dist/examples/mqtts.test.js +2 -2
- package/dist/examples/mqtts.test.js.map +1 -1
- package/dist/mqttConn/mqttConn.d.ts +5 -6
- package/dist/mqttConn/mqttConn.d.ts.map +1 -1
- package/dist/mqttConn/mqttConn.js +2 -3
- package/dist/mqttConn/mqttConn.js.map +1 -1
- package/dist/node/nodeSocketToNext.d.ts +20 -0
- package/dist/node/nodeSocketToNext.d.ts.map +1 -0
- package/dist/node/nodeSocketToNext.js +161 -0
- package/dist/node/nodeSocketToNext.js.map +1 -0
- package/dist/node/tcpClient.d.ts +4 -6
- package/dist/node/tcpClient.d.ts.map +1 -1
- package/dist/node/tcpClient.js +6 -21
- package/dist/node/tcpClient.js.map +1 -1
- package/dist/node/tcpServer.d.ts +8 -4
- package/dist/node/tcpServer.d.ts.map +1 -1
- package/dist/node/tcpServer.js +14 -6
- package/dist/node/tcpServer.js.map +1 -1
- package/dist/node/tlsServer.d.ts +7 -3
- package/dist/node/tlsServer.d.ts.map +1 -1
- package/dist/node/tlsServer.js +13 -5
- package/dist/node/tlsServer.js.map +1 -1
- package/dist/server/context.d.ts +5 -5
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js +4 -1
- package/dist/server/context.js.map +1 -1
- package/dist/server/deps.d.ts +1 -1
- package/dist/server/deps.d.ts.map +1 -1
- package/dist/server/mod.d.ts +1 -1
- package/dist/server/mod.d.ts.map +1 -1
- package/dist/server/server.d.ts +3 -3
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +3 -3
- package/dist/utils/utils.d.ts +1 -2
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +3 -2
- package/dist/utils/utils.js.map +1 -1
- package/dist/web/webSocketToNext.d.ts +3 -0
- package/dist/web/webSocketToNext.d.ts.map +1 -0
- package/dist/web/webSocketToNext.js +160 -0
- package/dist/web/webSocketToNext.js.map +1 -0
- package/dist/web/wsClient.d.ts +3 -3
- package/dist/web/wsClient.d.ts.map +1 -1
- package/dist/web/wsClient.js +19 -5
- package/dist/web/wsClient.js.map +1 -1
- package/dist/web/wsClient.test.js +15 -0
- package/dist/web/wsClient.test.js.map +1 -1
- package/examples/README.md +21 -0
- package/examples/authHandler.test.ts +2 -2
- package/examples/mqtt+mqtts.test.ts +122 -0
- package/examples/mqtt.test.ts +2 -2
- package/examples/mqtts.test.ts +2 -2
- package/examples/webSocket.test.ts +10 -64
- package/examples/webSocketServer.ts +98 -0
- package/mqttConn/mqttConn.test.ts +6 -6
- package/mqttConn/mqttConn.ts +8 -9
- package/node/README.md +1 -1
- package/node/{socket-node-stream.ts → nodeSocketToNext.ts} +78 -65
- package/node/tcpClient.ts +13 -27
- package/node/tcpServer.test.ts +12 -58
- package/node/tcpServer.ts +18 -8
- package/node/tlsServer.test.ts +11 -58
- package/node/tlsServer.ts +17 -7
- package/package.json +3 -2
- package/server/context.ts +9 -6
- package/server/deps.ts +1 -1
- package/server/mod.ts +1 -1
- package/server/server.ts +6 -6
- package/utils/utils.ts +3 -2
- package/web/webSocketToNext.ts +183 -0
- package/web/wsClient.test.ts +22 -0
- package/web/wsClient.ts +21 -8
- package/dist/node/wrapNodeSocket.d.ts +0 -12
- package/dist/node/wrapNodeSocket.d.ts.map +0 -1
- package/dist/node/wrapNodeSocket.js +0 -36
- package/dist/node/wrapNodeSocket.js.map +0 -1
- package/dist/socket/socket.d.ts +0 -58
- package/dist/socket/socket.d.ts.map +0 -1
- package/dist/socket/socket.js +0 -99
- package/dist/socket/socket.js.map +0 -1
- package/dist/web/webSocketStream.d.ts +0 -29
- package/dist/web/webSocketStream.d.ts.map +0 -1
- package/dist/web/webSocketStream.js +0 -69
- package/dist/web/webSocketStream.js.map +0 -1
- package/dist/web/wrapWebSocket.d.ts +0 -12
- package/dist/web/wrapWebSocket.d.ts.map +0 -1
- package/dist/web/wrapWebSocket.js +0 -41
- package/dist/web/wrapWebSocket.js.map +0 -1
- package/node/socket-node-stream.test.ts +0 -322
- package/node/wrapNodeSocket.ts +0 -44
- package/socket/socket.test.ts +0 -91
- package/socket/socket.ts +0 -149
- package/web/webSocketStream.ts +0 -97
- package/web/wrapWebSocket.ts +0 -52
package/dist/server/deps.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { ConnAddr, ConnNext } from "../connNext/connNext.ts";
|
|
2
2
|
export { MqttConn } from "../mqttConn/mqttConn.ts";
|
|
3
3
|
export type { ClientSubscription, ExtPublishPacket, Persistence, ShareName, } from "../persistence/persistence.ts";
|
|
4
4
|
export { MemoryPersistence } from "../persistence/memory/memoryPersistence.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../server/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../server/deps.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,SAAS,GACV,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,YAAY,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,EACZ,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,GAAG,EACH,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,cAAc,EACd,KAAK,EACL,WAAW,EACX,cAAc,EACd,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EACL,MAAM,EACN,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
|
package/dist/server/mod.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
export { ReasonCode } from "./deps.ts";
|
|
6
|
-
export type { ConnectPacket, Persistence, ShareName,
|
|
6
|
+
export type { ConnectPacket, ConnNext, Persistence, ShareName, Topic, } from "./deps.ts";
|
|
7
7
|
export { MqttServer } from "./server.ts";
|
|
8
8
|
export type { MqttServerOptions } from "./server.ts";
|
|
9
9
|
export { Context } from "./context.ts";
|
package/dist/server/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../server/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../server/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EACV,aAAa,EACb,QAAQ,EACR,WAAW,EACX,SAAS,EACT,KAAK,GACN,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/server/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Handlers } from "./context.ts";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ConnNext, Persistence } from "./deps.ts";
|
|
3
3
|
import type { Configuration, ConfigurationInput } from "./config.ts";
|
|
4
4
|
/**
|
|
5
5
|
* Configuration options for creating an MqttServer instance.
|
|
@@ -37,10 +37,10 @@ export declare class MqttServer {
|
|
|
37
37
|
constructor({ persistence, handlers, configuration, }: MqttServerOptions);
|
|
38
38
|
/**
|
|
39
39
|
* Serve a new client connection.
|
|
40
|
-
* @param
|
|
40
|
+
* @param conn - The socket connection to serve.
|
|
41
41
|
* @returns {Promise<void>} A promise that resolves when the connection is closed.
|
|
42
42
|
*/
|
|
43
|
-
serve(conn:
|
|
43
|
+
serve(conn: ConnNext): Promise<void>;
|
|
44
44
|
/**
|
|
45
45
|
* Close the server and all active client connections.
|
|
46
46
|
* @param {boolean} cleanUp - If true, clean up client sessions on close.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../server/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../server/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAoB,MAAM,WAAW,CAAC;AAGzE,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AA4DrE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gFAAgF;IAChF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IACrB,gEAAgE;IAChE,QAAQ,EAAE,QAAQ,CAAC;IACnB,oEAAoE;IACpE,WAAW,EAAE,WAAW,CAAC;IACzB,oEAAoE;IACpE,aAAa,EAAE,aAAa,CAAC;IAE7B;;;OAGG;IACH,YAAY,EACV,WAAW,EACX,QAAQ,EACR,aAAa,GACd,EAAE,iBAAiB,EAYnB;IAED;;;;OAIG;IACG,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BzC;IAED;;;OAGG;IACG,KAAK,CAAC,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CASnD;CACF"}
|
package/dist/server/server.js
CHANGED
|
@@ -4,8 +4,8 @@ import { handlePacket } from "./handlers/handlePacket.js";
|
|
|
4
4
|
import { createConfiguration } from "./config.js";
|
|
5
5
|
/**
|
|
6
6
|
* Default preconnect handler that unconditionally permits all connections.
|
|
7
|
-
* @param
|
|
8
|
-
* @returns
|
|
7
|
+
* @param _conn - The connection.
|
|
8
|
+
* @returns Always returns true
|
|
9
9
|
*/
|
|
10
10
|
const defaultPreconnect = (_conn) => (true);
|
|
11
11
|
/**
|
|
@@ -73,7 +73,7 @@ export class MqttServer {
|
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Serve a new client connection.
|
|
76
|
-
* @param
|
|
76
|
+
* @param conn - The socket connection to serve.
|
|
77
77
|
* @returns {Promise<void>} A promise that resolves when the connection is closed.
|
|
78
78
|
*/
|
|
79
79
|
async serve(conn) {
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAKA,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,eAAO,MAAM,IAAI,YAAW,CAAC"}
|
package/dist/utils/utils.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* This file contains utilities used throughout the project too small to
|
|
3
3
|
* deserve their own dedicated files.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export function delay(ms) {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
7
8
|
export const noop = () => { };
|
|
8
9
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../utils/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webSocketToNext.d.ts","sourceRoot":"","sources":["../../web/webSocketToNext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAElE,wBAAsB,eAAe,CACnC,EAAE,EAAE,SAAS,EACb,UAAU,CAAC,EAAE,QAAQ,GACpB,OAAO,CAAC,QAAQ,CAAC,CAiLnB"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export async function webSocketToNext(ws, remoteAddr) {
|
|
2
|
+
ws.binaryType = "arraybuffer";
|
|
3
|
+
const messageQueue = [];
|
|
4
|
+
let queueOffset = 0;
|
|
5
|
+
const readResolvers = [];
|
|
6
|
+
const notifyWaiters = () => {
|
|
7
|
+
while (readResolvers.length > 0) {
|
|
8
|
+
const resolve = readResolvers.shift();
|
|
9
|
+
resolve?.();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
// helper to check if websocket is Open
|
|
13
|
+
const ensureOpen = () => {
|
|
14
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
15
|
+
return Promise.resolve();
|
|
16
|
+
}
|
|
17
|
+
if (ws.readyState >= WebSocket.CLOSING) {
|
|
18
|
+
return Promise.reject(new Error("WebSocket is closing or closed"));
|
|
19
|
+
}
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const onOpen = () => {
|
|
22
|
+
cleanup();
|
|
23
|
+
resolve();
|
|
24
|
+
};
|
|
25
|
+
const onError = (err) => {
|
|
26
|
+
cleanup();
|
|
27
|
+
reject(err);
|
|
28
|
+
};
|
|
29
|
+
const onClose = () => {
|
|
30
|
+
cleanup();
|
|
31
|
+
reject(new Error("WebSocket closed before opening"));
|
|
32
|
+
};
|
|
33
|
+
const cleanup = () => {
|
|
34
|
+
ws.removeEventListener("open", onOpen);
|
|
35
|
+
ws.removeEventListener("error", onError);
|
|
36
|
+
ws.removeEventListener("close", onClose);
|
|
37
|
+
};
|
|
38
|
+
ws.addEventListener("open", onOpen);
|
|
39
|
+
ws.addEventListener("error", onError);
|
|
40
|
+
ws.addEventListener("close", onClose);
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
ws.addEventListener("message", (event) => {
|
|
44
|
+
let chunk;
|
|
45
|
+
if (typeof event.data === "string") {
|
|
46
|
+
chunk = new TextEncoder().encode(event.data);
|
|
47
|
+
}
|
|
48
|
+
else if (event.data instanceof ArrayBuffer) {
|
|
49
|
+
chunk = new Uint8Array(event.data);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
messageQueue.push(chunk);
|
|
55
|
+
notifyWaiters();
|
|
56
|
+
});
|
|
57
|
+
ws.addEventListener("close", notifyWaiters);
|
|
58
|
+
ws.addEventListener("error", notifyWaiters);
|
|
59
|
+
const getBufferedBytes = () => {
|
|
60
|
+
let total = 0;
|
|
61
|
+
for (let i = 0; i < messageQueue.length; i++) {
|
|
62
|
+
total += i === 0
|
|
63
|
+
? messageQueue[i].byteLength - queueOffset
|
|
64
|
+
: messageQueue[i].byteLength;
|
|
65
|
+
}
|
|
66
|
+
return total;
|
|
67
|
+
};
|
|
68
|
+
const waitForData = () => {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
readResolvers.push(resolve);
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
const connNext = {
|
|
74
|
+
remoteAddr,
|
|
75
|
+
localAddr: undefined,
|
|
76
|
+
async read(length) {
|
|
77
|
+
try {
|
|
78
|
+
await ensureOpen();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (getBufferedBytes() === 0 && ws.readyState >= WebSocket.CLOSING) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
while (getBufferedBytes() === 0) {
|
|
87
|
+
if (ws.readyState >= WebSocket.CLOSING)
|
|
88
|
+
return null;
|
|
89
|
+
await waitForData();
|
|
90
|
+
}
|
|
91
|
+
if (length === undefined) {
|
|
92
|
+
const firstChunk = messageQueue.shift();
|
|
93
|
+
const result = firstChunk.subarray(queueOffset);
|
|
94
|
+
queueOffset = 0;
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
while (getBufferedBytes() < length) {
|
|
98
|
+
if (ws.readyState >= WebSocket.CLOSING) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
await waitForData();
|
|
102
|
+
}
|
|
103
|
+
const result = new Uint8Array(length);
|
|
104
|
+
let bytesCopied = 0;
|
|
105
|
+
while (bytesCopied < length && messageQueue.length > 0) {
|
|
106
|
+
const currentChunk = messageQueue[0];
|
|
107
|
+
const bytesNeeded = length - bytesCopied;
|
|
108
|
+
const bytesAvailable = currentChunk.byteLength - queueOffset;
|
|
109
|
+
if (bytesAvailable <= bytesNeeded) {
|
|
110
|
+
result.set(currentChunk.subarray(queueOffset), bytesCopied);
|
|
111
|
+
bytesCopied += bytesAvailable;
|
|
112
|
+
messageQueue.shift();
|
|
113
|
+
queueOffset = 0;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
result.set(currentChunk.subarray(queueOffset, queueOffset + bytesNeeded), bytesCopied);
|
|
117
|
+
bytesCopied += bytesNeeded;
|
|
118
|
+
queueOffset += bytesNeeded;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
},
|
|
123
|
+
async write(data) {
|
|
124
|
+
await ensureOpen();
|
|
125
|
+
if (data instanceof Uint8Array) {
|
|
126
|
+
ws.send(data.buffer);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
ws.send(data);
|
|
130
|
+
}
|
|
131
|
+
const HIGH_WATER_MARK = 64 * 1024;
|
|
132
|
+
while (ws.bufferedAmount > HIGH_WATER_MARK) {
|
|
133
|
+
if (ws.readyState >= WebSocket.CLOSING) {
|
|
134
|
+
throw new Error("WebSocket closed while writing");
|
|
135
|
+
}
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
close() {
|
|
140
|
+
try {
|
|
141
|
+
ws.close();
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
/* swallow */
|
|
145
|
+
}
|
|
146
|
+
notifyWaiters();
|
|
147
|
+
},
|
|
148
|
+
async *[Symbol.asyncIterator]() {
|
|
149
|
+
while (true) {
|
|
150
|
+
const chunk = await this.read();
|
|
151
|
+
if (chunk === null)
|
|
152
|
+
break;
|
|
153
|
+
yield chunk;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
await ensureOpen();
|
|
158
|
+
return connNext;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=webSocketToNext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webSocketToNext.js","sourceRoot":"","sources":["../../web/webSocketToNext.ts"],"names":[],"mappings":"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"}
|
package/dist/web/wsClient.d.ts
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { Client } from "../client/client.ts";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ConnNext } from "../client/deps.ts";
|
|
8
8
|
/**
|
|
9
9
|
* WsClient extends the Client class to provide WebSocket based clients
|
|
10
10
|
* it is used by the MQTTclient to connect to the broker
|
|
11
11
|
* see the /examples folder for an example
|
|
12
12
|
*/
|
|
13
13
|
export declare class WsClient extends Client {
|
|
14
|
-
/** create a websocket and wrap it in a
|
|
14
|
+
/** create a websocket and wrap it in a ConnNext */
|
|
15
15
|
private establishSocket;
|
|
16
16
|
/** createConn provides support for both "ws:" and "wss:" URLs */
|
|
17
|
-
protected createConn(): Promise<
|
|
17
|
+
protected createConn(): Promise<ConnNext>;
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=wsClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../web/wsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../web/wsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,mBAAmB,CAAC;AAG3D;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,MAAM;IAClC,mDAAmD;YACrC,eAAe;IAmB7B,iEAAiE;IACjE,UAAmB,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,CAUjD;CACF"}
|
package/dist/web/wsClient.js
CHANGED
|
@@ -5,18 +5,32 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Client } from "../client/client.js";
|
|
7
7
|
import { logger } from "../client/deps.js";
|
|
8
|
-
import {
|
|
8
|
+
import { webSocketToNext } from "./webSocketToNext.js";
|
|
9
9
|
/**
|
|
10
10
|
* WsClient extends the Client class to provide WebSocket based clients
|
|
11
11
|
* it is used by the MQTTclient to connect to the broker
|
|
12
12
|
* see the /examples folder for an example
|
|
13
13
|
*/
|
|
14
14
|
export class WsClient extends Client {
|
|
15
|
-
/** create a websocket and wrap it in a
|
|
15
|
+
/** create a websocket and wrap it in a ConnNext */
|
|
16
16
|
async establishSocket(url) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
try {
|
|
18
|
+
const urlObj = new URL(url);
|
|
19
|
+
const remoteAddr = {
|
|
20
|
+
transport: "tcp",
|
|
21
|
+
hostname: urlObj.hostname,
|
|
22
|
+
port: Number(urlObj.port || 0),
|
|
23
|
+
};
|
|
24
|
+
const ws = new WebSocket(url);
|
|
25
|
+
const connNext = await webSocketToNext(ws, remoteAddr);
|
|
26
|
+
return connNext;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof ErrorEvent
|
|
30
|
+
? ` because of ${error.message}`
|
|
31
|
+
: "";
|
|
32
|
+
throw new Error(`Failed to connect to WebSocket at ${url}${message}`);
|
|
33
|
+
}
|
|
20
34
|
}
|
|
21
35
|
/** createConn provides support for both "ws:" and "wss:" URLs */
|
|
22
36
|
createConn() {
|
package/dist/web/wsClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsClient.js","sourceRoot":"","sources":["../../web/wsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"wsClient.js","sourceRoot":"","sources":["../../web/wsClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,MAAM;IAClC,mDAAmD;IAC3C,KAAK,CAAC,eAAe,CAAC,GAAW;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,UAAU,GAAY;gBAC1B,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;aAC/B,CAAC;YACF,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YACvD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,UAAU;gBACzC,CAAC,CAAC,eAAe,KAAK,CAAC,OAAO,EAAE;gBAChC,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED,iEAAiE;IAC9C,UAAU;QAC3B,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACxE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,QAAQ,IAAI,OAAO,CAAC;QAEjC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,QAAQ,KAAK,QAAQ,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;IACvD,CAAC;CACF"}
|
|
@@ -17,4 +17,19 @@ test("Web: Test createConn - unsupported protocol", async () => {
|
|
|
17
17
|
message: "Unsupported protocol: ftp:",
|
|
18
18
|
}, "Should throw an error when an unsupported protocol is provided");
|
|
19
19
|
});
|
|
20
|
+
test("Web: Test createConn - unsupported host", async () => {
|
|
21
|
+
const client = new WsClient();
|
|
22
|
+
// Use an host protocol to trigger the ws error
|
|
23
|
+
const invalidParams = {
|
|
24
|
+
url: new URL("ws://test.invalid"),
|
|
25
|
+
numberOfRetries: 0,
|
|
26
|
+
};
|
|
27
|
+
// Assert that connect rejects with the specific error
|
|
28
|
+
await assert.rejects(async () => {
|
|
29
|
+
await client.connect(invalidParams);
|
|
30
|
+
}, {
|
|
31
|
+
name: "Error",
|
|
32
|
+
message: /^Failed to connect to WebSocket/,
|
|
33
|
+
}, "Should throw an error when an unreachable host is provided");
|
|
34
|
+
});
|
|
20
35
|
//# sourceMappingURL=wsClient.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsClient.test.js","sourceRoot":"","sources":["../../web/wsClient.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,0DAA0D;AAC1D,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;IAC7D,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAE9B,+EAA+E;IAC/E,MAAM,aAAa,GAAG;QACpB,GAAG,EAAE,IAAI,GAAG,CAAC,sBAAsB,CAAC;QACpC,eAAe,EAAE,CAAC;KACnB,CAAC;IAEF,6EAA6E;IAC7E,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC,EACD;QACE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,4BAA4B;KACtC,EACD,gEAAgE,CACjE,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"wsClient.test.js","sourceRoot":"","sources":["../../web/wsClient.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,0DAA0D;AAC1D,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;IAC7D,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAE9B,+EAA+E;IAC/E,MAAM,aAAa,GAAG;QACpB,GAAG,EAAE,IAAI,GAAG,CAAC,sBAAsB,CAAC;QACpC,eAAe,EAAE,CAAC;KACnB,CAAC;IAEF,6EAA6E;IAC7E,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC,EACD;QACE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,4BAA4B;KACtC,EACD,gEAAgE,CACjE,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;IACzD,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAE9B,+CAA+C;IAC/C,MAAM,aAAa,GAAG;QACpB,GAAG,EAAE,IAAI,GAAG,CAAC,mBAAmB,CAAC;QACjC,eAAe,EAAE,CAAC;KACnB,CAAC;IAEF,sDAAsD;IACtD,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC,EACD;QACE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,iCAAiC;KAC3C,EACD,4DAA4D,CAC7D,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Opifex Examples
|
|
2
|
+
|
|
3
|
+
This folder contains examples for [Opifex](../README.md). It serves as a
|
|
4
|
+
practical reference for setting up client/server communication, transport
|
|
5
|
+
handling, authentication, and persistence.
|
|
6
|
+
|
|
7
|
+
## Index
|
|
8
|
+
|
|
9
|
+
- [`mqtt.test.ts`](mqtt.test.ts) — basic MQTT publish/subscribe flow over TCP
|
|
10
|
+
with in-memory persistence.
|
|
11
|
+
- [`mqtts.test.ts`](mqtts.test.ts) — TLS-based MQTT example using SQLite
|
|
12
|
+
persistence.
|
|
13
|
+
- [`mqtt+mqtts.test.ts`](mqtt+mqtts.test.ts) — Publish over TLS, subscribe over
|
|
14
|
+
TCP.
|
|
15
|
+
- [`authHandler.test.ts`](authHandler.test.ts) — MQTT v5 authentication example
|
|
16
|
+
with a custom `processAuth` handler.
|
|
17
|
+
- [`webSocket.test.ts`](webSocket.test.ts) — WebSocket-based client/server flow
|
|
18
|
+
for Deno.
|
|
19
|
+
- [`webSocketServer.ts`](webSocketServer.ts) — simple WebSocket serving example
|
|
20
|
+
for browser-based MQTT usage.
|
|
21
|
+
- [`public/`](public) — static assets used by the browser-facing WebSocket demo.
|
|
@@ -112,7 +112,7 @@ test("Test MQTTv5 Auth using TCP client and server", async function () {
|
|
|
112
112
|
const client = new TcpClient();
|
|
113
113
|
client.onAuth = clientProcessAuth;
|
|
114
114
|
await client.connect(params);
|
|
115
|
-
logger.info("Client connected to server at", client.url);
|
|
115
|
+
logger.info("Client connected to server at", client.url.toString());
|
|
116
116
|
|
|
117
117
|
const publishSet: { topic: string; qos: QoS }[] = [
|
|
118
118
|
{ topic: "t0@q0", qos: 0 },
|
|
@@ -160,5 +160,5 @@ test("Test MQTTv5 Auth using TCP client and server", async function () {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
logger.info("Stop server");
|
|
163
|
-
server.stop();
|
|
163
|
+
await server.stop();
|
|
164
164
|
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { TcpClient } from "@seriousme/opifex/tcpClient";
|
|
4
|
+
import { TlsServer } from "@seriousme/opifex/tlsServer";
|
|
5
|
+
import { MqttServer } from "@seriousme/opifex/server";
|
|
6
|
+
import { delay, logger, LogLevel } from "@seriousme/opifex/utils";
|
|
7
|
+
import type { PublishPacket, QoS } from "@seriousme/opifex/mqttPacket";
|
|
8
|
+
import { generateLocalhostCerts } from "../dev_utils/generateCert.ts";
|
|
9
|
+
import { TcpServer } from "@seriousme/opifex/tcpServer";
|
|
10
|
+
|
|
11
|
+
logger.level(LogLevel.info);
|
|
12
|
+
|
|
13
|
+
test("Test pubSub using TLS client and a TCP client", async function () {
|
|
14
|
+
// the localhost certs generate here are great for testing but lack securiity
|
|
15
|
+
// use something like LetsEncrypt for any serious server
|
|
16
|
+
// generateLocalhostCerts is a dev tool and relies on node-forge as a (dev)dependency
|
|
17
|
+
const { key, cert, caCert } = generateLocalhostCerts();
|
|
18
|
+
// first create the mqttServer, so we can pass it to multiple protocol servers
|
|
19
|
+
const mqttServer = new MqttServer({});
|
|
20
|
+
|
|
21
|
+
const tlsServer = new TlsServer({ port: 0, key, cert }, mqttServer);
|
|
22
|
+
const tcpServer = new TcpServer({ port: 0 }, mqttServer);
|
|
23
|
+
// .start() combines instance creation and async initialization
|
|
24
|
+
tlsServer.start();
|
|
25
|
+
tcpServer.start();
|
|
26
|
+
|
|
27
|
+
logger.info(
|
|
28
|
+
`TLS server running on port: ${tlsServer.port}, address: ${tlsServer.address}`,
|
|
29
|
+
);
|
|
30
|
+
logger.info(
|
|
31
|
+
`TCP server running on port: ${tcpServer.port}, address: ${tcpServer.address}`,
|
|
32
|
+
);
|
|
33
|
+
// pick the correct hostname
|
|
34
|
+
const tlsHostname = tlsServer.address === "0.0.0.0"
|
|
35
|
+
? "127.0.0.1"
|
|
36
|
+
: tlsServer.address;
|
|
37
|
+
const tcpHostname = tcpServer.address === "0.0.0.0"
|
|
38
|
+
? "127.0.0.1"
|
|
39
|
+
: tcpServer.address;
|
|
40
|
+
|
|
41
|
+
const tlsParams = {
|
|
42
|
+
url: new URL(`mqtts://${tlsHostname}:${tlsServer.port}`),
|
|
43
|
+
clientId: "I am a TLS client",
|
|
44
|
+
numberOfRetries: 0,
|
|
45
|
+
// since we signed our server cert ourselves we need to add the caCert
|
|
46
|
+
// this is not required if you use a public Certificate Authority
|
|
47
|
+
caCerts: [caCert],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const tcpParams = {
|
|
51
|
+
url: new URL(`mqtt://${tcpHostname}:${tcpServer.port}`),
|
|
52
|
+
clientId: "I am a TCP client",
|
|
53
|
+
numberOfRetries: 0,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const tlsClient = new TcpClient(); // TcpClient can also handle TLS
|
|
57
|
+
const tcpClient = new TcpClient();
|
|
58
|
+
await tlsClient.connect(tlsParams);
|
|
59
|
+
await tcpClient.connect(tcpParams);
|
|
60
|
+
logger.info("tlsClient connected to server at", tlsClient.url.toString());
|
|
61
|
+
logger.info("tcpClient connected to server at", tcpClient.url.toString());
|
|
62
|
+
|
|
63
|
+
const publishSet: { topic: string; qos: QoS }[] = [
|
|
64
|
+
{ topic: "t0@q0", qos: 0 },
|
|
65
|
+
{ topic: "t1@q0", qos: 0 },
|
|
66
|
+
{ topic: "t2@q0", qos: 0 },
|
|
67
|
+
{ topic: "t0@q1", qos: 1 },
|
|
68
|
+
{ topic: "t1@q1", qos: 1 },
|
|
69
|
+
{ topic: "t2@q1", qos: 1 },
|
|
70
|
+
{ topic: "t0@q2", qos: 2 },
|
|
71
|
+
{ topic: "t1@q2", qos: 2 },
|
|
72
|
+
{ topic: "t2@q2", qos: 2 },
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const subscriptions = publishSet.map((item) => ({
|
|
76
|
+
topicFilter: item.topic,
|
|
77
|
+
qos: item.qos,
|
|
78
|
+
}));
|
|
79
|
+
await tcpClient.subscribe({
|
|
80
|
+
subscriptions,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// the IIFE ensures message reception runs in parallel
|
|
84
|
+
logger.info("TCP client Start receiving");
|
|
85
|
+
const received: PublishPacket[] = [];
|
|
86
|
+
(async function () {
|
|
87
|
+
for await (const item of tcpClient.messages()) {
|
|
88
|
+
logger.verbose("Receiving:", item.topic, "--", item.qos);
|
|
89
|
+
received.push(item);
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
92
|
+
// end of IIFE
|
|
93
|
+
logger.info("TLS client Start publishing");
|
|
94
|
+
for (const item of publishSet) {
|
|
95
|
+
logger.verbose("Publishing:", item.topic, "--", item.qos);
|
|
96
|
+
await tlsClient.publish({
|
|
97
|
+
topic: item.topic,
|
|
98
|
+
qos: item.qos,
|
|
99
|
+
payload: new Uint8Array([0x01]),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await delay(100);
|
|
104
|
+
logger.info("Disconnect TLS client");
|
|
105
|
+
await tlsClient.disconnect();
|
|
106
|
+
logger.info("Disconnect TCP client");
|
|
107
|
+
await tcpClient.disconnect();
|
|
108
|
+
logger.info("Check completeness");
|
|
109
|
+
for (const item of publishSet) {
|
|
110
|
+
const found = received.find((f) =>
|
|
111
|
+
f.topic == item.topic && f.qos === item.qos
|
|
112
|
+
);
|
|
113
|
+
logger.verbose("Found:", item.topic, "--", item.qos);
|
|
114
|
+
assert(found, `${item.topic} -- ${item.qos}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// just for demo, you can keep the MQTT server alive on the TCP server wile the TLSserver closes
|
|
118
|
+
logger.info("Stop TLS server");
|
|
119
|
+
await tlsServer.stop();
|
|
120
|
+
logger.info("Stop TCP server");
|
|
121
|
+
await tcpServer.stop();
|
|
122
|
+
});
|
package/examples/mqtt.test.ts
CHANGED
|
@@ -30,7 +30,7 @@ test("Test pubSub using TCP client and server using memoryPersistence", async fu
|
|
|
30
30
|
|
|
31
31
|
const client = new TcpClient();
|
|
32
32
|
await client.connect(params);
|
|
33
|
-
logger.info("Client connected to server at", client.url);
|
|
33
|
+
logger.info("Client connected to server at", client.url.toString());
|
|
34
34
|
|
|
35
35
|
const publishSet: { topic: string; qos: QoS }[] = [
|
|
36
36
|
{ topic: "t0@q0", qos: 0 },
|
|
@@ -85,5 +85,5 @@ test("Test pubSub using TCP client and server using memoryPersistence", async fu
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
logger.info("Stop server");
|
|
88
|
-
server.stop();
|
|
88
|
+
await server.stop();
|
|
89
89
|
});
|
package/examples/mqtts.test.ts
CHANGED
|
@@ -41,7 +41,7 @@ test("Test pubSub using TLS client and server and sqlitePersistence", async func
|
|
|
41
41
|
|
|
42
42
|
const client = new TcpClient();
|
|
43
43
|
await client.connect(params);
|
|
44
|
-
logger.info("Client connected to server at", client.url);
|
|
44
|
+
logger.info("Client connected to server at", client.url.toString());
|
|
45
45
|
|
|
46
46
|
const publishSet: { topic: string; qos: QoS }[] = [
|
|
47
47
|
{ topic: "t0@q0", qos: 0 },
|
|
@@ -96,5 +96,5 @@ test("Test pubSub using TLS client and server and sqlitePersistence", async func
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
logger.info("Stop server");
|
|
99
|
-
server.stop();
|
|
99
|
+
await server.stop();
|
|
100
100
|
});
|