aws-crt
Version:
NodeJS bindings to the aws-c-* libraries
226 lines • 8.71 kB
JavaScript
"use strict";
/* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const mqtt_1 = require("mqtt");
const async_mqtt_1 = require("async-mqtt");
const WebsocketUtils = __importStar(require("./ws"));
const trie = __importStar(require("./trie"));
const event_1 = require("../common/event");
const browser_1 = require("../browser");
var mqtt_2 = require("../common/mqtt");
exports.QoS = mqtt_2.QoS;
exports.MqttWill = mqtt_2.MqttWill;
class MqttClient {
new_connection(config) {
return new MqttClientConnection(this, config);
}
}
exports.MqttClient = MqttClient;
class TopicTrie extends trie.Trie {
constructor() {
super('/');
}
find_node(key, op) {
const parts = this.split_key(key);
let current = this.root;
let parent = undefined;
for (const part in parts) {
let child = current.children.get(part);
if (!child) {
child = current.children.get('#');
if (child) {
return child;
}
child = current.children.get('+');
}
if (!child) {
if (op == trie.TrieOp.Insert) {
current.children.set(part, child = new trie.Node(part));
}
else {
return undefined;
}
}
parent = current;
current = child;
}
if (parent && op == trie.TrieOp.Delete) {
parent.children.delete(current.key);
}
return current;
}
}
function normalize_payload(payload) {
let payload_data = payload.toString();
if (payload instanceof DataView) {
payload_data = new TextDecoder('utf8').decode(payload);
}
else if (payload instanceof Object) {
// Convert payload to JSON string
payload_data = JSON.stringify(payload);
}
return payload_data;
}
class MqttClientConnection extends event_1.BufferedEventEmitter {
constructor(client, config) {
super();
this.client = client;
this.config = config;
this.subscriptions = new TopicTrie();
this.connection_count = 0;
this.on_online = (session_present) => {
if (++this.connection_count == 1) {
this.emit('connect', session_present);
}
else {
this.emit('resume', 0, session_present);
}
};
this.on_offline = () => {
this.emit('interrupt', -1);
};
this.on_disconnected = () => {
this.emit('disconnect');
};
this.on_message = (topic, payload, packet) => {
const callback = this.subscriptions.find(topic);
if (callback) {
callback(topic, payload);
}
this.emit('message', topic, payload);
};
const create_websocket_stream = (client) => WebsocketUtils.create_websocket_stream(this.config);
const transform_websocket_url = (url, options, client) => WebsocketUtils.create_websocket_url(this.config);
this.connection = new async_mqtt_1.AsyncClient(new mqtt_1.MqttClient(create_websocket_stream, {
keepalive: this.config.socket_options.keepalive ? this.config.socket_options.keep_alive_interval_sec : 0,
clientId: this.config.client_id,
connectTimeout: this.config.socket_options.connect_timeout_ms,
clean: this.config.clean_session,
username: this.config.username,
password: this.config.password,
reconnectPeriod: 0,
will: this.config.will ? {
topic: this.config.will.topic,
payload: normalize_payload(this.config.will.payload),
qos: this.config.will.qos,
retain: this.config.will.retain,
} : undefined,
transformWsUrl: (config.websocket || {}).protocol != 'wss-custom-auth' ? transform_websocket_url : undefined
}));
}
// Override to allow uncorking on connect
on(event, listener) {
super.on(event, listener);
if (event == 'connect') {
process.nextTick(() => {
this.uncork();
});
}
return this;
}
_reject(reject) {
return (reason) => {
reject(reason);
this.emit('error', new browser_1.CrtError(reason));
};
}
connect() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
reject = this._reject(reject);
try {
this.connection.on('connect', (connack) => {
resolve(connack.sessionPresent);
this.on_online(connack.sessionPresent);
});
this.connection.on('error', (error) => {
reject(`Failed to connect: error=${error}`);
});
this.connection.on('message', this.on_message);
this.connection.on('offline', this.on_offline);
this.connection.on('end', this.on_disconnected);
}
catch (e) {
reject(e);
}
});
});
}
reconnect() {
return __awaiter(this, void 0, void 0, function* () {
return this.connect();
});
}
publish(topic, payload, qos, retain = false) {
return __awaiter(this, void 0, void 0, function* () {
let payload_data = normalize_payload(payload);
return this.connection.publish(topic, payload_data, { qos: qos, retain: retain })
.catch((reason) => {
this.emit('error', new browser_1.CrtError(reason));
})
.then((value) => {
return { packet_id: value.messageId };
});
});
}
subscribe(topic, qos, on_message) {
return __awaiter(this, void 0, void 0, function* () {
this.subscriptions.insert(topic, on_message);
return this.connection.subscribe(topic, { qos: qos })
.catch((reason) => {
this.emit('error', new browser_1.CrtError(reason));
})
.then((value) => {
const sub = value[0];
return { topic: sub.topic, qos: sub.qos };
});
});
}
unsubscribe(topic) {
return __awaiter(this, void 0, void 0, function* () {
this.subscriptions.remove(topic);
return this.connection.unsubscribe(topic)
.catch((reason) => {
this.emit('error', new browser_1.CrtError(reason));
})
.then((value) => {
return { packet_id: value.messageId };
});
});
}
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
return this.connection.end();
});
}
}
exports.MqttClientConnection = MqttClientConnection;
//# sourceMappingURL=mqtt.js.map