Skip to content

Commit

Permalink
Compatibility with node versions pre 22.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
seriousme committed Nov 2, 2024
1 parent 81e6f46 commit 2a46af5
Show file tree
Hide file tree
Showing 9 changed files with 2,515 additions and 7 deletions.
74 changes: 74 additions & 0 deletions dist/bin/demoServer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env node
import { createServer } from "node:net";
import {
A as AuthenticationResult,
L as LogLevel,
l as logger,
} from "../timer-DDWVNsyG.js";
import "node:process";
import { MqttServer } from "../server/mod.js";
import {
g as getArgs,
p as parseArgs,
w as wrapNodeSocket,
} from "../wrapNodeSocket-BAJm059T.js";
import "node:stream";

class TcpServer {
mqttServer;
server;
serverOptions;
constructor(serverOptions, mqttOptions) {
this.mqttServer = new MqttServer(mqttOptions);
this.serverOptions = serverOptions;
}
start() {
this.server = createServer(
(sock) => this.mqttServer.serve(wrapNodeSocket(sock)),
);
this.server.listen(this.serverOptions.port, this.serverOptions.hostname);
}
stop() {
this.server?.close();
}
get port() {
return this.serverOptions.port;
}
}

const utf8Decoder = new TextDecoder();
const userTable = /* @__PURE__ */ new Map();
userTable.set("IoTester_1", "strong_password");
userTable.set("IoTester_2", "strong_password");
function isAuthenticated(_ctx, clientId, username, password) {
const pwd = utf8Decoder.decode(password);
logger.info(
`Verifying authentication of client '${clientId}' with username '${username}' and password '${pwd}'`,
);
return AuthenticationResult.ok;
}
function isAuthorizedToPublish(ctx, topic) {
logger.debug(
`Checking authorization of client '${ctx.store?.clientId}' to publish on topic '${topic}'`,
);
return true;
}
function isAuthorizedToSubscribe(ctx, topic) {
logger.debug(
`Checking authorization of client '${ctx.store?.clientId}' to subscribe to topic '${topic}'`,
);
return true;
}
const { _: [portNum] } = parseArgs(getArgs());
const port = Number(portNum ?? 1883);
const hostname = "::";
logger.level(LogLevel.info);
const tcpServer = new TcpServer({ port, hostname }, {
handlers: {
isAuthenticated,
isAuthorizedToPublish,
isAuthorizedToSubscribe,
},
});
tcpServer.start();
logger.info(`Server started on port ${tcpServer.port}`);
240 changes: 240 additions & 0 deletions dist/bin/mqtt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
#!/usr/bin/env node
import { C as Client, D as DEFAULT_URL } from "../client-DqLTBVC2.js";
import { L as LogLevel, l as logger } from "../timer-DDWVNsyG.js";
import {
g as getArgs,
p as parseArgs,
w as wrapNodeSocket,
} from "../wrapNodeSocket-BAJm059T.js";
import "node:process";
import { readFile } from "node:fs/promises";
import { connect } from "node:net";
import * as tls from "node:tls";
import "node:stream";

async function getCaCerts(filename) {
if (!filename) {
return;
}
const caCerts = await readFile(filename, { encoding: "utf-8" });
if (caCerts === "") {
return;
}
return [caCerts];
}
class TcpClient extends Client {
async connectMQTT(hostname, port = 1883) {
logger.debug({ hostname, port });
return wrapNodeSocket(await connect({ host: hostname, port }));
}
async connectMQTTS(hostname, port = 8883, caCerts) {
const opts = {
host: hostname,
port,
secureContext: caCerts
? tls.createSecureContext({ cert: caCerts })
: void 0,
};
logger.debug({ hostname, port, caCerts });
return wrapNodeSocket(await tls.connect(opts));
}
createConn(protocol, hostname, port, caCerts) {
if (protocol === "mqtts:") {
return this.connectMQTTS(hostname, port, caCerts);
}
if (protocol === "mqtt:") {
return this.connectMQTT(hostname, port);
}
throw `Unsupported protocol: ${protocol}`;
}
}

