UNPKG

gp-mqtt-client

Version:

Simple MQTT Client (no auth, decode base64, ...)

239 lines 10.9 kB
"use strict"; /** * gp-mqtt-client | Simple MQTT Client * * @author Greg PFISTER * @since 0.1.0 * @license MIT * @copyright (C) 2021, Greg PFISTER. MIT License * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GPMqttController = void 0; const events_1 = __importDefault(require("events")); const fs_1 = require("fs"); const promises_1 = require("fs/promises"); const log4js = __importStar(require("log4js")); const mqtt_1 = require("mqtt"); const uuid_1 = require("uuid"); /** * MQTT Controller */ class GPMqttController extends events_1.default { /** * Build a MQTT Controller that will connect to an MQTT server via TCP * @param hostname The hostname * @param port The port number * @param protocol The protocol (e.g. mqtt). Only mqtt supported for the time been * @param autoConnect Specifies if the client will autoconnect after been disconnected * @param verbose Output info message * @param debug Output debug message */ constructor(hostname, port, protocol, autoConnect, verbose = false, debug = false) { super(); this._hostname = hostname; this._port = port; this._protocol = protocol; this._deviceId = (0, uuid_1.v4)().toString(); this._autoConnect = autoConnect; // Configure the logger const logLevel = debug ? 'debug' : (verbose ? 'info' : 'warn'); log4js.configure({ appenders: { client: { type: 'console' } }, categories: { default: { appenders: ['client'], level: logLevel } } }); this._logger = log4js.getLogger('client'); } /** * Connect to the MQTT server */ connect() { const mqttClientId = `${this._deviceId}`; this._logger.debug(`[MQTT Controller] Connecting to ${this._hostname}:${this._port} with client id ${mqttClientId}`); // Create a client, and connect to the Google MQTT bridge. this._client = (0, mqtt_1.connect)({ host: this._hostname, port: this._port, protocol: this._protocol, keepalive: 10, clientId: this._deviceId, protocolId: 'MQTT', protocolVersion: 5, clean: true, reconnectPeriod: 20000, connectTimeout: 30 * 1000, rejectUnauthorized: false }); // On successful connection this._client.on('connect', (packet) => { this._logger.info(`[MQTT Controller] Connected to ${this._hostname}:${this._port} with client id ${mqttClientId}`); this.emit('connected'); // // Attach all boundDevices // this._topics.forEach((topic) => { // if (this._client) { // this._client.subscribe(topic.name, { qos: topic.qos }); // this._logger.info(`[MQTT Controller] Subscribed to ${topic.name}`); // } // }); }); // On errors this._client.on('error', (error) => { this._logger.error(`[MQTT Controller] Error ${error.name}: ${error.message}`); }); // On disconnected this._client.on('close', () => { this._logger.info(`[MQTT Controller] Disconnected from ${this._hostname}:${this._port}`); if (this._client) { this._client.end(); } if (this._autoConnect) { this._logger.info(`[MQTT Controller] Reconnecting to ${this._hostname}:${this._port} in 1 minute...`); setTimeout(() => this.connect(), 60 * 1000); } }); // On disconnected this._client.on('disconnect', (_) => { this._logger.warn(`[MQTT Controller] Disconnected from ${this._hostname}:${this._port}`); if (this._autoConnect) { this._logger.warn(`[MQTT Controller] Reconnecting to ${this._hostname}:${this._port} in 1 minute...`); setTimeout(() => this.connect(), 60 * 1000); } }); } /** * Subscribe to a topic * @param topic The topic to subscribe to * @param options Options */ subscribe(topic, options) { if (!this._topic) { this._topic = topic; if (this._client && this._client.connected) { // Handle incomming messages this._client.on('message', async (topic, message) => { this._logger.info(`[MQTT Controller] Message received on topic ${topic}`); if (options.useBase64Decoding) { this._logger.debug('[MQTT Controller] Apply base64 decoding'); } const decodedMessage = options.useBase64Decoding ? Buffer.from(message.toString(), 'base64').toString('binary') : message.toString(); if (options.outputPrettyJson) { this._logger.debug('[MQTT Controller] Apply JSON pretty print'); } const output = options.outputPrettyJson ? JSON.stringify(JSON.parse(decodedMessage), null, 2) : decodedMessage; if (options.outputFolder) { const folder = `${options.outputFolder}${topic}`; if (!(0, fs_1.existsSync)(folder)) { try { await (0, promises_1.mkdir)(folder, { recursive: true }); } catch (error) { this._logger.error(`[MQTT Controller] Unable to create folder ${folder}: ${error}`); } } const now = new Date(); let file = `${folder}/${now.toISOString()}`; if (options.outputPrettyJson) { file = `${file}.json`; } this._logger.info(`[MQTT Controller] Message written to file ${file}`); try { await (0, promises_1.writeFile)(file, output); this._logger.info(`[MQTT Controller] Message written to file ${file}`); } catch (error) { this._logger.error(`[MQTT Controller] Unable to write message to file ${file}: ${error}`); } } else { console.log(output); } if (!options.listen) { process.exit(0); } // const decodedMessage = JSON.parse(Buffer.from(message.toString(), 'base64').toString('binary')); // this._logger.info(`[MQTT Controller] message received on topic ${topic}`); // let i = 0; // while (i < message.toString().length) { // const r = message.toString().length - i; // if (r > 80) { // console.log(` ${message.toString().substring(i, i + 80)}`); // i += 80; // } else { // console.log(` ${message.toString().substring(i, message.toString().length)}`); // i = message.toString().length; // } // } // // console.log(`${message}`); // this._logger.info('[MQTT Controller] Message decoded:'); // console.log(`${JSON.stringify(decodedMessage, null, 2)}`); }); this._client.on('packetreceive', (packet) => { if (packet.cmd === 'suback') { this._logger.info(`[MQTT Controller] Subscribed to topic ${topic.name}`); } }); // Subscribe to topic this._logger.debug(`[MQTT Controller] Subscribing to topic ${topic.name}`); this._client.subscribe(topic.name, { qos: topic.qos }); if (!options.listen) { setTimeout(() => { this._logger.info('[MQTT Controller] Timeout (1s)'); process.exit(0); }, 1000); } } } } /** * Subscribe to a topic * @param topic The topic to publish to * @param message The message to publish * @param options Options */ publish(topic, message, options) { if (!this._topic) { this._topic = topic; if (this._client && this._client.connected) { this._client.on('packetreceive', (packet) => { if (packet.cmd === 'puback' && this._client) { this._logger.info(`[MQTT Controller] Message published to topic ${topic.name}`); this._client.end(); } }); this._logger.debug(`[MQTT Controller] Publishing to topic ${topic.name}`); this._client.publish(topic.name, message, { qos: topic.qos, retain: options.retain }); } } } } exports.GPMqttController = GPMqttController; //# sourceMappingURL=mqtt.controller.js.map