2 Copyright (c) 2012 Roger Light <roger@atchoo.org>
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. Neither the name of mosquitto nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
30 /* Mosquitto MQTT Javascript/Websocket client */
31 /* Provides complete support for QoS 0.
32 * Will not cause an error on QoS 1/2 packets.
44 var UNSUBSCRIBE = 0xA0;
48 var DISCONNECT = 0xE0;
50 function AB2S(buffer) {
52 var bytes = new Uint8Array(buffer);
53 var len = bytes.byteLength;
54 for(var i=0; i<len; i++){
55 binary += String.fromCharCode(bytes[i]);
63 this.onconnect = null;
64 this.ondisconnect = null;
65 this.onmessage = null;
68 Mosquitto.prototype = {
69 mqtt_ping : function()
71 var buffer = new ArrayBuffer(2);
72 var i8V = new Int8Array(buffer);
75 if(this.ws.readyState == 1){
80 setTimeout(function(_this){_this.mqtt_ping();}, 60000, this);
83 connect : function(url, keepalive){
86 this.keepalive = keepalive;
88 this.out_queue = new Array();
90 this.ws = new WebSocket(url, 'mqttv3.1');
91 this.ws.binaryType = "arraybuffer";
92 this.ws.onopen = this.ws_onopen;
93 this.ws.onclose = this.ws_onclose;
94 this.ws.onmessage = this.ws_onmessage;
96 this.ws.onerror = function(evt){
101 disconnect : function(){
102 if(this.ws.readyState == 1){
103 var buffer = new ArrayBuffer(2);
104 var i8V = new Int8Array(buffer);
108 this.ws.send(buffer);
113 ws_onopen : function(evt) {
114 var buffer = new ArrayBuffer(1+1+12+2+20);
115 var i8V = new Int8Array(buffer);
123 for(var j=0; j<str.length; j++){
124 i8V[i++] = str.charCodeAt(j);
133 for(var j=0; j<str.length; j++){
134 i8V[i++] = str.charCodeAt(j);
136 var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
137 for(var j=0; j<14; j++){
138 i8V[i++] = chars.charCodeAt(Math.floor(Math.random()*chars.length));
142 while(this.m.out_queue.length > 0){
143 this.send(this.m.out_queue.pop());
145 setTimeout(function(_this){_this.mqtt_ping();}, 60000, this.m);
148 ws_onclose : function(evt) {
149 if(this.m.ondisconnect){
150 this.m.ondisconnect(evt.data);
154 ws_onmessage : function(evt) {
155 var i8V = new Int8Array(evt.data);
158 while(i8V.length > 0 && q < 1000){
160 switch(i8V[0] & 0xF0){
164 if(this.m.onconnect){
165 this.m.onconnect(rc);
167 buffer = buffer.slice(rl+2);
168 i8V = new Int8Array(buffer);
176 var qos = (i8V[0] & 0x06) >> 1;
177 var retain = (i8V[0] & 0x01);
182 rl += (digit & 127)*mult;
184 }while((digit & 128) != 0);
186 var topiclen = i8V[i++]*256 + i8V[i++];
187 var atopic = buffer.slice(i, i+topiclen);
189 var topic = AB2S(atopic);
191 mid = i8V[i++]*256 + i8V[i++];
193 var apayload = buffer.slice(i, rl+count+1);
194 var payload = AB2S(apayload);
196 buffer = buffer.slice(rl+1+count);
197 i8V = new Int8Array(buffer);
199 if(this.m.onmessage){
200 this.m.onmessage(topic, payload, qos, retain);
211 buffer = buffer.slice(rl+2);
212 i8V = new Int8Array(buffer);
218 get_remaining_count : function(remaining_length)
220 if(remaining_length >= 0 && remaining_length < 128){
222 }else if(remaining_length >= 128 && remaining_length < 16384){
224 }else if(remaining_length >= 16384 && remaining_length < 2097152){
226 }else if(remaining_length >= 2097152 && remaining_length < 268435456){
233 generate_mid : function()
237 if(this.mid == 256) this.mid = 0;
241 queue : function(buffer)
243 this.out_queue.push(buffer);
246 send_cmd_with_mid : function(cmd, mid)
248 var buffer = new ArrayBuffer(4);
249 var i8V = new Int8Array(buffer);
254 if(this.ws.readyState == 1){
255 this.ws.send(buffer);
261 unsubscribe : function(topic)
263 var rl = 2+2+topic.length;
264 var remaining_count = this.get_remaining_count(rl);
265 var buffer = new ArrayBuffer(1+remaining_count+rl);
266 var i8V = new Int8Array(buffer);
269 i8V[i++] = UNSUBSCRIBE | 0x02;
271 digit = Math.floor(rl % 128);
272 rl = Math.floor(rl / 128);
274 digit = digit | 0x80;
279 i8V[i++] = this.generate_mid();
281 i8V[i++] = topic.length;
282 for(var j=0; j<topic.length; j++){
283 i8V[i++] = topic.charCodeAt(j);
286 if(this.ws.readyState == 1){
287 this.ws.send(buffer);
293 subscribe : function(topic, qos)
298 var rl = 2+2+topic.length+1;
299 var remaining_count = this.get_remaining_count(rl);
300 var buffer = new ArrayBuffer(1+remaining_count+rl);
301 var i8V = new Int8Array(buffer);
304 i8V[i++] = SUBSCRIBE | 0x02;
306 digit = Math.floor(rl % 128);
307 rl = Math.floor(rl / 128);
309 digit = digit | 0x80;
314 i8V[i++] = this.generate_mid();
316 i8V[i++] = topic.length;
317 for(var j=0; j<topic.length; j++){
318 i8V[i++] = topic.charCodeAt(j);
322 if(this.ws.readyState == 1){
323 this.ws.send(buffer);
329 publish : function(topic, payload, qos, retain){
330 if(qos != 0) return 1;
331 var rl = 2+topic.length+payload.length;
332 var remaining_count = this.get_remaining_count(rl);
333 var buffer = new ArrayBuffer(1+remaining_count+rl);
334 var i8V = new Int8Array(buffer);
338 i8V[i++] = PUBLISH | (qos<<1) | retain;
340 digit = Math.floor(rl % 128);
341 rl = Math.floor(rl / 128);
343 digit = digit | 0x80;
348 i8V[i++] = topic.length;
349 for(var j=0; j<topic.length; j++){
350 i8V[i++] = topic.charCodeAt(j);
352 for(var j=0; j<payload.length; j++){
353 i8V[i++] = payload.charCodeAt(j);
356 if(this.ws.readyState == 1){
357 this.ws.send(buffer);