@seriousme/opifex 1.6.2 → 1.7.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 +6 -7
- package/bin/conformanceServer.ts +67 -16
- package/bin/demoServer.ts +69 -14
- package/bin/mqtt.ts +30 -0
- package/client/ConnectionState.ts +12 -0
- package/client/client.ts +56 -2
- package/client/context.ts +5 -0
- package/client/handlers/handleConnack.ts +6 -0
- package/client/handlers/handlePacket.ts +7 -0
- package/client/handlers/handlePuback.ts +8 -2
- package/client/handlers/handlePubcomp.ts +10 -4
- package/client/handlers/handlePublish.ts +6 -2
- package/client/handlers/handlePubrec.ts +13 -6
- package/client/handlers/handlePubrel.ts +16 -6
- package/client/handlers/handleSuback.ts +9 -6
- package/client/handlers/handleUnsuback.ts +10 -3
- package/client/store/memoryStore.ts +25 -0
- package/client/store/store.ts +39 -0
- package/deno/tcpServer.test.ts +137 -2
- package/node/tcpServer.test.ts +61 -6
- package/node/tcpServer.ts +9 -2
- package/node/wrapNodeSocket.ts +13 -2
- package/package.json +13 -3
- package/persistence/memory/memoryPersistence.test.ts +2 -1
- package/persistence/memory/memoryPersistence.ts +1 -0
- package/persistence/store.ts +1 -0
- package/server/handlers/handleConnect.ts +49 -6
- package/server/handlers/handleDisconnect.ts +5 -0
- package/server/handlers/handlePacket.ts +7 -0
- package/server/handlers/handlePingreq.ts +6 -0
- package/server/handlers/handlePuback.ts +9 -2
- package/server/handlers/handlePubcomp.ts +8 -3
- package/server/handlers/handlePublish.ts +13 -0
- package/server/handlers/handlePubrec.ts +11 -3
- package/server/handlers/handlePubrel.ts +12 -4
- package/server/handlers/handleSubscribe.ts +28 -5
- package/server/handlers/handleUnsubscribe.ts +6 -0
- package/utils/asyncQueue.ts +2 -1
- package/utils/nextTick.ts +13 -1
- package/.github/workflows/closeStale.yml +0 -15
- package/.github/workflows/codeql-analysis.yml +0 -71
- package/.github/workflows/deno-ci.yml +0 -16
- package/.github/workflows/nodejs-ci.yml +0 -23
- package/.github/workflows/publish.yml +0 -16
- package/.github/workflows/update-license-year.sh +0 -14
- package/.github/workflows/update-license-year.yml +0 -13
- package/CHANGELOG.md +0 -74
- package/deno.json +0 -15
- package/deno.lock +0 -34
- package/dist/bin/conformanceServer.js +0 -51
- package/dist/bin/demoServer.js +0 -46
- package/dist/bin/mqtt.js +0 -227
- package/dist/client/ConnectionState.js +0 -7
- package/dist/client/client.js +0 -132
- package/dist/client/context.js +0 -148
- package/dist/client/deps.js +0 -5
- package/dist/client/handlers/handleConnack.js +0 -18
- package/dist/client/handlers/handlePacket.js +0 -50
- package/dist/client/handlers/handlePuback.js +0 -6
- package/dist/client/handlers/handlePubcomp.js +0 -9
- package/dist/client/handlers/handlePublish.js +0 -28
- package/dist/client/handlers/handlePubrec.js +0 -17
- package/dist/client/handlers/handlePubrel.js +0 -19
- package/dist/client/handlers/handleSuback.js +0 -9
- package/dist/client/handlers/handleUnsuback.js +0 -7
- package/dist/client/mod.js +0 -5
- package/dist/client/store/deps.js +0 -1
- package/dist/client/store/memoryStore.js +0 -36
- package/dist/client/store/store.js +0 -1
- package/dist/mqttConn/mqttConn.js +0 -104
- package/dist/mqttPacket/AuthenticationResult.js +0 -16
- package/dist/mqttPacket/BitMask.js +0 -10
- package/dist/mqttPacket/PacketType.js +0 -18
- package/dist/mqttPacket/connack.js +0 -27
- package/dist/mqttPacket/connect.js +0 -115
- package/dist/mqttPacket/decoder.js +0 -89
- package/dist/mqttPacket/disconnect.js +0 -14
- package/dist/mqttPacket/encoder.js +0 -56
- package/dist/mqttPacket/length.js +0 -43
- package/dist/mqttPacket/mod.js +0 -76
- package/dist/mqttPacket/pingreq.js +0 -15
- package/dist/mqttPacket/pingres.js +0 -14
- package/dist/mqttPacket/puback.js +0 -20
- package/dist/mqttPacket/pubcomp.js +0 -20
- package/dist/mqttPacket/publish.js +0 -51
- package/dist/mqttPacket/pubrec.js +0 -20
- package/dist/mqttPacket/pubrel.js +0 -20
- package/dist/mqttPacket/suback.js +0 -29
- package/dist/mqttPacket/subscribe.js +0 -52
- package/dist/mqttPacket/types.js +0 -1
- package/dist/mqttPacket/unsuback.js +0 -20
- package/dist/mqttPacket/unsubscribe.js +0 -36
- package/dist/mqttPacket/validators.js +0 -15
- package/dist/node/tcpClient.js +0 -81
- package/dist/node/tcpServer.js +0 -43
- package/dist/node/wrapNodeSocket.js +0 -47
- package/dist/persistence/deps.js +0 -3
- package/dist/persistence/memory/memoryPersistence.js +0 -117
- package/dist/persistence/persistence.js +0 -1
- package/dist/persistence/store.js +0 -1
- package/dist/server/context.js +0 -100
- package/dist/server/deps.js +0 -5
- package/dist/server/handlers/handleConnect.js +0 -46
- package/dist/server/handlers/handleDisconnect.js +0 -4
- package/dist/server/handlers/handlePacket.js +0 -58
- package/dist/server/handlers/handlePingreq.js +0 -6
- package/dist/server/handlers/handlePuback.js +0 -8
- package/dist/server/handlers/handlePubcomp.js +0 -8
- package/dist/server/handlers/handlePublish.js +0 -41
- package/dist/server/handlers/handlePubrec.js +0 -15
- package/dist/server/handlers/handlePubrel.js +0 -18
- package/dist/server/handlers/handleSubscribe.js +0 -33
- package/dist/server/handlers/handleUnsubscribe.js +0 -12
- package/dist/server/mod.js +0 -7
- package/dist/server/server.js +0 -47
- package/dist/socket/socket.js +0 -36
- package/dist/timer/timer.js +0 -40
- package/dist/trie/trie.js +0 -95
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/utils/args.js +0 -75
- package/dist/utils/assert.js +0 -20
- package/dist/utils/asyncQueue.js +0 -67
- package/dist/utils/deferred.js +0 -14
- package/dist/utils/logger.js +0 -58
- package/dist/utils/mod.js +0 -11
- package/dist/utils/nextTick.js +0 -6
- package/dist/utils/platform.js +0 -7
- package/tsconfig.json +0 -22
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { Decoder } from "./decoder.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
export const pubcomp = {
|
|
5
|
-
encode(packet) {
|
|
6
|
-
const flags = 0;
|
|
7
|
-
const encoder = new Encoder();
|
|
8
|
-
encoder.setInt16(packet.id);
|
|
9
|
-
return { flags, bytes: encoder.done() };
|
|
10
|
-
},
|
|
11
|
-
decode(buffer) {
|
|
12
|
-
const decoder = new Decoder(buffer);
|
|
13
|
-
const id = decoder.getInt16();
|
|
14
|
-
decoder.done();
|
|
15
|
-
return {
|
|
16
|
-
type: PacketType.pubcomp,
|
|
17
|
-
id,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { BitMask } from "./BitMask.js";
|
|
3
|
-
import { Encoder, EncoderError } from "./encoder.js";
|
|
4
|
-
import { booleanFlag, Decoder, DecoderError } from "./decoder.js";
|
|
5
|
-
export const publish = {
|
|
6
|
-
encode(packet) {
|
|
7
|
-
const qos = packet.qos || 0;
|
|
8
|
-
const flags = (packet.dup ? BitMask.bit3 : 0) +
|
|
9
|
-
(qos & 2 ? BitMask.bit2 : 0) +
|
|
10
|
-
(qos & 1 ? BitMask.bit1 : 0) +
|
|
11
|
-
(packet.retain ? BitMask.bit0 : 0);
|
|
12
|
-
const encoder = new Encoder();
|
|
13
|
-
encoder.setTopic(packet.topic);
|
|
14
|
-
if (qos === 1 || qos === 2) {
|
|
15
|
-
if (typeof packet.id !== "number" || packet.id < 1) {
|
|
16
|
-
throw new EncoderError("when qos is 1 or 2, packet must have id");
|
|
17
|
-
}
|
|
18
|
-
encoder.setInt16(packet.id);
|
|
19
|
-
}
|
|
20
|
-
encoder.setRemainder(packet.payload);
|
|
21
|
-
return { flags, bytes: encoder.done() };
|
|
22
|
-
},
|
|
23
|
-
decode(buffer, flags) {
|
|
24
|
-
const dup = booleanFlag(flags, BitMask.bit3);
|
|
25
|
-
const qos = (flags & 6) >> 1;
|
|
26
|
-
const retain = booleanFlag(flags, BitMask.bit0);
|
|
27
|
-
if (qos !== 0 && qos !== 1 && qos !== 2) {
|
|
28
|
-
throw new DecoderError("Invalid qos");
|
|
29
|
-
}
|
|
30
|
-
if (dup && qos === 0) {
|
|
31
|
-
throw new DecoderError("Invalid qos for possible duplicate");
|
|
32
|
-
}
|
|
33
|
-
const decoder = new Decoder(buffer);
|
|
34
|
-
const topic = decoder.getTopic();
|
|
35
|
-
let id = 0;
|
|
36
|
-
if (qos > 0) {
|
|
37
|
-
id = decoder.getInt16();
|
|
38
|
-
}
|
|
39
|
-
const payload = decoder.getRemainder();
|
|
40
|
-
// no decoder.done() required because of getRemainder
|
|
41
|
-
return {
|
|
42
|
-
type: PacketType.publish,
|
|
43
|
-
topic,
|
|
44
|
-
payload,
|
|
45
|
-
dup,
|
|
46
|
-
retain,
|
|
47
|
-
qos,
|
|
48
|
-
id,
|
|
49
|
-
};
|
|
50
|
-
},
|
|
51
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { Decoder } from "./decoder.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
export const pubrec = {
|
|
5
|
-
encode(packet) {
|
|
6
|
-
const flags = 0;
|
|
7
|
-
const encoder = new Encoder();
|
|
8
|
-
encoder.setInt16(packet.id);
|
|
9
|
-
return { flags, bytes: encoder.done() };
|
|
10
|
-
},
|
|
11
|
-
decode(buffer) {
|
|
12
|
-
const decoder = new Decoder(buffer);
|
|
13
|
-
const id = decoder.getInt16();
|
|
14
|
-
decoder.done();
|
|
15
|
-
return {
|
|
16
|
-
type: PacketType.pubrec,
|
|
17
|
-
id,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { Decoder } from "./decoder.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
export const pubrel = {
|
|
5
|
-
encode(packet) {
|
|
6
|
-
const flags = 0;
|
|
7
|
-
const encoder = new Encoder();
|
|
8
|
-
encoder.setInt16(packet.id);
|
|
9
|
-
return { flags, bytes: encoder.done() };
|
|
10
|
-
},
|
|
11
|
-
decode(buffer) {
|
|
12
|
-
const decoder = new Decoder(buffer);
|
|
13
|
-
const id = decoder.getInt16();
|
|
14
|
-
decoder.done();
|
|
15
|
-
return {
|
|
16
|
-
type: PacketType.pubrel,
|
|
17
|
-
id,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { Encoder } from "./encoder.js";
|
|
3
|
-
import { Decoder } from "./decoder.js";
|
|
4
|
-
export const suback = {
|
|
5
|
-
encode(packet) {
|
|
6
|
-
const flags = 0;
|
|
7
|
-
const encoder = new Encoder();
|
|
8
|
-
encoder.setInt16(packet.id);
|
|
9
|
-
encoder.setRemainder(packet.returnCodes);
|
|
10
|
-
return {
|
|
11
|
-
flags,
|
|
12
|
-
bytes: encoder.done(),
|
|
13
|
-
};
|
|
14
|
-
},
|
|
15
|
-
decode(buffer) {
|
|
16
|
-
const decoder = new Decoder(buffer);
|
|
17
|
-
const id = decoder.getInt16();
|
|
18
|
-
const payload = decoder.getRemainder();
|
|
19
|
-
const returnCodes = [];
|
|
20
|
-
for (const code of payload) {
|
|
21
|
-
returnCodes.push(code);
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
type: PacketType.suback,
|
|
25
|
-
id,
|
|
26
|
-
returnCodes,
|
|
27
|
-
};
|
|
28
|
-
},
|
|
29
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { BitMask } from "./BitMask.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
import { booleanFlag, Decoder, DecoderError } from "./decoder.js";
|
|
5
|
-
export const subscribe = {
|
|
6
|
-
encode(packet) {
|
|
7
|
-
// Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
|
|
8
|
-
// MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
|
|
9
|
-
// malformed and close the Network Connection [MQTT-3.8.1-1].
|
|
10
|
-
const flags = 0b0010;
|
|
11
|
-
const encoder = new Encoder();
|
|
12
|
-
encoder.setInt16(packet.id);
|
|
13
|
-
for (const sub of packet.subscriptions) {
|
|
14
|
-
encoder.setTopic(sub.topicFilter);
|
|
15
|
-
encoder.setByte(sub.qos);
|
|
16
|
-
}
|
|
17
|
-
return { flags, bytes: encoder.done() };
|
|
18
|
-
},
|
|
19
|
-
decode(buffer, flags) {
|
|
20
|
-
// Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and
|
|
21
|
-
// MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
|
|
22
|
-
// malformed and close the Network Connection [MQTT-3.8.1-1].
|
|
23
|
-
if (!booleanFlag(flags, BitMask.bit1)) {
|
|
24
|
-
throw new DecoderError("Invalid header");
|
|
25
|
-
}
|
|
26
|
-
const decoder = new Decoder(buffer);
|
|
27
|
-
const id = decoder.getInt16();
|
|
28
|
-
const subscriptions = [];
|
|
29
|
-
// The payload of a SUBSCRIBE packet MUST contain at least one Topic Filter / QoS pair.
|
|
30
|
-
// A SUBSCRIBE packet with no payload is a protocol violation [MQTT-3.8.3-3].
|
|
31
|
-
do {
|
|
32
|
-
const topicFilter = decoder.getTopicFilter();
|
|
33
|
-
const qos = decoder.getByte();
|
|
34
|
-
if (qos !== 0 && qos !== 1 && qos !== 2) {
|
|
35
|
-
throw new DecoderError("Invalid qos");
|
|
36
|
-
}
|
|
37
|
-
if (qos > 0 && id === 0) {
|
|
38
|
-
throw new DecoderError("Invalid packet identifier");
|
|
39
|
-
}
|
|
40
|
-
subscriptions.push({
|
|
41
|
-
topicFilter: topicFilter,
|
|
42
|
-
qos,
|
|
43
|
-
});
|
|
44
|
-
} while (!decoder.atEnd());
|
|
45
|
-
decoder.done();
|
|
46
|
-
return {
|
|
47
|
-
type: PacketType.subscribe,
|
|
48
|
-
id,
|
|
49
|
-
subscriptions,
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
};
|
package/dist/mqttPacket/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { Decoder } from "./decoder.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
export const unsuback = {
|
|
5
|
-
encode(packet) {
|
|
6
|
-
const flags = 0;
|
|
7
|
-
const encoder = new Encoder();
|
|
8
|
-
encoder.setInt16(packet.id);
|
|
9
|
-
return { flags, bytes: encoder.done() };
|
|
10
|
-
},
|
|
11
|
-
decode(buffer) {
|
|
12
|
-
const decoder = new Decoder(buffer);
|
|
13
|
-
const id = decoder.getInt16();
|
|
14
|
-
decoder.done();
|
|
15
|
-
return {
|
|
16
|
-
type: PacketType.unsuback,
|
|
17
|
-
id,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { PacketType } from "./PacketType.js";
|
|
2
|
-
import { BitMask } from "./BitMask.js";
|
|
3
|
-
import { Encoder } from "./encoder.js";
|
|
4
|
-
import { booleanFlag, Decoder, DecoderError } from "./decoder.js";
|
|
5
|
-
export const unsubscribe = {
|
|
6
|
-
encode(packet) {
|
|
7
|
-
// Bits 3,2,1 and 0 of the fixed header of the UNSUBSCRIBE Control Packet are reserved and
|
|
8
|
-
// MUST be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as
|
|
9
|
-
// malformed and close the Network Connection [MQTT-3.10.1-1].
|
|
10
|
-
const flags = 0b0010;
|
|
11
|
-
const encoder = new Encoder();
|
|
12
|
-
encoder.setInt16(packet.id);
|
|
13
|
-
for (const topicFilter of packet.topicFilters) {
|
|
14
|
-
encoder.setTopicFilter(topicFilter);
|
|
15
|
-
}
|
|
16
|
-
return { flags, bytes: encoder.done() };
|
|
17
|
-
},
|
|
18
|
-
decode(buffer, flags) {
|
|
19
|
-
if (!booleanFlag(flags, BitMask.bit1)) {
|
|
20
|
-
throw new DecoderError("Invalid header");
|
|
21
|
-
}
|
|
22
|
-
const decoder = new Decoder(buffer);
|
|
23
|
-
const id = decoder.getInt16();
|
|
24
|
-
const topicFilters = [];
|
|
25
|
-
do {
|
|
26
|
-
const topicFilter = decoder.getTopicFilter();
|
|
27
|
-
topicFilters.push(topicFilter);
|
|
28
|
-
} while (!decoder.atEnd());
|
|
29
|
-
decoder.done();
|
|
30
|
-
return {
|
|
31
|
-
type: PacketType.unsubscribe,
|
|
32
|
-
id,
|
|
33
|
-
topicFilters,
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// deno-lint-ignore no-control-regex
|
|
2
|
-
const invalidUTF8regEx = new RegExp(/\x00|\uFFFD/);
|
|
3
|
-
// deno-lint-ignore no-control-regex
|
|
4
|
-
const invalidTopicRegEx = new RegExp(/^$|\+|#|\x00|\uFFFD/);
|
|
5
|
-
// deno-lint-ignore no-control-regex
|
|
6
|
-
const invalidTopicFilterRegEx = new RegExp(/^$|#.|[^\/]\+|\+[^\/]|\x00|\uFFFD/);
|
|
7
|
-
export function invalidUTF8(value) {
|
|
8
|
-
return invalidUTF8regEx.test(value);
|
|
9
|
-
}
|
|
10
|
-
export function invalidTopic(value) {
|
|
11
|
-
return invalidTopicRegEx.test(value);
|
|
12
|
-
}
|
|
13
|
-
export function invalidTopicFilter(value) {
|
|
14
|
-
return invalidTopicFilterRegEx.test(value);
|
|
15
|
-
}
|
package/dist/node/tcpClient.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* this a NodeJS specific implementation of TCP client sockets
|
|
3
|
-
* it extends the platform agnostic Client class
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import { Client } from "../client/client.js";
|
|
7
|
-
import { logger } from "../client/deps.js";
|
|
8
|
-
import { readFile } from "node:fs/promises";
|
|
9
|
-
import { createConnection } from "node:net";
|
|
10
|
-
import * as tls from "node:tls";
|
|
11
|
-
import { wrapNodeSocket } from "./wrapNodeSocket.js";
|
|
12
|
-
/**
|
|
13
|
-
* @function getFileData
|
|
14
|
-
* @param filename
|
|
15
|
-
* @returns Promise
|
|
16
|
-
*
|
|
17
|
-
* Fetches data from a file and returns it as a string
|
|
18
|
-
* @example
|
|
19
|
-
* const data = await getFileData("data.txt");
|
|
20
|
-
*/
|
|
21
|
-
export async function getFileData(filename) {
|
|
22
|
-
if (!filename) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const data = await readFile(filename, { encoding: "utf-8" });
|
|
26
|
-
if (data === "") {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
return data;
|
|
30
|
-
}
|
|
31
|
-
/*
|
|
32
|
-
* TCPclient extends the Client class to provide TCP based clients
|
|
33
|
-
* it is used by the MQTTclient to connect to the broker
|
|
34
|
-
* see mqtt.ts in the /bin folder as an example
|
|
35
|
-
*/
|
|
36
|
-
export class TcpClient extends Client {
|
|
37
|
-
connectMQTT(hostname, port = 1883) {
|
|
38
|
-
logger.debug({ hostname, port });
|
|
39
|
-
return new Promise((resolve, reject) => {
|
|
40
|
-
const socket = createConnection({ port, host: hostname }, () => {
|
|
41
|
-
logger.debug("Connected to server");
|
|
42
|
-
resolve(wrapNodeSocket(socket));
|
|
43
|
-
});
|
|
44
|
-
socket.once("error", (err) => {
|
|
45
|
-
logger.debug("Connection failed: ", err);
|
|
46
|
-
reject(err);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
connectMQTTS(hostname, port = 8883, ca, cert, key) {
|
|
51
|
-
const opts = {
|
|
52
|
-
host: hostname,
|
|
53
|
-
port,
|
|
54
|
-
secureContext: (ca || key || cert)
|
|
55
|
-
? tls.createSecureContext({ ca, cert, key })
|
|
56
|
-
: undefined,
|
|
57
|
-
};
|
|
58
|
-
logger.debug({ hostname, port, ca, cert });
|
|
59
|
-
return new Promise((resolve, reject) => {
|
|
60
|
-
const socket = tls.connect(opts, () => {
|
|
61
|
-
logger.debug("Connected to server");
|
|
62
|
-
resolve(wrapNodeSocket(socket));
|
|
63
|
-
});
|
|
64
|
-
socket.once("error", (err) => {
|
|
65
|
-
logger.debug("Connection failed", err);
|
|
66
|
-
reject(err);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
createConn(protocol, hostname, port, caCerts) {
|
|
71
|
-
// if you need to support alternative connection types just
|
|
72
|
-
// overload this method in your subclass
|
|
73
|
-
if (protocol === "mqtts:") {
|
|
74
|
-
return this.connectMQTTS(hostname, port, caCerts);
|
|
75
|
-
}
|
|
76
|
-
if (protocol === "mqtt:") {
|
|
77
|
-
return this.connectMQTT(hostname, port);
|
|
78
|
-
}
|
|
79
|
-
throw `Unsupported protocol: ${protocol}`;
|
|
80
|
-
}
|
|
81
|
-
}
|
package/dist/node/tcpServer.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { createServer } from "node:net";
|
|
2
|
-
import { MqttServer } from "../server/mod.js";
|
|
3
|
-
import { wrapNodeSocket } from "./wrapNodeSocket.js";
|
|
4
|
-
/*
|
|
5
|
-
* TCP server that wraps a MqttServer, see demoServer.ts in the /bin folder
|
|
6
|
-
*/
|
|
7
|
-
export class TcpServer {
|
|
8
|
-
mqttServer;
|
|
9
|
-
server;
|
|
10
|
-
serverOptions;
|
|
11
|
-
constructor(serverOptions, mqttOptions) {
|
|
12
|
-
this.mqttServer = new MqttServer(mqttOptions);
|
|
13
|
-
this.serverOptions = serverOptions;
|
|
14
|
-
}
|
|
15
|
-
start() {
|
|
16
|
-
this.server = createServer((sock) => this.mqttServer.serve(wrapNodeSocket(sock)));
|
|
17
|
-
this.server.listen(this.serverOptions.port, this.serverOptions.hostname);
|
|
18
|
-
}
|
|
19
|
-
stop() {
|
|
20
|
-
this.server?.close();
|
|
21
|
-
}
|
|
22
|
-
get port() {
|
|
23
|
-
const address = this.server?.address();
|
|
24
|
-
if (typeof address === "object") {
|
|
25
|
-
return address?.port;
|
|
26
|
-
}
|
|
27
|
-
return this.serverOptions?.port;
|
|
28
|
-
}
|
|
29
|
-
get address() {
|
|
30
|
-
const addressResult = this.server?.address();
|
|
31
|
-
if (typeof addressResult === "object") {
|
|
32
|
-
const address = addressResult?.address;
|
|
33
|
-
if (address === "::") {
|
|
34
|
-
return "localhost";
|
|
35
|
-
}
|
|
36
|
-
if (address?.includes(":")) {
|
|
37
|
-
return `[${address}]`;
|
|
38
|
-
}
|
|
39
|
-
return address;
|
|
40
|
-
}
|
|
41
|
-
return addressResult;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Writable } from "node:stream";
|
|
2
|
-
function closer(sock) {
|
|
3
|
-
if (!sock.closed) {
|
|
4
|
-
sock.end();
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
export function wrapNodeSocket(socket) {
|
|
8
|
-
const readable = new ReadableStream({
|
|
9
|
-
type: "bytes",
|
|
10
|
-
start(controller) {
|
|
11
|
-
socket.on("data", (data) => {
|
|
12
|
-
controller.enqueue(data);
|
|
13
|
-
const desiredSize = controller.desiredSize ?? 0;
|
|
14
|
-
if (desiredSize <= 0) {
|
|
15
|
-
// The internal queue is full, so propagate
|
|
16
|
-
// the backpressure signal to the underlying source.
|
|
17
|
-
socket.pause();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
socket.on("error", (err) => controller.error(err));
|
|
21
|
-
socket.on("end", () => {
|
|
22
|
-
// close the controller
|
|
23
|
-
controller.close();
|
|
24
|
-
// and unlock the last BYOB read request
|
|
25
|
-
controller.byobRequest?.respond(0);
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
pull: () => {
|
|
29
|
-
socket.resume();
|
|
30
|
-
},
|
|
31
|
-
cancel: () => {
|
|
32
|
-
socket.end();
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
const writable = Writable.toWeb(socket);
|
|
36
|
-
const remoteAddr = {
|
|
37
|
-
hostname: socket.remoteAddress || "",
|
|
38
|
-
port: socket.remotePort || 0,
|
|
39
|
-
};
|
|
40
|
-
const conn = {
|
|
41
|
-
readable: readable,
|
|
42
|
-
writable: writable,
|
|
43
|
-
close: () => closer(socket),
|
|
44
|
-
remoteAddr,
|
|
45
|
-
};
|
|
46
|
-
return conn;
|
|
47
|
-
}
|
package/dist/persistence/deps.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { Trie, } from "../deps.js";
|
|
2
|
-
import { assert } from "../../utils/mod.js";
|
|
3
|
-
const maxPacketId = 0xffff;
|
|
4
|
-
export class MemoryStore {
|
|
5
|
-
clientId;
|
|
6
|
-
packetId;
|
|
7
|
-
pendingIncoming;
|
|
8
|
-
pendingOutgoing;
|
|
9
|
-
pendingAckOutgoing;
|
|
10
|
-
subscriptions;
|
|
11
|
-
constructor(clientId) {
|
|
12
|
-
this.packetId = 0;
|
|
13
|
-
this.pendingIncoming = new Map();
|
|
14
|
-
this.pendingOutgoing = new Map();
|
|
15
|
-
this.pendingAckOutgoing = new Set();
|
|
16
|
-
this.subscriptions = new Map();
|
|
17
|
-
this.clientId = clientId;
|
|
18
|
-
}
|
|
19
|
-
nextId() {
|
|
20
|
-
const currentId = this.packetId;
|
|
21
|
-
do {
|
|
22
|
-
this.packetId++;
|
|
23
|
-
if (this.packetId > maxPacketId) {
|
|
24
|
-
this.packetId = 0;
|
|
25
|
-
}
|
|
26
|
-
} while ((this.pendingOutgoing.has(this.packetId) ||
|
|
27
|
-
this.pendingAckOutgoing.has(this.packetId)) &&
|
|
28
|
-
this.packetId !== currentId);
|
|
29
|
-
assert(this.packetId !== currentId, "No unused packetId available");
|
|
30
|
-
return this.packetId;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export class MemoryPersistence {
|
|
34
|
-
clientList;
|
|
35
|
-
retained;
|
|
36
|
-
trie;
|
|
37
|
-
constructor() {
|
|
38
|
-
this.clientList = new Map();
|
|
39
|
-
this.retained = new Map();
|
|
40
|
-
this.trie = new Trie(true);
|
|
41
|
-
}
|
|
42
|
-
registerClient(clientId, handler, clean) {
|
|
43
|
-
const existingClient = this.clientList.get(clientId);
|
|
44
|
-
const store = !clean && existingClient
|
|
45
|
-
? existingClient.store
|
|
46
|
-
: new MemoryStore(clientId);
|
|
47
|
-
this.clientList.set(clientId, { store, handler });
|
|
48
|
-
return store;
|
|
49
|
-
}
|
|
50
|
-
deregisterClient(clientId) {
|
|
51
|
-
const client = this.clientList.get(clientId);
|
|
52
|
-
if (client) {
|
|
53
|
-
this.unsubscribeAll(client.store);
|
|
54
|
-
this.clientList.delete(clientId);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
subscribe(store, topicFilter, qos) {
|
|
58
|
-
const clientId = store.clientId;
|
|
59
|
-
if (!store.subscriptions.has(topicFilter)) {
|
|
60
|
-
store.subscriptions.set(topicFilter, qos);
|
|
61
|
-
this.trie.add(topicFilter, { clientId, qos });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
unsubscribe(store, topicFilter) {
|
|
65
|
-
const clientId = store.clientId;
|
|
66
|
-
const qos = store.subscriptions.get(topicFilter);
|
|
67
|
-
if (qos) {
|
|
68
|
-
store.subscriptions.delete(topicFilter);
|
|
69
|
-
this.trie.remove(topicFilter, { clientId, qos });
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
unsubscribeAll(store) {
|
|
73
|
-
for (const [topicFilter, _qos] of store.subscriptions) {
|
|
74
|
-
this.unsubscribe(store, topicFilter);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
publish(topic, packet) {
|
|
78
|
-
if (packet.retain) {
|
|
79
|
-
this.retained.set(packet.topic, packet);
|
|
80
|
-
if (packet.payload === undefined) {
|
|
81
|
-
this.retained.delete(packet.topic);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// dedup clients
|
|
85
|
-
const clients = new Map();
|
|
86
|
-
for (const { clientId, qos } of this.trie.match(topic)) {
|
|
87
|
-
const prevQos = clients.get(clientId);
|
|
88
|
-
if (!prevQos || prevQos < qos) {
|
|
89
|
-
clients.set(clientId, qos);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// publish the message to all clients
|
|
93
|
-
for (const [clientId, qos] of clients) {
|
|
94
|
-
const newPacket = Object.assign({}, packet);
|
|
95
|
-
newPacket.retain = false;
|
|
96
|
-
newPacket.qos = qos;
|
|
97
|
-
// logger.debug(`publish ${topic} to client ${clientId}`);
|
|
98
|
-
const client = this.clientList.get(clientId);
|
|
99
|
-
client?.handler(packet);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
handleRetained(clientId) {
|
|
103
|
-
const retainedTrie = new Trie();
|
|
104
|
-
const client = this.clientList.get(clientId);
|
|
105
|
-
const store = client?.store;
|
|
106
|
-
if (store) {
|
|
107
|
-
for (const [topicFilter, _qos] of store.subscriptions) {
|
|
108
|
-
retainedTrie.add(topicFilter, clientId);
|
|
109
|
-
}
|
|
110
|
-
for (const [topic, packet] of this.retained) {
|
|
111
|
-
if (retainedTrie.match(topic).length > 0) {
|
|
112
|
-
client?.handler(packet);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/server/context.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { logger, MqttConn, PacketNameByType, PacketType, } from "./deps.js";
|
|
2
|
-
export const SysPrefix = "$";
|
|
3
|
-
export const utf8Encoder = new TextEncoder();
|
|
4
|
-
/**
|
|
5
|
-
* The Context class is used to maintain state of a MQTT connection
|
|
6
|
-
* It handles:
|
|
7
|
-
* - connect/disconnect including broadcasting of these events
|
|
8
|
-
* - publish
|
|
9
|
-
* - persistence
|
|
10
|
-
* - the will
|
|
11
|
-
*/
|
|
12
|
-
export class Context {
|
|
13
|
-
connected;
|
|
14
|
-
conn;
|
|
15
|
-
mqttConn;
|
|
16
|
-
persistence;
|
|
17
|
-
handlers;
|
|
18
|
-
static clientList = new Map();
|
|
19
|
-
store;
|
|
20
|
-
will;
|
|
21
|
-
timer;
|
|
22
|
-
constructor(persistence, conn, handlers) {
|
|
23
|
-
this.persistence = persistence;
|
|
24
|
-
this.connected = false;
|
|
25
|
-
this.conn = conn;
|
|
26
|
-
this.mqttConn = new MqttConn({ conn });
|
|
27
|
-
this.handlers = handlers;
|
|
28
|
-
}
|
|
29
|
-
async send(packet) {
|
|
30
|
-
logger.debug("Sending", PacketNameByType[packet.type]);
|
|
31
|
-
logger.debug(JSON.stringify(packet, null, 2));
|
|
32
|
-
await this.mqttConn.send(packet);
|
|
33
|
-
}
|
|
34
|
-
connect(clientId, clean) {
|
|
35
|
-
logger.debug("Connecting", clientId);
|
|
36
|
-
const existingSession = Context.clientList.get(clientId);
|
|
37
|
-
if (existingSession) {
|
|
38
|
-
existingSession.close(false);
|
|
39
|
-
}
|
|
40
|
-
this.store = this.persistence.registerClient(clientId, this.doPublish.bind(this), clean);
|
|
41
|
-
this.connected = true;
|
|
42
|
-
this.broadcast("$SYS/connect/clients", clientId);
|
|
43
|
-
logger.debug("Connected", clientId);
|
|
44
|
-
}
|
|
45
|
-
doPublish(packet) {
|
|
46
|
-
const qos = packet.qos || 0;
|
|
47
|
-
if (qos === 0) {
|
|
48
|
-
packet.id = 0;
|
|
49
|
-
this.send(packet);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (this.store) {
|
|
53
|
-
packet.id = this.store.nextId();
|
|
54
|
-
this.store.pendingOutgoing.set(packet.id, packet);
|
|
55
|
-
this.send(packet);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
clean(clientId) {
|
|
59
|
-
this.persistence.deregisterClient(clientId);
|
|
60
|
-
}
|
|
61
|
-
close(executewill = true) {
|
|
62
|
-
if (this.connected) {
|
|
63
|
-
logger.debug(`Closing ${this.store?.clientId} while mqttConn is ${this.mqttConn.isClosed ? "" : "not "}closed`);
|
|
64
|
-
this.connected = false;
|
|
65
|
-
if (typeof this.timer === "object") {
|
|
66
|
-
this.timer.clear();
|
|
67
|
-
}
|
|
68
|
-
if (this.store) {
|
|
69
|
-
this.broadcast("$SYS/disconnect/clients", this.store.clientId);
|
|
70
|
-
}
|
|
71
|
-
if (executewill) {
|
|
72
|
-
this.handleWill();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (!this.mqttConn.isClosed) {
|
|
76
|
-
this.mqttConn.close();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
handleWill() {
|
|
80
|
-
if (this.will) {
|
|
81
|
-
if (!this.will.topic.startsWith(SysPrefix) &&
|
|
82
|
-
this.handlers.isAuthorizedToPublish &&
|
|
83
|
-
this.handlers.isAuthorizedToPublish(this, this.will.topic)) {
|
|
84
|
-
this.persistence.publish(this.will.topic, this.will);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
broadcast(topic, payload, retain = false) {
|
|
89
|
-
const packet = {
|
|
90
|
-
type: PacketType.publish,
|
|
91
|
-
topic,
|
|
92
|
-
retain,
|
|
93
|
-
payload: utf8Encoder.encode(payload),
|
|
94
|
-
};
|
|
95
|
-
if (packet.retain === true) {
|
|
96
|
-
this.persistence.retained.set(packet.topic, packet);
|
|
97
|
-
}
|
|
98
|
-
this.persistence.publish(packet.topic, packet);
|
|
99
|
-
}
|
|
100
|
-
}
|
package/dist/server/deps.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { MqttConn } from "../mqttConn/mqttConn.js";
|
|
2
|
-
export { MemoryPersistence } from "../persistence/memory/memoryPersistence.js";
|
|
3
|
-
export { AuthenticationResult, PacketNameByType, PacketType, } from "../mqttPacket/mod.js";
|
|
4
|
-
export { Timer } from "../timer/timer.js";
|
|
5
|
-
export { logger } from "../utils/mod.js";
|