1 | 'use strict';
|
2 | var util = require('util');
|
3 | var EventEmitter = require('events').EventEmitter;
|
4 | var socketIoClient = require("socket.io-client");
|
5 |
|
6 | var DEFAULT_TIMEOUT = 10000;
|
7 |
|
8 | function Connection(opt){
|
9 |
|
10 | EventEmitter.call(this);
|
11 |
|
12 | this._callbackHandlers = {};
|
13 | this._ackId = 0;
|
14 |
|
15 | this.options = opt || {};
|
16 | this.options.options = this.options.options || {};
|
17 |
|
18 | this.options.options.transports = this.options.options.transports || ['websocket'];
|
19 | this.options.forceNew = (opt.forceNew != null) ? opt.forceNew : false;
|
20 |
|
21 | this.options.server = this.options.server || 'ws://meshblu.octoblu.com';
|
22 | this.options.port = this.options.port || 80;
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | if(this.options.server.indexOf("http") === -1 && this.options.server.indexOf("ws") === -1 && this.options.server.indexOf("wss") === -1 ){
|
28 | this.options.server = "ws://" + this.options.server;
|
29 | }
|
30 |
|
31 |
|
32 | var network = this.options.server + ':' + this.options.port;
|
33 | console.log('trying', network);
|
34 | this.socket = socketIoClient(network, this.options.options);
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | this.options.protocol = "websocket";
|
44 | this.setup();
|
45 | }
|
46 |
|
47 | util.inherits(Connection, EventEmitter);
|
48 |
|
49 | Connection.prototype.setup = function(){
|
50 | var self = this;
|
51 | this.socket.once('connect', function(){
|
52 | this.emit('connect');
|
53 |
|
54 | this.socket.on('messageAck', function(data){
|
55 | if(self._callbackHandlers[data.ack]){
|
56 | try{
|
57 | self._callbackHandlers[data.ack](data.payload);
|
58 | delete self._callbackHandlers[data.ack];
|
59 | }
|
60 | catch(err){
|
61 | console.log('error resolving callback', err);
|
62 | }
|
63 | }
|
64 | });
|
65 |
|
66 | this.socket.on('message', function(data){
|
67 | self._handleAckRequest('message', data);
|
68 | });
|
69 |
|
70 |
|
71 | this.socket.on('config', function(data){
|
72 | self._handleAckRequest('config', data);
|
73 | });
|
74 |
|
75 | this.socket.on('disconnect', this.emit.bind(this, 'disconnect'));
|
76 | this.socket.on('identify', this.identify.bind(this));
|
77 | this.socket.on('ready', this.emit.bind(this, 'ready'));
|
78 | this.socket.on('notReady', this.emit.bind(this, 'notReady'));
|
79 | this.socket.on('tb', this.emit.bind(this, 'tb'));
|
80 | this.socket.on('unboundSocket', this.emit.bind(this, 'unboundSocket'));
|
81 |
|
82 | }.bind(this));
|
83 |
|
84 | return this;
|
85 | };
|
86 |
|
87 |
|
88 | Connection.prototype._handleAckRequest = function(topic, data){
|
89 | var self = this;
|
90 | if(data){
|
91 | if(data.ack && data.fromUuid){
|
92 |
|
93 | self.emit(topic, data, function(response){
|
94 | self._messageAck({
|
95 | devices: data.fromUuid,
|
96 | ack: data.ack,
|
97 | payload: response
|
98 | });
|
99 | });
|
100 | }else{
|
101 | self.emit(topic, data);
|
102 | }
|
103 | }
|
104 | };
|
105 |
|
106 |
|
107 | Connection.prototype._emitWithAck = function(topic, data, fn){
|
108 | var self = this;
|
109 | if(data){
|
110 | if(fn){
|
111 | var ack = ++this._ackId;
|
112 | data.ack = ack;
|
113 | self._callbackHandlers[ack] = fn;
|
114 | var timeout = data.timeout || DEFAULT_TIMEOUT;
|
115 |
|
116 | setTimeout(function(){
|
117 | if(self._callbackHandlers[ack]){
|
118 | self._callbackHandlers[ack]({error: 'timeout ' + timeout});
|
119 | delete self._callbackHandlers[ack];
|
120 | }
|
121 | }, timeout);
|
122 | }
|
123 |
|
124 | this.socket.emit(topic, data);
|
125 | }
|
126 | return this;
|
127 | };
|
128 |
|
129 | Connection.prototype._messageAck = function(response){
|
130 | this.socket.emit('messageAck', response);
|
131 | return this;
|
132 | };
|
133 |
|
134 |
|
135 |
|
136 | Connection.prototype.identify = function(){
|
137 | this.socket.emit('identity', {
|
138 | uuid: this.options.uuid,
|
139 | token: this.options.token,
|
140 | protocol: this.options.protocol
|
141 | });
|
142 | return this;
|
143 | };
|
144 |
|
145 |
|
146 | Connection.prototype.message = function(data, fn) {
|
147 | return this._emitWithAck('message', data, fn);
|
148 | };
|
149 |
|
150 | Connection.prototype.config = function(data, fn) {
|
151 | return this._emitWithAck('gatewayConfig', data, fn);
|
152 | };
|
153 |
|
154 | Connection.prototype.gatewayConfig = function(data, fn) {
|
155 | return this._emitWithAck('gatewayConfig', data, fn);
|
156 | };
|
157 |
|
158 |
|
159 | Connection.prototype.send = function(text) {
|
160 |
|
161 | if(text){
|
162 | text = text.toString();
|
163 | this.socket.send(text);
|
164 | }
|
165 |
|
166 | return this;
|
167 | };
|
168 |
|
169 | Connection.prototype.update = function(data, fn) {
|
170 | this.socket.emit('update', data, fn);
|
171 | return this;
|
172 | };
|
173 |
|
174 | Connection.prototype.register = function(data, fn) {
|
175 | this.socket.emit('register', data, fn);
|
176 | return this;
|
177 | };
|
178 |
|
179 | Connection.prototype.unregister = function(data, fn) {
|
180 | this.socket.emit('unregister', data, fn);
|
181 | return this;
|
182 | };
|
183 |
|
184 | Connection.prototype.claimdevice = function(data, fn) {
|
185 | this.socket.emit('claimdevice', data, fn);
|
186 | return this;
|
187 | };
|
188 |
|
189 | Connection.prototype.whoami = function(data, fn) {
|
190 | this.socket.emit('whoami', data, fn);
|
191 | return this;
|
192 | };
|
193 |
|
194 | Connection.prototype.devices = function(data, fn) {
|
195 | this.socket.emit('devices', data, fn);
|
196 | return this;
|
197 | };
|
198 |
|
199 | Connection.prototype.mydevices = function(data, fn) {
|
200 | this.socket.emit('mydevices', data, fn);
|
201 | return this;
|
202 | };
|
203 |
|
204 | Connection.prototype.status = function(data) {
|
205 | this.socket.emit('status', data);
|
206 | return this;
|
207 | };
|
208 |
|
209 | Connection.prototype.subscribe = function(data, fn) {
|
210 | if(typeof data === 'string'){
|
211 | data = {uuid: data};
|
212 | }
|
213 | this.socket.emit('subscribe', data, fn);
|
214 | return this;
|
215 | };
|
216 |
|
217 | Connection.prototype.unsubscribe = function(data, fn) {
|
218 | if(typeof data === 'string'){
|
219 | data = {uuid: data};
|
220 | }
|
221 | this.socket.emit('unsubscribe', data, fn);
|
222 | return this;
|
223 | };
|
224 |
|
225 | Connection.prototype.authenticate = function(data, fn) {
|
226 | this.socket.emit('authenticate', data, fn);
|
227 | return this;
|
228 | };
|
229 |
|
230 | Connection.prototype.events = function(data, fn) {
|
231 | this.socket.emit('events', data, fn);
|
232 | return this;
|
233 | };
|
234 |
|
235 | Connection.prototype.data = function(data, fn) {
|
236 | this.socket.emit('data', data, fn);
|
237 | return this;
|
238 | };
|
239 |
|
240 | Connection.prototype.getdata = function(data, fn) {
|
241 | this.socket.emit('getdata', data, fn);
|
242 | return this;
|
243 | };
|
244 |
|
245 | Connection.prototype.localdevices = function(fn) {
|
246 | this.socket.emit('localdevices', {}, fn);
|
247 | return this;
|
248 | };
|
249 |
|
250 | Connection.prototype.textBroadcast = function(data) {
|
251 | if(typeof data !== 'string'){
|
252 | data = String(data);
|
253 | }
|
254 | this.socket.emit('tb', data);
|
255 | return this;
|
256 | };
|
257 |
|
258 | Connection.prototype.directText = function(data) {
|
259 | if(typeof data === 'object' && data.payload && typeof data.payload === 'string' && data.devices){
|
260 | this.socket.emit('directText', data);
|
261 | }
|
262 | else{
|
263 | console.log('directText requires an object with a string payload property, and a devices property');
|
264 | }
|
265 |
|
266 | return this;
|
267 | };
|
268 |
|
269 | Connection.prototype.subscribeText = function(data, fn) {
|
270 | if(typeof data === 'string'){
|
271 | data = {uuid: data};
|
272 | }
|
273 | this.socket.emit('subscribeText', data, fn);
|
274 | return this;
|
275 | };
|
276 |
|
277 | Connection.prototype.unsubscribeText = function(data, fn) {
|
278 | if(typeof data === 'string'){
|
279 | data = {uuid: data};
|
280 | }
|
281 | this.socket.emit('unsubscribeText', data, fn);
|
282 | return this;
|
283 | };
|
284 |
|
285 |
|
286 | Connection.prototype.close = function(fn){
|
287 | this.socket.close(fn);
|
288 | return this;
|
289 | };
|
290 |
|
291 |
|
292 |
|
293 | module.exports = Connection;
|