UNPKG

@kaaiot/mqtt-client

Version:

Comprehensive MQTT client tailored for the Kaa IoT platform, providing a range of methods to interact with the platform's features.

321 lines (320 loc) 14.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (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 __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.KaaMqttClient = void 0; var mqtt = __importStar(require("mqtt")); var crypto_1 = require("crypto"); var json_1 = require("./json"); var KaaMqttClient = /** @class */ (function () { function KaaMqttClient(clientOptions, options) { this.clientOptions = clientOptions; this.subscriptions = {}; var appVersionName = clientOptions.appVersionName, token = clientOptions.token; this.client = mqtt.connect(this.getConnectionUrl(clientOptions), __assign({ keepalive: 60 }, options)); this.client.on('error', function (error) { console.error('Error occurred:', error); }); this.appVersionName = appVersionName; this.token = token; this.client.on('message', this.handleMessage.bind(this)); } KaaMqttClient.prototype.handleMessage = function (topic, messageBuffer) { var _this = this; var message = messageBuffer.toString(); Object.keys(this.subscriptions).forEach(function (baseTopic) { if (topic.startsWith(baseTopic)) { _this.debugLog('[MESSAGE] Handling message for topic', topic); var _a = _this.subscriptions[baseTopic], callback = _a.callback, errorCallback = _a.errorCallback; if (topic.endsWith('/status') && callback) { var payload = (0, json_1.safeJson)(message); callback(payload, topic); } else if (topic.endsWith('/error') && errorCallback) { var error = (0, json_1.safeJson)(message); errorCallback(error, topic); } } }); }; KaaMqttClient.prototype.debugLog = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (this.clientOptions.debug) { console.debug.apply(console, __spreadArray(['[KaaMqttClient] '], args, true)); } }; KaaMqttClient.prototype.getConnectionUrl = function (options) { if (options.hostname) { return "mqtt://".concat(options.hostname, ":").concat(options.port || 1883); } if (options.connectionUrl) { return options.connectionUrl; } if (!options.hostname && !options.connectionUrl) { throw new Error('Either hostname or connectionUrl must be specified'); } return ''; }; KaaMqttClient.prototype.subscribeToResponseTopics = function (baseTopic, callback, errorCallback) { var _this = this; if (!callback && !errorCallback) { return; } this.subscriptions[baseTopic] = { callback: callback, errorCallback: errorCallback }; this.client.subscribe("".concat(baseTopic, "/+"), function (err, granted) { if (err) { _this.debugLog('[SUBSCRIBE] Error subscribing to topic', baseTopic, err); errorCallback && errorCallback({ reasonPhrase: err.message, statusCode: 500 }, baseTopic); } else { if (granted && granted[0]) { _this.debugLog('[SUBSCRIBE] Subscribed to topic', granted[0].topic); } } }); }; /** * Publish single or multiple data samples * * @param dataSamples * @param callback * @param errorCallback * @param requestId */ KaaMqttClient.prototype.publishDataCollection = function (dataSamples, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/dcx/").concat(this.token, "/json").concat(requestId ? "/".concat(requestId) : ''); var payload = JSON.stringify(dataSamples); this.debugLog('[DATA COLLECTION] Sending data samples', topic, payload); this.client.publish(topic, payload); this.subscribeToResponseTopics(topic, callback, errorCallback); }; /** * Publish plain data sample with a metric name * * @param metricName * @param dataSample * @param callback * @param errorCallback * @param requestId */ KaaMqttClient.prototype.publishPlainDataSample = function (metricName, dataSample, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/dcx/").concat(this.token, "/plain/").concat(metricName).concat(requestId ? "/".concat(requestId) : ''); var payload = typeof dataSample === 'string' ? dataSample : dataSample.toString(); this.debugLog('[DATA COLLECTION] Sending data samples', topic, payload); this.client.publish(topic, payload); this.subscribeToResponseTopics(topic, callback, errorCallback); }; /** * Get all metadata keys * * @param callback * @param errorCallback * @param requestId */ KaaMqttClient.prototype.getAllMetadataKeys = function (callback, errorCallback, requestId) { if (requestId === void 0) { requestId = (0, crypto_1.randomInt)(1, 100).toString(); } var topic = "kp1/".concat(this.appVersionName, "/epmx/").concat(this.token, "/get/keys/").concat(requestId); this.debugLog('[METADATA] Getting all metadata keys', topic); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, ''); }; /** * Get all metadata values * * @param callback * @param errorCallback * @param requestId */ KaaMqttClient.prototype.getMetadata = function (callback, errorCallback, requestId) { if (requestId === void 0) { requestId = (0, crypto_1.randomInt)(1, 100).toString(); } var topic = "kp1/".concat(this.appVersionName, "/epmx/").concat(this.token, "/get/").concat(requestId); this.debugLog('[METADATA] Getting metadata', topic); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, ''); }; /** * Full metadata update * * @param payload * @param requestId * @param callback * @param errorCallback */ KaaMqttClient.prototype.publishMetadata = function (payload, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/epmx/").concat(this.token, "/update").concat(requestId ? "/".concat(requestId) : ''); this.debugLog('[METADATA] Publish full metadata update', topic, payload); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, JSON.stringify(payload)); }; /** * Partially update metadata keys * * @param metadata * @param requestId * @param callback * @param errorCallback */ KaaMqttClient.prototype.publishMetadataKeys = function (metadata, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/epmx/").concat(this.token, "/update/keys").concat(requestId ? "/".concat(requestId) : ''); this.debugLog('[METADATA] Publish metadata keys update', topic, metadata); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, JSON.stringify(metadata)); }; /** * Delete list of metadata keys * * @param keys * @param callback * @param errorCallback * @param requestId */ KaaMqttClient.prototype.deleteMetadataKeys = function (keys, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/epmx/").concat(this.token, "/delete/keys").concat(requestId ? "/".concat(requestId) : ''); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, JSON.stringify(keys)); }; /** * Get list of pending commands. * Callback is called with the list of pending commands and a handler to report the results. * Report handler should be called with the results of the command execution. * * @example * ```typescript * client.getPendingCommands('commandType', (commands, topic, reportHandler) => { * // Handle commands * const results = commands.map((command) => { * // Execute command * return { * id: command.id, * statusCode: 200, * payload: 'OK', * }; * }); * ``` * * @param commandType * @param callback * @param errorCallback */ KaaMqttClient.prototype.getPendingCommands = function (commandType, callback, errorCallback) { var _this = this; var topic = "kp1/".concat(this.appVersionName, "/cex/").concat(this.token, "/command/").concat(commandType); this.debugLog('[COMMANDS] Subscribing to commands', "".concat(topic, "/+")); this.subscribeToResponseTopics(topic, callback ? function (response) { callback(response, topic, function (results, errorCallback) { _this.reportCommandExecutionResult(commandType, results, errorCallback); }); } : undefined, errorCallback); }; KaaMqttClient.prototype.reportCommandExecutionResult = function (commandType, results, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/cex/").concat(this.token, "/result/").concat(commandType).concat(requestId ? "/".concat(requestId) : ''); var payload = JSON.stringify(results); this.subscribeToResponseTopics(topic, undefined, errorCallback); this.client.publish(topic, payload); }; KaaMqttClient.prototype.getConfigurationJson = function (payload, callback, errorCallback, requestId) { var _this = this; if (payload === void 0) { payload = {}; } var configTopic = "kp1/".concat(this.appVersionName, "/cmx/").concat(this.token, "/config/json").concat(requestId ? "/".concat(requestId) : ''); this.client.publish(configTopic, JSON.stringify(payload)); this.debugLog('[CONFIGURATION] Getting configuration', configTopic); this.subscribeToResponseTopics(configTopic, callback ? function (response, topic) { callback(response, topic, function (config, errorCallback) { _this.reportAppliedConfiguration(config, undefined, errorCallback); }); } : undefined, errorCallback); }; KaaMqttClient.prototype.reportAppliedConfiguration = function (payload, callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/cmx/").concat(this.token, "/applied/json").concat(requestId ? "/".concat(requestId) : ''); this.client.publish(topic, JSON.stringify(payload)); this.debugLog('[CONFIGURATION] Reporting applied configuration', topic, payload); this.subscribeToResponseTopics(topic, callback, errorCallback); }; KaaMqttClient.prototype.reportCurrentSoftwareVersion = function (payload, callback, errorCallback) { var topic = "kp1/".concat(this.appVersionName, "/cmx_ota/").concat(this.token, "/applied/json"); this.debugLog('[SOFTWARE] Reporting current software version', topic, payload); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, JSON.stringify(payload)); }; KaaMqttClient.prototype.getSoftwareUpdate = function (callback, errorCallback, requestId) { var topic = "kp1/".concat(this.appVersionName, "/cmx_ota/").concat(this.token, "/config/json").concat(requestId ? "/".concat(requestId) : ''); this.debugLog('[SOFTWARE] Getting software version', topic); this.subscribeToResponseTopics(topic, callback, errorCallback); this.client.publish(topic, JSON.stringify({})); }; /** * Safely unsubscribe from all subscriptions and clear the subscriptions record. */ KaaMqttClient.prototype.disconnect = function (callback) { var _this = this; var topics = Object.keys(this.subscriptions); if (topics.length === 0) { this.client.end(callback); return; } this.client.unsubscribe(topics, function (err) { if (err) { _this.debugLog('[DESTROY] Error unsubscribing from topics', err); } else { _this.debugLog('[DESTROY] Successfully unsubscribed from all topics'); } _this.subscriptions = {}; _this.client.end(callback); }); }; KaaMqttClient.prototype.connect = function () { this.client.connect(); }; return KaaMqttClient; }()); exports.KaaMqttClient = KaaMqttClient;