@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
JavaScript
"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;