@nestjs/microservices
Version:
Nest - modern, fast, powerful node.js web framework (@microservices)
148 lines (147 loc) • 5.93 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerMqtt = void 0;
const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
const constants_1 = require("../constants");
const mqtt_context_1 = require("../ctx-host/mqtt.context");
const enums_1 = require("../enums");
const mqtt_record_serializer_1 = require("../serializers/mqtt-record.serializer");
const server_1 = require("./server");
let mqttPackage = {};
class ServerMqtt extends server_1.Server {
constructor(options) {
super();
this.options = options;
this.transportId = enums_1.Transport.MQTT;
this.url = this.getOptionsProp(options, 'url') || constants_1.MQTT_DEFAULT_URL;
mqttPackage = this.loadPackage('mqtt', ServerMqtt.name, () => require('mqtt'));
this.initializeSerializer(options);
this.initializeDeserializer(options);
}
async listen(callback) {
try {
this.mqttClient = this.createMqttClient();
this.start(callback);
}
catch (err) {
callback(err);
}
}
start(callback) {
this.handleError(this.mqttClient);
this.bindEvents(this.mqttClient);
this.mqttClient.on(constants_1.CONNECT_EVENT, () => callback());
}
bindEvents(mqttClient) {
mqttClient.on(constants_1.MESSAGE_EVENT, this.getMessageHandler(mqttClient).bind(this));
const registeredPatterns = [...this.messageHandlers.keys()];
registeredPatterns.forEach(pattern => {
const { isEventHandler } = this.messageHandlers.get(pattern);
mqttClient.subscribe(isEventHandler ? pattern : this.getRequestPattern(pattern), this.getOptionsProp(this.options, 'subscribeOptions'));
});
}
close() {
this.mqttClient && this.mqttClient.end();
}
createMqttClient() {
return mqttPackage.connect(this.url, this.options);
}
getMessageHandler(pub) {
return async (channel, buffer, originalPacket) => this.handleMessage(channel, buffer, pub, originalPacket);
}
async handleMessage(channel, buffer, pub, originalPacket) {
const rawPacket = this.parseMessage(buffer.toString());
const packet = await this.deserializer.deserialize(rawPacket, { channel });
const mqttContext = new mqtt_context_1.MqttContext([channel, originalPacket]);
if ((0, shared_utils_1.isUndefined)(packet.id)) {
return this.handleEvent(channel, packet, mqttContext);
}
const publish = this.getPublisher(pub, channel, packet.id);
const handler = this.getHandlerByPattern(channel);
if (!handler) {
const status = 'error';
const noHandlerPacket = {
id: packet.id,
status,
err: constants_1.NO_MESSAGE_HANDLER,
};
return publish(noHandlerPacket);
}
const response$ = this.transformToObservable(await handler(packet.data, mqttContext));
response$ && this.send(response$, publish);
}
getPublisher(client, pattern, id) {
return (response) => {
Object.assign(response, { id });
const outgoingResponse = this.serializer.serialize(response);
const options = outgoingResponse.options;
delete outgoingResponse.options;
return client.publish(this.getReplyPattern(pattern), JSON.stringify(outgoingResponse), options);
};
}
parseMessage(content) {
try {
return JSON.parse(content);
}
catch (e) {
return content;
}
}
matchMqttPattern(pattern, topic) {
const patternSegments = pattern.split(constants_1.MQTT_SEPARATOR);
const topicSegments = topic.split(constants_1.MQTT_SEPARATOR);
const patternSegmentsLength = patternSegments.length;
const topicSegmentsLength = topicSegments.length;
const lastIndex = patternSegmentsLength - 1;
for (let i = 0; i < patternSegmentsLength; i++) {
const currentPattern = patternSegments[i];
const patternChar = currentPattern[0];
const currentTopic = topicSegments[i];
if (!currentTopic && !currentPattern) {
continue;
}
if (!currentTopic && currentPattern !== constants_1.MQTT_WILDCARD_ALL) {
return false;
}
if (patternChar === constants_1.MQTT_WILDCARD_ALL) {
return i === lastIndex;
}
if (patternChar !== constants_1.MQTT_WILDCARD_SINGLE &&
currentPattern !== currentTopic) {
return false;
}
}
return patternSegmentsLength === topicSegmentsLength;
}
getHandlerByPattern(pattern) {
const route = this.getRouteFromPattern(pattern);
if (this.messageHandlers.has(route)) {
return this.messageHandlers.get(route) || null;
}
for (const [key, value] of this.messageHandlers) {
const keyWithoutSharedPrefix = this.removeHandlerKeySharedPrefix(key);
if (this.matchMqttPattern(keyWithoutSharedPrefix, route)) {
return value;
}
}
return null;
}
removeHandlerKeySharedPrefix(handlerKey) {
return handlerKey && handlerKey.startsWith('$share')
? handlerKey.split('/').slice(2).join('/')
: handlerKey;
}
getRequestPattern(pattern) {
return pattern;
}
getReplyPattern(pattern) {
return `${pattern}/reply`;
}
handleError(stream) {
stream.on(constants_1.ERROR_EVENT, (err) => this.logger.error(err));
}
initializeSerializer(options) {
this.serializer = options?.serializer ?? new mqtt_record_serializer_1.MqttRecordSerializer();
}
}
exports.ServerMqtt = ServerMqtt;