@getanthill/datastore
Version:
Event-Sourced Datastore
119 lines • 4.29 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const async_mqtt_1 = __importDefault(require("async-mqtt"));
const merge_1 = __importDefault(require("lodash/merge"));
const get_1 = __importDefault(require("lodash/get"));
const unset_1 = __importDefault(require("lodash/unset"));
const omit_1 = __importDefault(require("lodash/omit"));
const broker_1 = __importDefault(require("./broker"));
class MQTTClient extends broker_1.default {
constructor() {
super(...arguments);
this._client = null;
}
get client() {
if (this._client === null) {
throw MQTTClient.ERRORS.NOT_CONNECTED;
}
return this._client;
}
async connect() {
if (this._client !== null) {
return this;
}
this._client = await async_mqtt_1.default.connectAsync(this.config.url, (0, merge_1.default)({}, this.config.options, {
protocolVersion: 5,
clean: true,
}));
this._client.on('message', this.onMessage.bind(this));
return this;
}
async end() {
if (this._client === null) {
return;
}
await this._client.end();
this._client = null;
return this;
}
authenticate(tokens, handler) {
return (event, route, headers, opts) => {
const token = headers?.['authorization'];
if (tokens.find((t) => t.token === token)) {
return handler(event, route, headers, opts);
}
this.telemetry?.logger.debug('[events#authenticate] Authentication failed', {
event,
});
};
}
onMessage(topic, message, packet) {
const route = this.getRoute(topic);
if (route === null) {
return;
}
const event = JSON.parse(message.toString());
const headers = packet?.properties?.userProperties || {};
this.telemetry?.logger.debug('[services#mqtt] Handling event', {
topic,
event,
headers: (0, omit_1.default)(headers, 'authorization'),
});
const isValid = route.validate(event);
if (!isValid) {
this.logOnInvalid(event, route);
return;
}
/* istanbul ignore next */
const ack = async () => null;
/* istanbul ignore next */
const nack = async () => null;
this.emit(route.original, event, this.parseTopic(topic, route), headers, {
source: 'mqtt',
original: packet,
delivery: 0,
ack,
nack,
});
}
publish(topic, payload, options = {}) {
let _options = (0, merge_1.default)({}, {
properties: {
userProperties: (0, get_1.default)(this.config, 'options.properties.userProperties', {}),
},
}, options);
if (Object.keys((0, get_1.default)(_options, 'properties.userProperties', {})).length === 0) {
_options = (0, unset_1.default)(_options, 'properies.userProperties');
}
return this.client.publish(this.topicWithNamespace(topic), JSON.stringify(payload), _options);
}
subscribe(topic, schema) {
const mappedTopic = this.mapTopic(topic, schema);
this.topics.set(mappedTopic.topic, mappedTopic);
this.addChannelToSpec(topic, schema);
return this.client.subscribe(`$share/${this.config.group}/${mappedTopic.topic}`);
}
async next(topic, timeout = 1000) {
let resolve;
let _timeout;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
_timeout = setTimeout(() => _reject(new Error('[mqtt#next] Message timeout')), timeout);
});
const handler = (event) => {
clearTimeout(_timeout);
resolve(event);
this.removeListener(topic, handler);
};
this.on(topic, handler);
return promise;
}
}
MQTTClient.ERRORS = {
NOT_CONNECTED: new Error('MQTT not connected yet'),
};
exports.default = MQTTClient;
//# sourceMappingURL=mqtt.js.map