├── .gitignore ├── .eslintrc.js ├── index.js ├── package.json ├── .travis.yml ├── LICENSE ├── README.md └── mqttws31.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | strict: 0, 4 | 'no-use-before-define': 0, 5 | }, 6 | extends: 'airbnb', 7 | plugins: [], 8 | }; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Storage from 'react-native-storage'; 2 | 3 | export default (opts) => { 4 | window.localStorage = new Storage(opts); 5 | require('./mqttws31'); 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react_native_mqtt", 3 | "version": "1.1.4", 4 | "description": "Drop in mqtt client for react native.", 5 | "repository": { 6 | "type" : "git", 7 | "url" : "https://github.com/Introvertuous/react_native_mqtt" 8 | }, 9 | "dependencies": { 10 | "react-native-storage": "^0.1.2" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | cache: 5 | yarn: true 6 | directories: 7 | - node_modules 8 | deploy: 9 | provider: npm 10 | email: theramin108@gmail.com 11 | api_key: 12 | secure: Rq2+hzhTi1SV1HPc66s0aNoTMohYnQBInH3++bE9QJOPpEN9VPis7YsQQPDjeRK8Pxb+v43x5r4RY4/cENYxMBnjFlvMncyMSlh7HhNCNufuQCK3INkoCDjKcbj5J1OG8ZVHXoOWhBL1UOYkK9/LAtfFXA9Cm0bkekzhlTe0oV6qMIfX0NO12cE0H58LVSDJzqmxCGVxVoaE++Tt2MvdokCtl/4DOWkTo096+UI1Wx96VwdYW5Xwai2ICiTS3HN7V2Pc409KtjqSI9p0/inBhETFNPgcXo12Qbq8C3rPF0ziFhY5hp44GC4Kx4dl28H5GjLum/BJDI4KaGFpZ2X+MgzuK6vkZN+Qqu3HFMOobViFWupD0uGjKvDNt3lavfeklHI6s/rdJO5rL467zadvfmAn6i24AhrOQUY//CUNGro7EkFAYd90w9wta+CuK5vUWJ8tBHQYrQckCGoj8Xxvs+d95+Z/fmaCgAAhfb0edtwq4Fu7/UZ36GvXlGwyOuLhhSNZCEzhVxGOk5/VSk4K5cMzwCoTOD0jzQAA13U/1airxRgV1TMfYWZDousPMQRwGlB3VwSk6y3pHaZBy6c/eN06aqSauJoEwldahtTK6Dkeov7vv7lsm4OVPPMU66+o7xs/r0+psnRrYKLh8GJQIW4wi+p0STshjFtdy1U4oys= 13 | on: 14 | all_branches: true 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Chris Ryan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Mqtt  2 | 3 | This package is a wrapper around the javascript implementation of the [paho mqtt client library](https://eclipse.org/paho/clients/js/) to provide drop in compatibility with react native. If you happen to be running your own mqtt broker, it must support websockets for a connection to be possible. [Mosquitto](https://mosquitto.org/) does not support websockets out of the box and will require some extra work. Another broker that does have support for websockets is [aedes](https://github.com/mcollina/aedes), which is the broker I use personally. 4 | 5 | ## Install 6 | 7 | To install, use npm: 8 | 9 | ``` 10 | npm install react_native_mqtt --save 11 | ``` 12 | 13 | ## Usage 14 | 15 | To use the library just pass in the options for the local storage module ([react-native-storage](https://github.com/sunnylqm/react-native-storage)) and the paho object will be attached to global scope. 16 | ```javascript 17 | import init from 'react_native_mqtt'; 18 | import { AsyncStorage } from 'react-native'; 19 | 20 | init({ 21 | size: 10000, 22 | storageBackend: AsyncStorage, 23 | defaultExpires: 1000 * 3600 * 24, 24 | enableCache: true, 25 | sync : { 26 | } 27 | }); 28 | 29 | function onConnect() { 30 | console.log("onConnect"); 31 | var message = new Paho.MQTT.Message("Hello"); 32 | message.destinationName = "/World"; 33 | client.send(message); 34 | } 35 | 36 | function onConnectionLost(responseObject) { 37 | if (responseObject.errorCode !== 0) { 38 | console.log("onConnectionLost:"+responseObject.errorMessage); 39 | } 40 | } 41 | 42 | function onMessageArrived(message) { 43 | console.log("onMessageArrived:"+message.payloadString); 44 | } 45 | 46 | var client = new Paho.MQTT.Client('test.mosquitto.org', 8080, 'unique_client_name'); 47 | client.onConnectionLost = onConnectionLost; 48 | client.onMessageArrived = onMessageArrived; 49 | client.connect({onSuccess:onConnect}); 50 | ``` 51 | 52 | This is how you can use the [aedes](https://github.com/mcollina/aedes) broker to handle websocket and standard connections. 53 | ```javascript 54 | var net = require('net'); 55 | var aedes = require('aedes'); 56 | var websocket = require('websocket-stream'); 57 | 58 | exports.listen = function() { 59 | aedes = aedes(); 60 | var server = net.createServer(aedes.handle); 61 | server.listen(1883); 62 | websocket.createServer({port: 8080}, aedes.handle); 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /mqttws31.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 IBM Corp. 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Eclipse Distribution License v1.0 which accompany this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * and the Eclipse Distribution License is available at 11 | * http://www.eclipse.org/org/documents/edl-v10.php. 12 | * 13 | * Contributors: 14 | * Andrew Banks - initial API and implementation and initial documentation 15 | *******************************************************************************/ 16 | 17 | 18 | // Only expose a single object name in the global namespace. 19 | // Everything must go through this module. Global Paho.MQTT module 20 | // only has a single public function, client, which returns 21 | // a Paho.MQTT client object given connection details. 22 | 23 | /** 24 | * Send and receive messages using web browsers. 25 | *
26 | * This programming interface lets a JavaScript client application use the MQTT V3.1 or 27 | * V3.1.1 protocol to connect to an MQTT-supporting messaging server. 28 | * 29 | * The function supported includes: 30 | *
38 | * The API consists of two main objects: 39 | *
51 | * The programming interface validates parameters passed to it, and will throw 52 | * an Error containing an error message intended for developer use, if it detects 53 | * an error with any parameter. 54 | *
55 | * Example:
56 | *
57 | *
1517 | * The send, subscribe and unsubscribe methods are implemented as asynchronous JavaScript methods
1518 | * (even though the underlying protocol exchange might be synchronous in nature).
1519 | * This means they signal their completion by calling back to the application,
1520 | * via Success or Failure callback functions provided by the application on the method in question.
1521 | * Such callbacks are called at most once per method invocation and do not persist beyond the lifetime
1522 | * of the script that made the invocation.
1523 | *
1524 | * In contrast there are some callback functions, most notably onMessageArrived,
1525 | * that are defined on the {@link Paho.MQTT.Client} object.
1526 | * These may get called multiple times, and aren't directly related to specific method invocations made by the client.
1527 | *
1528 | * @name Paho.MQTT.Client
1529 | *
1530 | * @constructor
1531 | *
1532 | * @param {string} host - the address of the messaging server, as a fully qualified WebSocket URI, as a DNS name or dotted decimal IP address.
1533 | * @param {number} port - the port number to connect to - only required if host is not a URI
1534 | * @param {string} path - the path on the host to connect to - only used if host is not a URI. Default: '/mqtt'.
1535 | * @param {string} clientId - the Messaging client identifier, between 1 and 23 characters in length.
1536 | *
1537 | * @property {string} host - read only the server's DNS hostname or dotted decimal IP address.
1538 | * @property {number} port - read only the server's port.
1539 | * @property {string} path - read only the server's path.
1540 | * @property {string} clientId - read only used when connecting to the server.
1541 | * @property {function} onConnectionLost - called when a connection has been lost.
1542 | * after a connect() method has succeeded.
1543 | * Establish the call back used when a connection has been lost. The connection may be
1544 | * lost because the client initiates a disconnect or because the server or network
1545 | * cause the client to be disconnected. The disconnect call back may be called without
1546 | * the connectionComplete call back being invoked if, for example the client fails to
1547 | * connect.
1548 | * A single response object parameter is passed to the onConnectionLost callback containing the following fields:
1549 | *
2021 | * All attributes may be null, which implies the default values.
2022 | *
2023 | * @name Paho.MQTT.Message
2024 | * @constructor
2025 | * @param {String|ArrayBuffer} payload The message data to be sent.
2026 | *
2027 | * @property {string} payloadString read only The payload as a string if the payload consists of valid UTF-8 characters.
2028 | * @property {ArrayBuffer} payloadBytes read only The payload as an ArrayBuffer.
2029 | *
2030 | * @property {string} destinationName mandatory The name of the destination to which the message is to be sent
2031 | * (for messages about to be sent) or the name of the destination from which the message has been received.
2032 | * (for messages received by the onMessage function).
2033 | *
2034 | * @property {number} qos The Quality of Service used to deliver the message.
2035 | *
2041 | * @property {Boolean} retained If true, the message is to be retained by the server and delivered
2042 | * to both current and future subscriptions.
2043 | * If false the server only delivers the message to current subscribers, this is the default for new Messages.
2044 | * A received message has the retained boolean set to true if the message was published
2045 | * with the retained boolean set to true
2046 | * and the subscrption was made after the message has been published.
2047 | *
2048 | * @property {Boolean} duplicate read only If true, this message might be a duplicate of one which has already been received.
2049 | * This is only set on messages received from the server.
2050 | *
2051 | */
2052 | var Message = function (newPayload) {
2053 | var payload;
2054 | if ( typeof newPayload === "string"
2055 | || newPayload instanceof ArrayBuffer
2056 | || newPayload instanceof Int8Array
2057 | || newPayload instanceof Uint8Array
2058 | || newPayload instanceof Int16Array
2059 | || newPayload instanceof Uint16Array
2060 | || newPayload instanceof Int32Array
2061 | || newPayload instanceof Uint32Array
2062 | || newPayload instanceof Float32Array
2063 | || newPayload instanceof Float64Array
2064 | ) {
2065 | payload = newPayload;
2066 | } else {
2067 | throw (format(ERROR.INVALID_ARGUMENT, [newPayload, "newPayload"]));
2068 | }
2069 |
2070 | this._getPayloadString = function () {
2071 | if (typeof payload === "string")
2072 | return payload;
2073 | else
2074 | return parseUTF8(payload, 0, payload.length);
2075 | };
2076 |
2077 | this._getPayloadBytes = function() {
2078 | if (typeof payload === "string") {
2079 | var buffer = new ArrayBuffer(UTF8Length(payload));
2080 | var byteStream = new Uint8Array(buffer);
2081 | stringToUTF8(payload, byteStream, 0);
2082 |
2083 | return byteStream;
2084 | } else {
2085 | return payload;
2086 | };
2087 | };
2088 |
2089 | var destinationName = undefined;
2090 | this._getDestinationName = function() { return destinationName; };
2091 | this._setDestinationName = function(newDestinationName) {
2092 | if (typeof newDestinationName === "string")
2093 | destinationName = newDestinationName;
2094 | else
2095 | throw new Error(format(ERROR.INVALID_ARGUMENT, [newDestinationName, "newDestinationName"]));
2096 | };
2097 |
2098 | var qos = 0;
2099 | this._getQos = function() { return qos; };
2100 | this._setQos = function(newQos) {
2101 | if (newQos === 0 || newQos === 1 || newQos === 2 )
2102 | qos = newQos;
2103 | else
2104 | throw new Error("Invalid argument:"+newQos);
2105 | };
2106 |
2107 | var retained = false;
2108 | this._getRetained = function() { return retained; };
2109 | this._setRetained = function(newRetained) {
2110 | if (typeof newRetained === "boolean")
2111 | retained = newRetained;
2112 | else
2113 | throw new Error(format(ERROR.INVALID_ARGUMENT, [newRetained, "newRetained"]));
2114 | };
2115 |
2116 | var duplicate = false;
2117 | this._getDuplicate = function() { return duplicate; };
2118 | this._setDuplicate = function(newDuplicate) { duplicate = newDuplicate; };
2119 | };
2120 |
2121 | Message.prototype = {
2122 | get payloadString() { return this._getPayloadString(); },
2123 | get payloadBytes() { return this._getPayloadBytes(); },
2124 |
2125 | get destinationName() { return this._getDestinationName(); },
2126 | set destinationName(newDestinationName) { this._setDestinationName(newDestinationName); },
2127 |
2128 | get qos() { return this._getQos(); },
2129 | set qos(newQos) { this._setQos(newQos); },
2130 |
2131 | get retained() { return this._getRetained(); },
2132 | set retained(newRetained) { this._setRetained(newRetained); },
2133 |
2134 | get duplicate() { return this._getDuplicate(); },
2135 | set duplicate(newDuplicate) { this._setDuplicate(newDuplicate); }
2136 | };
2137 |
2138 | // Module contents.
2139 | return {
2140 | Client: Client,
2141 | Message: Message
2142 | };
2143 | })(window);
2144 |
--------------------------------------------------------------------------------
80 | * @namespace Paho.MQTT
81 | */
82 |
83 | if (typeof Paho === "undefined") {
84 | Paho = {};
85 | }
86 |
87 | Paho.MQTT = (function (global) {
88 |
89 | // Private variables below, these are only visible inside the function closure
90 | // which is used to define the module.
91 |
92 | var version = "@VERSION@";
93 | var buildLevel = "@BUILDLEVEL@";
94 |
95 | /**
96 | * Unique message type identifiers, with associated
97 | * associated integer values.
98 | * @private
99 | */
100 | var MESSAGE_TYPE = {
101 | CONNECT: 1,
102 | CONNACK: 2,
103 | PUBLISH: 3,
104 | PUBACK: 4,
105 | PUBREC: 5,
106 | PUBREL: 6,
107 | PUBCOMP: 7,
108 | SUBSCRIBE: 8,
109 | SUBACK: 9,
110 | UNSUBSCRIBE: 10,
111 | UNSUBACK: 11,
112 | PINGREQ: 12,
113 | PINGRESP: 13,
114 | DISCONNECT: 14
115 | };
116 |
117 | // Collection of utility methods used to simplify module code
118 | // and promote the DRY pattern.
119 |
120 | /**
121 | * Validate an object's parameter names to ensure they
122 | * match a list of expected variables name for this option
123 | * type. Used to ensure option object passed into the API don't
124 | * contain erroneous parameters.
125 | * @param {Object} obj - User options object
126 | * @param {Object} keys - valid keys and types that may exist in obj.
127 | * @throws {Error} Invalid option parameter found.
128 | * @private
129 | */
130 | var validate = function(obj, keys) {
131 | for (var key in obj) {
132 | if (obj.hasOwnProperty(key)) {
133 | if (keys.hasOwnProperty(key)) {
134 | if (typeof obj[key] !== keys[key])
135 | throw new Error(format(ERROR.INVALID_TYPE, [typeof obj[key], key]));
136 | } else {
137 | var errorStr = "Unknown property, " + key + ". Valid properties are:";
138 | for (var key in keys)
139 | if (keys.hasOwnProperty(key))
140 | errorStr = errorStr+" "+key;
141 | throw new Error(errorStr);
142 | }
143 | }
144 | }
145 | };
146 |
147 | /**
148 | * Return a new function which runs the user function bound
149 | * to a fixed scope.
150 | * @param {function} User function
151 | * @param {object} Function scope
152 | * @return {function} User function bound to another scope
153 | * @private
154 | */
155 | var scope = function (f, scope) {
156 | return function () {
157 | return f.apply(scope, arguments);
158 | };
159 | };
160 |
161 | /**
162 | * Unique message type identifiers, with associated
163 | * associated integer values.
164 | * @private
165 | */
166 | var ERROR = {
167 | OK: {code:0, text:"AMQJSC0000I OK."},
168 | CONNECT_TIMEOUT: {code:1, text:"AMQJSC0001E Connect timed out."},
169 | SUBSCRIBE_TIMEOUT: {code:2, text:"AMQJS0002E Subscribe timed out."},
170 | UNSUBSCRIBE_TIMEOUT: {code:3, text:"AMQJS0003E Unsubscribe timed out."},
171 | PING_TIMEOUT: {code:4, text:"AMQJS0004E Ping timed out."},
172 | INTERNAL_ERROR: {code:5, text:"AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}"},
173 | CONNACK_RETURNCODE: {code:6, text:"AMQJS0006E Bad Connack return code:{0} {1}."},
174 | SOCKET_ERROR: {code:7, text:"AMQJS0007E Socket error:{0}."},
175 | SOCKET_CLOSE: {code:8, text:"AMQJS0008I Socket closed."},
176 | MALFORMED_UTF: {code:9, text:"AMQJS0009E Malformed UTF data:{0} {1} {2}."},
177 | UNSUPPORTED: {code:10, text:"AMQJS0010E {0} is not supported by this browser."},
178 | INVALID_STATE: {code:11, text:"AMQJS0011E Invalid state {0}."},
179 | INVALID_TYPE: {code:12, text:"AMQJS0012E Invalid type {0} for {1}."},
180 | INVALID_ARGUMENT: {code:13, text:"AMQJS0013E Invalid argument {0} for {1}."},
181 | UNSUPPORTED_OPERATION: {code:14, text:"AMQJS0014E Unsupported operation."},
182 | INVALID_STORED_DATA: {code:15, text:"AMQJS0015E Invalid data in local storage key={0} value={1}."},
183 | INVALID_MQTT_MESSAGE_TYPE: {code:16, text:"AMQJS0016E Invalid MQTT message type {0}."},
184 | MALFORMED_UNICODE: {code:17, text:"AMQJS0017E Malformed Unicode string:{0} {1}."}
185 | };
186 |
187 | /** CONNACK RC Meaning. */
188 | var CONNACK_RC = {
189 | 0:"Connection Accepted",
190 | 1:"Connection Refused: unacceptable protocol version",
191 | 2:"Connection Refused: identifier rejected",
192 | 3:"Connection Refused: server unavailable",
193 | 4:"Connection Refused: bad user name or password",
194 | 5:"Connection Refused: not authorized"
195 | };
196 |
197 | /**
198 | * Format an error message text.
199 | * @private
200 | * @param {error} ERROR.KEY value above.
201 | * @param {substitutions} [array] substituted into the text.
202 | * @return the text with the substitutions made.
203 | */
204 | var format = function(error, substitutions) {
205 | var text = error.text;
206 | if (substitutions) {
207 | var field,start;
208 | for (var i=0; i
58 | client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId");
59 | client.onConnectionLost = onConnectionLost;
60 | client.onMessageArrived = onMessageArrived;
61 | client.connect({onSuccess:onConnect});
62 |
63 | function onConnect() {
64 | // Once a connection has been made, make a subscription and send a message.
65 | console.log("onConnect");
66 | client.subscribe("/World");
67 | message = new Paho.MQTT.Message("Hello");
68 | message.destinationName = "/World";
69 | client.send(message);
70 | };
71 | function onConnectionLost(responseObject) {
72 | if (responseObject.errorCode !== 0)
73 | console.log("onConnectionLost:"+responseObject.errorMessage);
74 | };
75 | function onMessageArrived(message) {
76 | console.log("onMessageArrived:"+message.payloadString);
77 | client.disconnect();
78 | };
79 | *
1550 | *
1553 | * @property {function} onMessageDelivered called when a message has been delivered.
1554 | * All processing that this Client will ever do has been completed. So, for example,
1555 | * in the case of a Qos=2 message sent by this client, the PubComp flow has been received from the server
1556 | * and the message has been removed from persistent storage before this callback is invoked.
1557 | * Parameters passed to the onMessageDelivered callback are:
1558 | *
1559 | *
1561 | * @property {function} onMessageArrived called when a message has arrived in this Paho.MQTT.client.
1562 | * Parameters passed to the onMessageArrived callback are:
1563 | *
1564 | *
1566 | */
1567 | var Client = function (host, port, path, clientId) {
1568 |
1569 | var uri;
1570 |
1571 | if (typeof host !== "string")
1572 | throw new Error(format(ERROR.INVALID_TYPE, [typeof host, "host"]));
1573 |
1574 | if (arguments.length == 2) {
1575 | // host: must be full ws:// uri
1576 | // port: clientId
1577 | clientId = port;
1578 | uri = host;
1579 | var match = uri.match(/^(wss?):\/\/((\[(.+)\])|([^\/]+?))(:(\d+))?(\/.*)$/);
1580 | if (match) {
1581 | host = match[4]||match[2];
1582 | port = parseInt(match[7]);
1583 | path = match[8];
1584 | } else {
1585 | throw new Error(format(ERROR.INVALID_ARGUMENT,[host,"host"]));
1586 | }
1587 | } else {
1588 | if (arguments.length == 3) {
1589 | clientId = path;
1590 | path = "/mqtt";
1591 | }
1592 | if (typeof port !== "number" || port < 0)
1593 | throw new Error(format(ERROR.INVALID_TYPE, [typeof port, "port"]));
1594 | if (typeof path !== "string")
1595 | throw new Error(format(ERROR.INVALID_TYPE, [typeof path, "path"]));
1596 |
1597 | var ipv6AddSBracket = (host.indexOf(":") != -1 && host.slice(0,1) != "[" && host.slice(-1) != "]");
1598 | uri = "ws://"+(ipv6AddSBracket?"["+host+"]":host)+":"+port+path;
1599 | }
1600 |
1601 | var clientIdLength = 0;
1602 | for (var i = 0; i
1685 | *
1687 | * @config {function} [onFailure] called when the connect request has failed or timed out.
1688 | * A single response object parameter is passed to the onFailure callback containing the following fields:
1689 | *
1690 | *
1694 | * @config {Array} [hosts] If present this contains either a set of hostnames or fully qualified
1695 | * WebSocket URIs (ws://example.com:1883/mqtt), that are tried in order in place
1696 | * of the host and port paramater on the construtor. The hosts are tried one at at time in order until
1697 | * one of then succeeds.
1698 | * @config {Array} [ports] If present the set of ports matching the hosts. If hosts contains URIs, this property
1699 | * is not used.
1700 | * @throws {InvalidState} if the client is not in disconnected state. The client must have received connectionLost
1701 | * or disconnected before calling connect for a second or subsequent time.
1702 | */
1703 | this.connect = function (connectOptions) {
1704 | connectOptions = connectOptions || {} ;
1705 | validate(connectOptions, {timeout:"number",
1706 | userName:"string",
1707 | password:"string",
1708 | willMessage:"object",
1709 | keepAliveInterval:"number",
1710 | cleanSession:"boolean",
1711 | useSSL:"boolean",
1712 | invocationContext:"object",
1713 | onSuccess:"function",
1714 | onFailure:"function",
1715 | hosts:"object",
1716 | ports:"object",
1717 | mqttVersion:"number",
1718 | mqttVersionExplicit:"boolean",
1719 | uris: "object"});
1720 |
1721 | // If no keep alive interval is set, assume 60 seconds.
1722 | if (connectOptions.keepAliveInterval === undefined)
1723 | connectOptions.keepAliveInterval = 60;
1724 |
1725 | if (connectOptions.mqttVersion > 4 || connectOptions.mqttVersion < 3) {
1726 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.mqttVersion, "connectOptions.mqttVersion"]));
1727 | }
1728 |
1729 | if (connectOptions.mqttVersion === undefined) {
1730 | connectOptions.mqttVersionExplicit = false;
1731 | connectOptions.mqttVersion = 4;
1732 | } else {
1733 | connectOptions.mqttVersionExplicit = true;
1734 | }
1735 |
1736 | //Check that if password is set, so is username
1737 | if (connectOptions.password !== undefined && connectOptions.userName === undefined)
1738 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.password, "connectOptions.password"]))
1739 |
1740 | if (connectOptions.willMessage) {
1741 | if (!(connectOptions.willMessage instanceof Message))
1742 | throw new Error(format(ERROR.INVALID_TYPE, [connectOptions.willMessage, "connectOptions.willMessage"]));
1743 | // The will message must have a payload that can be represented as a string.
1744 | // Cause the willMessage to throw an exception if this is not the case.
1745 | connectOptions.willMessage.stringPayload;
1746 |
1747 | if (typeof connectOptions.willMessage.destinationName === "undefined")
1748 | throw new Error(format(ERROR.INVALID_TYPE, [typeof connectOptions.willMessage.destinationName, "connectOptions.willMessage.destinationName"]));
1749 | }
1750 | if (typeof connectOptions.cleanSession === "undefined")
1751 | connectOptions.cleanSession = true;
1752 | if (connectOptions.hosts) {
1753 |
1754 | if (!(connectOptions.hosts instanceof Array) )
1755 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"]));
1756 | if (connectOptions.hosts.length <1 )
1757 | throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"]));
1758 |
1759 | var usingURIs = false;
1760 | for (var i = 0; i
1819 | *
1821 | * @param {function} subscribeOptions.onFailure - called when the subscribe request has failed or timed out.
1822 | * A single response object parameter is passed to the onFailure callback containing the following fields:
1823 | *
1824 | *
1828 | * @param {number} subscribeOptions.timeout - which, if present, determines the number of
1829 | * seconds after which the onFailure calback is called.
1830 | * The presence of a timeout does not prevent the onSuccess
1831 | * callback from being called when the subscribe completes.
1832 | * @throws {InvalidState} if the client is not in connected state.
1833 | */
1834 | this.subscribe = function (filter, subscribeOptions) {
1835 | if (typeof filter !== "string")
1836 | throw new Error("Invalid argument:"+filter);
1837 | subscribeOptions = subscribeOptions || {} ;
1838 | validate(subscribeOptions, {qos:"number",
1839 | invocationContext:"object",
1840 | onSuccess:"function",
1841 | onFailure:"function",
1842 | timeout:"number"
1843 | });
1844 | if (subscribeOptions.timeout && !subscribeOptions.onFailure)
1845 | throw new Error("subscribeOptions.timeout specified with no onFailure callback.");
1846 | if (typeof subscribeOptions.qos !== "undefined"
1847 | && !(subscribeOptions.qos === 0 || subscribeOptions.qos === 1 || subscribeOptions.qos === 2 ))
1848 | throw new Error(format(ERROR.INVALID_ARGUMENT, [subscribeOptions.qos, "subscribeOptions.qos"]));
1849 | client.subscribe(filter, subscribeOptions);
1850 | };
1851 |
1852 | /**
1853 | * Unsubscribe for messages, stop receiving messages sent to destinations described by the filter.
1854 | *
1855 | * @name Paho.MQTT.Client#unsubscribe
1856 | * @function
1857 | * @param {string} filter - describing the destinations to receive messages from.
1858 | * @param {object} unsubscribeOptions - used to control the subscription
1859 | * @param {object} unsubscribeOptions.invocationContext - passed to the onSuccess callback
1860 | or onFailure callback.
1861 | * @param {function} unsubscribeOptions.onSuccess - called when the unsubscribe acknowledgement has been received from the server.
1862 | * A single response object parameter is passed to the
1863 | * onSuccess callback containing the following fields:
1864 | *
1865 | *
1867 | * @param {function} unsubscribeOptions.onFailure called when the unsubscribe request has failed or timed out.
1868 | * A single response object parameter is passed to the onFailure callback containing the following fields:
1869 | *
1870 | *
1874 | * @param {number} unsubscribeOptions.timeout - which, if present, determines the number of seconds
1875 | * after which the onFailure callback is called. The presence of
1876 | * a timeout does not prevent the onSuccess callback from being
1877 | * called when the unsubscribe completes
1878 | * @throws {InvalidState} if the client is not in connected state.
1879 | */
1880 | this.unsubscribe = function (filter, unsubscribeOptions) {
1881 | if (typeof filter !== "string")
1882 | throw new Error("Invalid argument:"+filter);
1883 | unsubscribeOptions = unsubscribeOptions || {} ;
1884 | validate(unsubscribeOptions, {invocationContext:"object",
1885 | onSuccess:"function",
1886 | onFailure:"function",
1887 | timeout:"number"
1888 | });
1889 | if (unsubscribeOptions.timeout && !unsubscribeOptions.onFailure)
1890 | throw new Error("unsubscribeOptions.timeout specified with no onFailure callback.");
1891 | client.unsubscribe(filter, unsubscribeOptions);
1892 | };
1893 |
1894 | /**
1895 | * Send a message to the consumers of the destination in the Message.
1896 | *
1897 | * @name Paho.MQTT.Client#send
1898 | * @function
1899 | * @param {string|Paho.MQTT.Message} topic - mandatory The name of the destination to which the message is to be sent.
1900 | * - If it is the only parameter, used as Paho.MQTT.Message object.
1901 | * @param {String|ArrayBuffer} payload - The message data to be sent.
1902 | * @param {number} qos The Quality of Service used to deliver the message.
1903 | *
1904 | *
1908 | * @param {Boolean} retained If true, the message is to be retained by the server and delivered
1909 | * to both current and future subscriptions.
1910 | * If false the server only delivers the message to current subscribers, this is the default for new Messages.
1911 | * A received message has the retained boolean set to true if the message was published
1912 | * with the retained boolean set to true
1913 | * and the subscrption was made after the message has been published.
1914 | * @throws {InvalidState} if the client is not connected.
1915 | */
1916 | this.send = function (topic,payload,qos,retained) {
1917 | var message ;
1918 |
1919 | if(arguments.length == 0){
1920 | throw new Error("Invalid argument."+"length");
1921 |
1922 | }else if(arguments.length == 1) {
1923 |
1924 | if (!(topic instanceof Message) && (typeof topic !== "string"))
1925 | throw new Error("Invalid argument:"+ typeof topic);
1926 |
1927 | message = topic;
1928 | if (typeof message.destinationName === "undefined")
1929 | throw new Error(format(ERROR.INVALID_ARGUMENT,[message.destinationName,"Message.destinationName"]));
1930 | client.send(message);
1931 |
1932 | }else {
1933 | //parameter checking in Message object
1934 | message = new Message(payload);
1935 | message.destinationName = topic;
1936 | if(arguments.length >= 3)
1937 | message.qos = qos;
1938 | if(arguments.length >= 4)
1939 | message.retained = retained;
1940 | client.send(message);
1941 | }
1942 | };
1943 |
1944 | /**
1945 | * Normal disconnect of this Messaging client from its server.
1946 | *
1947 | * @name Paho.MQTT.Client#disconnect
1948 | * @function
1949 | * @throws {InvalidState} if the client is already disconnected.
1950 | */
1951 | this.disconnect = function () {
1952 | client.disconnect();
1953 | };
1954 |
1955 | /**
1956 | * Get the contents of the trace log.
1957 | *
1958 | * @name Paho.MQTT.Client#getTraceLog
1959 | * @function
1960 | * @return {Object[]} tracebuffer containing the time ordered trace records.
1961 | */
1962 | this.getTraceLog = function () {
1963 | return client.getTraceLog();
1964 | }
1965 |
1966 | /**
1967 | * Start tracing.
1968 | *
1969 | * @name Paho.MQTT.Client#startTrace
1970 | * @function
1971 | */
1972 | this.startTrace = function () {
1973 | client.startTrace();
1974 | };
1975 |
1976 | /**
1977 | * Stop tracing.
1978 | *
1979 | * @name Paho.MQTT.Client#stopTrace
1980 | * @function
1981 | */
1982 | this.stopTrace = function () {
1983 | client.stopTrace();
1984 | };
1985 |
1986 | this.isConnected = function() {
1987 | return client.connected;
1988 | };
1989 | };
1990 |
1991 | Client.prototype = {
1992 | get host() { return this._getHost(); },
1993 | set host(newHost) { this._setHost(newHost); },
1994 |
1995 | get port() { return this._getPort(); },
1996 | set port(newPort) { this._setPort(newPort); },
1997 |
1998 | get path() { return this._getPath(); },
1999 | set path(newPath) { this._setPath(newPath); },
2000 |
2001 | get clientId() { return this._getClientId(); },
2002 | set clientId(newClientId) { this._setClientId(newClientId); },
2003 |
2004 | get onConnectionLost() { return this._getOnConnectionLost(); },
2005 | set onConnectionLost(newOnConnectionLost) { this._setOnConnectionLost(newOnConnectionLost); },
2006 |
2007 | get onMessageDelivered() { return this._getOnMessageDelivered(); },
2008 | set onMessageDelivered(newOnMessageDelivered) { this._setOnMessageDelivered(newOnMessageDelivered); },
2009 |
2010 | get onMessageArrived() { return this._getOnMessageArrived(); },
2011 | set onMessageArrived(newOnMessageArrived) { this._setOnMessageArrived(newOnMessageArrived); },
2012 |
2013 | get trace() { return this._getTrace(); },
2014 | set trace(newTraceFunction) { this._setTrace(newTraceFunction); }
2015 |
2016 | };
2017 |
2018 | /**
2019 | * An application message, sent or received.
2020 | *
2036 | *
2040 | *