UNPKG

aws-crt

Version:

NodeJS/browser bindings to the aws-c-* libraries

348 lines 15 kB
"use strict"; /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MqttClientConnection = exports.MqttClient = void 0; const binding_1 = __importDefault(require("./binding")); const native_resource_1 = require("./native_resource"); const event_1 = require("../common/event"); const error_1 = require("./error"); const io = __importStar(require("./io")); var http_1 = require("./http"); Object.defineProperty(exports, "HttpProxyOptions", { enumerable: true, get: function () { return http_1.HttpProxyOptions; } }); /** @category MQTT */ var mqtt_1 = require("../common/mqtt"); Object.defineProperty(exports, "QoS", { enumerable: true, get: function () { return mqtt_1.QoS; } }); Object.defineProperty(exports, "MqttWill", { enumerable: true, get: function () { return mqtt_1.MqttWill; } }); /** * MQTT client * * @module aws-crt * @category MQTT */ class MqttClient extends native_resource_1.NativeResource { /** * @param bootstrap The {@link ClientBootstrap} to use for socket connections */ constructor(bootstrap) { super(binding_1.default.mqtt_client_new(bootstrap.native_handle())); this.bootstrap = bootstrap; } /** * Creates a new {@link MqttClientConnection} * @param config Configuration for the connection * @returns A new connection */ new_connection(config) { return new MqttClientConnection(this, config); } } exports.MqttClient = MqttClient; /** @internal */ function normalize_payload(payload) { if (ArrayBuffer.isView(payload)) { // native can use ArrayBufferView bytes directly return payload; } if (payload instanceof ArrayBuffer) { // native can use ArrayBuffer bytes directly return payload; } if (typeof payload === 'string') { // native will convert string to utf-8 return payload; } if (typeof payload === 'object') { // convert object to JSON string (which will be converted to utf-8 in native) return JSON.stringify(payload); } throw new TypeError("payload parameter must be a string, object, or DataView."); } /** * MQTT client connection * * @module aws-crt * @category MQTT */ class MqttClientConnection extends native_resource_1.NativeResourceMixin(event_1.BufferedEventEmitter) { /** * @param client The client that owns this connection * @param config The configuration for this connection */ constructor(client, config) { super(); this.client = client; this.config = config; // If there is a will, ensure that its payload is normalized to a DataView const will = config.will ? { topic: config.will.topic, qos: config.will.qos, payload: normalize_payload(config.will.payload), retain: config.will.retain } : undefined; this._super(binding_1.default.mqtt_client_connection_new(client.native_handle(), (error_code) => { this._on_connection_interrupted(error_code); }, (return_code, session_present) => { this._on_connection_resumed(return_code, session_present); }, config.tls_ctx ? config.tls_ctx.native_handle() : null, will, config.username, config.password, config.use_websocket, config.proxy_options ? config.proxy_options.create_native_handle() : undefined, config.websocket_handshake_transform)); this.tls_ctx = config.tls_ctx; binding_1.default.mqtt_client_connection_on_message(this.native_handle(), this._on_any_publish.bind(this)); } close() { binding_1.default.mqtt_client_connection_close(this.native_handle()); } /** @internal */ // Overridden to allow uncorking on ready on(event, listener) { super.on(event, listener); if (event == 'connect') { process.nextTick(() => { this.uncork(); }); } return this; } /** * Open the actual connection to the server (async). * @returns A Promise which completes whether the connection succeeds or fails. * If connection fails, the Promise will reject with an exception. * If connection succeeds, the Promise will return a boolean that is * true for resuming an existing session, or false if the session is new */ connect() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); const on_connect = (error_code, return_code, session_present) => { if (error_code == 0 && return_code == 0) { resolve(session_present); this.emit('connect', session_present); } else if (error_code != 0) { reject("Failed to connect: " + io.error_code_to_string(error_code)); } else { reject("Server rejected connection."); } }; try { binding_1.default.mqtt_client_connection_connect(this.native_handle(), this.config.client_id, this.config.host_name, this.config.port, this.config.socket_options.native_handle(), this.config.keep_alive, this.config.ping_timeout, this.config.protocol_operation_timeout, this.config.clean_session, on_connect); } catch (e) { reject(e); } }); }); } /** * The connection will automatically reconnect. To cease reconnection attempts, call {@link disconnect}. * To resume the connection, call {@link connect}. * @deprecated */ reconnect() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); function on_connect(error_code, return_code, session_present) { if (error_code == 0 && return_code == 0) { resolve(session_present); } else if (error_code != 0) { reject("Failed to connect: " + io.error_code_to_string(error_code)); } else { reject("Server rejected connection."); } } try { binding_1.default.mqtt_client_connection_reconnect(this.native_handle(), on_connect); } catch (e) { reject(e); } }); }); } /** * Publish message (async). * If the device is offline, the PUBLISH packet will be sent once the connection resumes. * * @param topic Topic name * @param payload Contents of message * @param qos Quality of Service for delivering this message * @param retain If true, the server will store the message and its QoS so that it can be * delivered to future subscribers whose subscriptions match the topic name * @returns Promise which returns a {@link MqttRequest} which will contain the packet id of * the PUBLISH packet. * * * For QoS 0, completes as soon as the packet is sent. * * For QoS 1, completes when PUBACK is received. * * For QoS 2, completes when PUBCOMP is received. */ publish(topic, payload, qos, retain = false) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); function on_publish(packet_id, error_code) { payload = ""; topic = ""; if (error_code == 0) { resolve({ packet_id }); } else { reject("Failed to publish: " + io.error_code_to_string(error_code)); } } let payload_data = normalize_payload(payload); try { binding_1.default.mqtt_client_connection_publish(this.native_handle(), topic, payload_data, qos, retain, on_publish); } catch (e) { reject(e); } }); }); } /** * Subscribe to a topic filter (async). * The client sends a SUBSCRIBE packet and the server responds with a SUBACK. * * subscribe() may be called while the device is offline, though the async * operation cannot complete successfully until the connection resumes. * * Once subscribed, `callback` is invoked each time a message matching * the `topic` is received. It is possible for such messages to arrive before * the SUBACK is received. * * @param topic Subscribe to this topic filter, which may include wildcards * @param qos Maximum requested QoS that server may use when sending messages to the client. * The server may grant a lower QoS in the SUBACK * @param on_message Optional callback invoked when message received. * @returns Promise which returns a {@link MqttSubscribeRequest} which will contain the * result of the SUBSCRIBE. The Promise resolves when a SUBACK is returned * from the server or is rejected when an exception occurs. */ subscribe(topic, qos, on_message) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); function on_suback(packet_id, topic, qos, error_code) { if (error_code == 0) { resolve({ packet_id, topic, qos, error_code }); } else { reject("Failed to subscribe: " + io.error_code_to_string(error_code)); } } try { binding_1.default.mqtt_client_connection_subscribe(this.native_handle(), topic, qos, on_message, on_suback); } catch (e) { reject(e); } }); }); } /** * Unsubscribe from a topic filter (async). * The client sends an UNSUBSCRIBE packet, and the server responds with an UNSUBACK. * @param topic The topic filter to unsubscribe from. May contain wildcards. * @returns Promise wihch returns a {@link MqttRequest} which will contain the packet id * of the UNSUBSCRIBE packet being acknowledged. Promise is resolved when an * UNSUBACK is received from the server or is rejected when an exception occurs. */ unsubscribe(topic) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); function on_unsuback(packet_id, error_code) { if (error_code == 0) { resolve({ packet_id }); } else { reject("Failed to unsubscribe: " + io.error_code_to_string(error_code)); } } try { binding_1.default.mqtt_client_connection_unsubscribe(this.native_handle(), topic, on_unsuback); } catch (e) { reject(e); } }); }); } /** * Close the connection (async). * @returns Promise which completes when the connection is closed. */ disconnect() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { reject = this._reject(reject); const on_disconnect = () => { resolve(); this.emit('disconnect'); this.close(); }; try { binding_1.default.mqtt_client_connection_disconnect(this.native_handle(), on_disconnect); } catch (e) { reject(e); } }); }); } // Wrap a promise rejection with a function that will also emit the error as an event _reject(reject) { return (reason) => { reject(reason); process.nextTick(() => { this.emit('error', new error_1.CrtError(reason)); }); }; } _on_connection_interrupted(error_code) { this.emit('interrupt', new error_1.CrtError(error_code)); } _on_connection_resumed(return_code, session_present) { this.emit('resume', return_code, session_present); } _on_any_publish(topic, payload, dup, qos, retain) { this.emit('message', topic, payload, dup, qos, retain); } } exports.MqttClientConnection = MqttClientConnection; //# sourceMappingURL=mqtt.js.map