const client = new TcpClient();
const encoder = new TextEncoder();
const decoder = new TextDecoder();
logger.level(LogLevel.info);
const MQTTHelp = `MQTT command line interface, available commands are:
* publish publish a message to the broker
* subscribe subscribe for updates from the broker
Run 'mqtt [command] --help' to know more about the commands.`;
const ConnectHelp = `
-u/--url the URL to connect to: default is ${DEFAULT_URL}
-i/--clientId the clientId to connect to the server
-U/--username the username to connect to the server
-P/--password the password to connect to the server
-c/--certFile the path to a certFile
-n/--noClean try to resume a previous session
-h/--help this text
`;
const connectOpts = {
string: ["url", "username", "password", "certFile", "clientId"],
alias: {
u: "url",
U: "username",
P: "password",
c: "certFile",
i: "clientId",
n: "noClean",
h: "help",
},
boolean: ["noClean", "help"],
default: {
noClean: false,
},
};
const SubscribeHelp = `Usage: mqtt subscribe <options>
Where options are:
-t/--topic the topic to use
-q/--qos the QoS (0/1/2) to use, default is 0
${ConnectHelp}
Example: mqtt subscribe -t hello`;
const subscribeOpts = {
string: ["topic"],
alias: {
t: "topic",
q: "qos",
},
default: {
qos: 0,
topic: "",
},
};
function parseQos(qosArg) {
const qos = Number(qosArg);
switch (qos) {
case 0:
return 0;
case 1:
return 1;
case 2:
return 2;
}
console.log("QoS must be between 0 and 2");
return 0;
}
async function subscribe() {
const connectArgs = parseArgs(getArgs(), connectOpts);
const caCerts = await getCaCerts(connectArgs.certFile);
const subscribeArgs = parseArgs(getArgs(), subscribeOpts);
if (connectArgs.help) {
console.log(SubscribeHelp);
return;
}
if (subscribeArgs.topic === void 0) {
console.log("Missing `topic`");
return;
}
try {
await client.connect({
url: connectArgs.url,
caCerts,
options: {
username: connectArgs.username,
password: encoder.encode(connectArgs.password),
clientId: connectArgs.clientId,
clean: !connectArgs.noClean,
keepAlive: 60,
},
});
logger.debug("Connected !");
client.subscribe({
subscriptions: [
{
topicFilter: subscribeArgs.topic,
qos: parseQos(subscribeArgs.qos),
},
],
});
logger.debug("Subscribed!");
for await (const message of client.messages()) {
console.log(decoder.decode(message.payload));
}
} catch (err) {
if (err instanceof Error) {
logger.info(err.message);
}
}
}
const PublishHelp = `Usage: mqtt publish <options>
Where options are:
-t/--topic the topic to use
-m/--message the message to send
-q/--qos the QoS (0/1/2) to use, default is 0
-r/--retain if the message should be retained, default is false
${ConnectHelp}
Example: mqtt publish -t hello -m world`;
const publishOpts = {
string: ["topic", "message"],
boolean: ["retain"],
alias: {
t: "topic",
m: "message",
q: "qos",
r: "retain",
},
default: {
qos: 0,
dup: false,
retain: false,
topic: void 0,
message: "",
},
};
async function publish() {
const connectArgs = parseArgs(getArgs(), connectOpts);
const caCerts = await getCaCerts(connectArgs.certFile);
const publishArgs = parseArgs(getArgs(), publishOpts);
if (connectArgs.help) {
console.log(PublishHelp);
return;
}
if (publishArgs.topic === void 0) {
console.log("Missing `topic`");
return;
}
try {
await client.connect({
url: connectArgs.url,
caCerts,
options: {
username: connectArgs.username,
password: encoder.encode(connectArgs.password),
clientId: connectArgs.clientId,
clean: !connectArgs.noClean,
},
});
logger.debug("Connected !");
await client.publish({
topic: publishArgs.topic,
payload: encoder.encode(publishArgs.message),
retain: publishArgs.retain,
qos: parseQos(publishArgs.qos),
});
logger.debug("Published!");
client.disconnect();
logger.debug("Disconnected !");
} catch (err) {
if (err instanceof Error) {
logger.info(err.message);
}
}
}
function processArgs() {
const { _: [cmd] } = parseArgs(getArgs());
switch (cmd) {
case "publish":
publish();
break;
case "subscribe":
subscribe();
break;
default:
console.log(MQTTHelp);
break;
}
}
processArgs();
Loading

0 comments on commit 2a46af5

Please sign in to comment.