PageRenderTime 45ms CodeModel.GetById 2ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/socketLogic.js

https://github.com/SYCCON/skynet
JavaScript | 843 lines | 598 code | 207 blank | 38 comment | 89 complexity | b735bd6514a9a4740f3abe19d71ee5f2 MD5 | raw file
  1var whoAmI = require('./whoAmI');
  2var config = require('../config');
  3var getData = require('./getData');
  4var logData = require('./logData');
  5var logEvent = require('./logEvent');
  6var register = require('./register');
  7var getEvents = require('./getEvents');
  8var getDevices = require('./getDevices');
  9var authDevice = require('./authDevice');
 10var unregister = require('./unregister');
 11var claimDevice = require('./claimDevice');
 12var securityImpl = require('./getSecurityImpl');
 13var createActivity = require('./createActivity');
 14var updateSocketId = require('./updateSocketId');
 15var updatePresence = require('./updatePresence');
 16var getLocalDevices = require('./getLocalDevices');
 17var getSystemStatus = require('./getSystemStatus');
 18var updateFromClient = require('./updateFromClient');
 19
 20
 21function getActivity(topic, socket, device, toDevice){
 22  return createActivity(topic, socket.ipAddress, device, toDevice);
 23}
 24
 25function getDevice(socket, callback) {
 26  console.log('getDevice socket info:', socket.id, socket.skynetDevice);
 27
 28  if(socket.skynetDevice){
 29    return callback(null, socket.skynetDevice);
 30  }else{
 31    return callback(new Error('skynetDevice not found for socket' + socket), null);
 32  }
 33
 34}
 35
 36
 37function socketLogic (socket, secure, skynet){
 38  console.log('\nsocket connected...');
 39  //TODO check x-forward handshake header on load balancer?
 40  var ipAddress = socket.request.connection.remoteAddress;
 41  socket.ipAddress = ipAddress;
 42  //socket.handshake.address.address; <-busted as of 1.0.6
 43  console.log('\nipAddress', ipAddress);
 44
 45  console.log('Websocket connection detected. Requesting identification from socket id: ', socket.id);
 46  logEvent(100, {"socketid": socket.id, "protocol": "websocket"});
 47
 48  socket.emit('identify', { socketid: socket.id });
 49  socket.on('identity', function (data) {
 50    console.log('identity received', data);
 51    data.socketid = socket.id;
 52    data.ipAddress = ipAddress;
 53    data.secure = secure;
 54    if(!data.protocol){
 55      data.protocol = "websocket";
 56    }
 57    console.log('Identity received: ', JSON.stringify(data));
 58    // logEvent(101, data);
 59    updateSocketId(data, function(auth){
 60      skynet.sendActivity(getActivity('identity',socket));
 61
 62      if (auth.status == 201){
 63
 64          socket.skynetDevice = auth.device;
 65
 66          socket.emit('ready', {"api": "connect", "status": auth.status, "socketid": socket.id, "uuid": auth.device.uuid, "token": auth.device.token});
 67          // Have device join its uuid room name so that others can subscribe to it
 68          console.log('subscribe: ' + auth.device.uuid);
 69
 70          //Announce presence online
 71          var message = {};
 72          message.payload = {"online":true};
 73          message.devices = "*";
 74          skynet.sendMessage(auth.device, message);
 75
 76          //make sure not in there already:
 77          try{
 78            socket.leave(auth.device.uuid);
 79          }catch(lexp){
 80            console.log('error leaving room', lexp);
 81          }
 82          socket.join(auth.device.uuid);
 83
 84      } else {
 85        socket.emit('notReady', {"api": "connect", "status": auth.status, "uuid": data.uuid});
 86      }
 87
 88      whoAmI(data.uuid, false, function(results){
 89        data.auth = auth;
 90        // results._id.toString();
 91        // delete results._id;
 92        data.fromUuid = results;
 93        logEvent(101, data);
 94      });
 95
 96    });
 97  });
 98
 99  socket.on('disconnect', function (data) {
100
101
102    console.log('Presence offline for socket id: ', socket.id);
103    updatePresence(socket.id);
104    // Emit API request from device to room for subscribers
105    getDevice(socket, function(err, device){
106      skynet.sendActivity(getActivity('disconnect', socket, device));
107
108      //Announce presence offline
109      var message = {};
110      message.payload = {"online":false};
111      message.devices = "*";
112      skynet.sendMessage(device, message);
113
114      device = device || null;
115      logEvent(102, {api: "disconnect", socketid: socket.id, device: device});
116    });
117
118  });
119
120
121
122socket.on('subscribeText', function(data, fn) {
123
124
125    if(!data){ return; }
126
127    getDevice(socket, function(err, device){
128      skynet.sendActivity(getActivity('subscribeText', socket, device));
129      if(err){ return; }
130
131      if(data.uuid && data.uuid.length > 30){
132        //no token provided, attempt to only listen for public broadcasts FROM this uuid
133        whoAmI(data.uuid, false, function(results){
134          if(results.error){
135            fn(results);
136          }else{
137            if(securityImpl.canRead(device, results)){
138              socket.join(data.uuid + "_tb");
139              fn({"api": "subscribe", "socketid": socket.id, "toUuid": data.uuid, "result": true});
140            }else{
141              fn({error: "unauthorized access"});
142            }
143
144          }
145
146          data.toUuid = results;
147          logEvent(204, data);
148
149        });
150
151      }
152    });
153
154
155  });
156
157  // Is this API still needed with MQTT?
158  socket.on('subscribe', function(data, fn) {
159
160    if(!data){ return; }
161
162    getDevice(socket, function(err, device){
163      skynet.sendActivity(getActivity('subscribe', socket, device));
164      if(err){ return; }
165
166      if(data.uuid && data.uuid.length > 30 && !data.token){
167        //no token provided, attempt to only listen for public broadcasts FROM this uuid
168        whoAmI(data.uuid, false, function(results){
169          if(results.error){
170            fn(results);
171          }else{
172            if(securityImpl.canRead(device, results)){
173              socket.join(data.uuid + "_bc");
174              if(fn){
175                fn({"api": "subscribe", "socketid": socket.id, "toUuid": data.uuid, "result": true});
176              }
177            }else{
178              if(fn){
179                fn({error: "unauthorized access"});
180              }
181            }
182
183          }
184
185          data.toUuid = results;
186          logEvent(204, data);
187
188        });
189
190      }else{
191        //token provided, attempt to listen to any broadcast FOR this uuid
192        authDevice(data.uuid, data.token, function(auth){
193          if (auth.authenticate){
194            console.log('joining rooms ', data.uuid);
195            socket.join(data.uuid);
196            socket.join(data.uuid + "_bc"); //shouldnt be here?
197
198            // Emit API request from device to room for subscribers
199            var results = {"api": "subscribe", "socketid": socket.id, "fromUuid": device.uuid, "toUuid": data.uuid, "result": true};
200
201            data.auth = auth;
202            data.fromUuid = device;
203            data.toUuid = auth.device;
204            logEvent(204, data);
205
206            try{
207              fn(results);
208            } catch (e){
209              console.log(e);
210            }
211
212          } else {
213            console.log('subscribe failed for room ', data.uuid);
214
215            var results = {"api": "subscribe", "uuid": data.uuid, "result": false};
216            // socket.broadcast.to(uuid).emit('message', results);
217
218            logEvent(204, results);
219
220            console.log(results);
221            try{
222              fn(results);
223
224            } catch (e){
225              console.log(e);
226            }
227
228          }
229
230        });
231      }
232    });
233
234
235  });
236
237  socket.on('unsubscribeText', function(data, fn) {
238    skynet.sendActivity(getActivity('unsubscribeText', socket));
239    try{
240      socket.leave(data.uuid + "_tb");
241      if(fn){
242        fn({"api": "unsubscribeText", "uuid": data.uuid});
243      }
244    } catch (e){
245      console.log(e);
246    }
247  });
248
249  socket.on('unsubscribe', function(data, fn) {
250    console.log('leaving room ', data.uuid);
251    try{
252      socket.leave(data.uuid);
253      socket.leave(data.uuid + "_bc");
254      if(fn){
255        fn({"api": "unsubscribe", "uuid": data.uuid});
256      }
257      getDevice(socket, function(err, device){
258        skynet.sendActivity(getActivity('unsubscribe', socket, device));
259        if(err){ return; }
260        data.fromUuid = device;
261        logEvent(205, data);
262      });
263    } catch (e){
264      console.log(e);
265    }
266  });
267
268  // APIs
269  socket.on('status', function (fn) {
270
271    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
272      if(limited){
273        console.log('status throttled', socket.id);
274      }else{
275
276        // Emit API request from device to room for subscribers
277        getDevice(socket, function(err, device){
278          skynet.sendActivity(getActivity('status', socket, device));
279          if(err){ return; }
280          // socket.broadcast.to(uuid).emit('message', {"api": "status"});
281
282          getSystemStatus(function(results){
283
284            results.fromUuid = device;
285            logEvent(200, results);
286            console.log(results);
287
288            try{
289              fn(results);
290            } catch (e){
291              console.log(e);
292            }
293          });
294
295        });
296      }
297    });
298
299  });
300
301
302
303  socket.on('devices', function (data, fn) {
304
305    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
306      if(limited){
307        console.log('query throttled', socket.id);
308      }else{
309
310        if(!data || (typeof data != 'object')){
311          data = {};
312        }
313
314        getDevice(socket, function(err, device){
315          skynet.sendActivity(getActivity('devices', socket, device));
316          if(err){ return; }
317          var reqData = data;
318          getDevices(device, data, false, function(results){
319            results.fromUuid = device;
320            logEvent(403, results);
321            console.log(results);
322
323            try{
324              fn(results);
325
326            } catch (e){
327              console.log(e);
328            }
329          });
330        });
331      }
332    });
333  });
334
335  socket.on('mydevices', function (data, fn) {
336
337    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
338      if(limited){
339        console.log('query throttled', socket.id);
340      }else{
341        getDevice(socket, function(err, device){
342          skynet.sendActivity(getActivity('mydevices', socket, device));
343          if(err){ return; }
344          getDevices(device, {owner: device.uuid}, true, function(results){
345            try{
346              results.fromUuid = device.uuid;
347              logEvent(403, results);
348              console.log(results);
349              fn(results);
350
351            } catch (e){
352              console.log(e);
353            }
354          });
355        });
356      }
357    });
358  });
359
360
361  socket.on('localdevices', function (data, fn) {
362
363    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
364      if(limited){
365        console.log('query throttled', socket.id);
366      }else{
367
368        if(!data || (typeof data != 'object')){
369          data = {};
370        }
371        // Emit API request from device to room for subscribers
372        getDevice(socket, function(err, device){
373          skynet.sendActivity(getActivity('localdevices', socket, device));
374          if(err){ return; }
375          getLocalDevices(device, false, function(results){
376            results.fromUuid = device;
377            logEvent(403, results);
378            console.log(results);
379
380            try{
381              fn(results);
382
383            } catch (e){
384              console.log(e);
385            }
386          });
387        });
388      }
389    });
390  });
391
392
393  socket.on('claimdevice', function (data, fn) {
394
395    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
396      if(limited){
397        console.log('query throttled', socket.id);
398      }else{
399
400        if(!data || (typeof data != 'object')){
401          data = {};
402        }
403        // Emit API request from device to room for subscribers
404        getDevice(socket, function(err, device){
405          skynet.sendActivity(getActivity('claimdevice', socket, device));
406          if(err){ return; }
407          claimDevice(device, data, function(err, results){
408            logEvent(403, {error: err, results: results, fromUuid: device});
409            console.log('claimdevice', err, results);
410
411            try{
412              fn({error: err, results: results});
413
414            } catch (e){
415              console.log(e);
416            }
417          });
418        });
419      }
420    });
421  });
422
423  socket.on('whoami', function (data, fn) {
424
425    skynet.throttles.whoami.rateLimit(socket.id, function (err, limited) {
426      if(limited){
427        console.log('whoami throttled', socket.id);
428      }else{
429        getDevice(socket, function(err, device){
430          skynet.sendActivity(getActivity('whoami', socket, device));
431          if(err){ return; }
432          try{
433            fn(device);
434          } catch (e){
435            console.log(e);
436          }
437        });
438
439      }
440    });
441
442  });
443
444
445  socket.on('register', function (data, fn) {
446    skynet.sendActivity(getActivity('register', socket));
447
448    if(!data){
449      data = {};
450    }
451    data.socketid = socket.id;
452    data.ipAddress = ipAddress;
453
454    register(data, function(results){
455
456      whoAmI(data.uuid, false, function(check){
457
458        results.fromUuid = check;
459
460        if(!check.error){
461          socket.skynetDevice = check;
462        }
463
464        logEvent(400, results);
465      });
466
467
468
469      try{
470        fn(results);
471
472      } catch (e){
473        console.log(e);
474      }
475    });
476
477  });
478
479  socket.on('update', function (data, fn) {
480
481    if(!data){
482      data = {};
483    }
484    // Emit API request from device to room for subscribers
485    getDevice(socket, function(err, fromDevice){
486      skynet.sendActivity(getActivity('update', socket, fromDevice));
487      if(err){ return; }
488
489      updateFromClient(fromDevice, data, fn);
490
491    });
492  });
493
494  socket.on('unregister', function (data, fn) {
495    skynet.sendActivity(getActivity('',socket));
496
497    if(!data){
498      data = {};
499    }
500    // Emit API request from device to room for subscribers
501    getDevice(socket, function(err, device){
502      skynet.sendActivity(getActivity('unregister', socket, device));
503      if(err){ return; }
504      var reqData = data;
505      unregister(device, data.uuid, function(results){
506
507        console.log(results);
508
509        if(results == null || results == undefined){
510          results = {};
511        }
512        results.fromUuid = device;
513        logEvent(402, results);
514
515        try{
516          fn(results);
517
518        } catch (e){
519          console.log(e);
520        }
521      });
522    });
523  });
524
525  socket.on('events', function(data, fn) {
526
527    authDevice(data.uuid, data.token, function(auth){
528
529      // Emit API request from device to room for subscribers
530      getDevice(socket, function(err, device){
531        skynet.sendActivity(getActivity('events', socket, device));
532        if(err){ return; }
533        var reqData = data;
534        reqData.api = "events";
535
536        if (auth.authenticate){
537
538          getEvents(data.uuid, function(results){
539            console.log(results);
540
541            try{
542              fn(results);
543            } catch (e){
544              console.log(e);
545            }
546
547          });
548
549        } else {
550          console.log('UUID not found or invalid token ', data.uuid);
551
552          var results = {"api": "events", "result": false};
553
554          console.log(results);
555          try{
556            fn(results);
557
558          } catch (e){
559            console.log(e);
560          }
561
562        }
563
564      });
565
566    });
567  });
568
569
570  socket.on('authenticate', function(data, fn) {
571    skynet.sendActivity(getActivity('authenticate', socket));
572
573    authDevice(data.uuid, data.token, function(auth){
574      var results;
575      if (auth.authenticate){
576        results = {"uuid": data.uuid, "authentication": true};
577
578        socket.emit('ready', {"api": "connect", "status": 201, "socketid": socket.id, "uuid": data.uuid});
579        console.log('subscribe: ' + data.uuid);
580        socket.join(data.uuid);
581
582        try{
583          fn(results);
584        } catch (e){
585          console.log(e);
586        }
587
588      } else {
589        results = {"uuid": data.uuid, "authentication": false};
590        try{
591          fn(results);
592        } catch (e){
593          console.log(e);
594        }
595
596      }
597
598      // require('./lib/whoAmI')(data.uuid, false, function(check){
599      whoAmI(data.uuid, false, function(check){
600        // check._id.toString();
601        // delete check._id;
602        results.toUuid = check;
603        logEvent(102, results);
604      });
605
606
607    });
608  });
609
610  socket.on('data', function (messageX, fn) {
611
612    skynet.throttles.data.rateLimit(socket.id, function (err, limited) {
613      if(limited){
614        console.log('data throttled', socket.id);
615      }else{
616        var data = messageX;
617
618        getDevice(socket, function(err, fromDevice){
619          skynet.sendActivity(getActivity('data', socket, fromDevice));
620          if(err){ return; }
621
622          delete data.token;
623
624          logData(data, function(results){
625            console.log(results);
626
627            // Send messsage regarding data update
628            var message = {};
629            message.payload = data;
630            // message.devices = data.uuid;
631            message.devices = "*";
632
633            console.log('message: ' + JSON.stringify(message));
634
635            skynet.sendMessage(fromDevice, message);
636
637
638            try{
639              fn(results);
640            } catch (e){
641              console.log(e);
642            }
643
644          });
645
646        });
647
648      }
649    });
650  });
651
652  socket.on('getdata', function (data, fn) {
653
654    skynet.throttles.query.rateLimit(socket.id, function (err, limited) {
655      if(limited){
656        console.log('query throttled', socket.id);
657      }else{
658        skynet.sendActivity(getActivity('getdata', socket));
659        authDevice(data.uuid, data.token, function(auth){
660
661          if (auth.authenticate){
662
663            if(!data || (typeof data != 'object')){
664              data = {};
665            }
666            data.params = {};
667            data.query = {};
668
669            data.params.uuid = data.uuid;
670            data.query.start = data.start; // time to start from
671            data.query.finish = data.finish; // time to end
672            data.query.limit = data.limit; // 0 bypasses the limit
673
674            getData(data, function(results){
675              // if(err){ return; }
676
677              results.fromUuid = socket.skynetDevice.uuid;
678              console.log(results);
679
680              try{
681                fn(results);
682
683              } catch (e){
684                console.log(e);
685              }
686
687            });
688
689          } else {
690            console.log('UUID not found or invalid token ', data.uuid);
691
692            var results = {"api": "getdata", "result": false};
693
694            console.log(results);
695            try{
696              fn(results);
697            } catch (e){
698              console.log(e);
699            }
700          }
701
702        });
703
704      }
705    });
706  });
707
708
709  socket.on('gatewayConfig', function(data) {
710
711    getDevice(socket, function(err, device){
712      skynet.sendActivity(getActivity('gatewayConfig', socket, device));
713      if(err){ return; }
714      skynet.gateway.config(device, data);
715    });
716
717  });
718
719  socket.on('gatewayConfigAck', function (data) {
720
721    getDevice(socket, function(err, device){
722      skynet.sendActivity(getActivity('gatewayConfigAck', socket, device));
723      if(err){ return; }
724      skynet.gateway.configAck(device, data);
725    });
726  });
727
728  socket.on('messageAck', function (data) {
729
730    getDevice(socket, function(err, fromDevice){
731      skynet.sendActivity(getActivity('messageAck', socket, fromDevice));
732      if(fromDevice){
733        whoAmI(data.devices, false, function(check){
734          data.fromUuid = fromDevice.uuid;
735          if(!check.error && securityImpl.canSend(fromDevice, check)){
736            skynet.emitToClient('messageAck', check, data);
737          }
738        });
739      }
740    });
741  });
742
743
744  socket.on('tb', function (messageX) {
745
746    // socket.limiter.removeTokens(1, function(err, remainingRequests) {
747    skynet.throttles.message.rateLimit(socket.id, function (err, limited) {
748      var message = messageX;
749
750      if (limited) {
751
752        // TODO: Emit rate limit exceeded message
753        console.log("Rate limit exceeded for socket:", socket.id);
754        console.log("message", message);
755
756      } else {
757        console.log("Sending message for socket:", socket.id, message);
758
759        if(!message){
760          return;
761        }else{
762          message = message.toString();
763
764          // Broadcast to room for pubsub
765          getDevice(socket, function(err, fromDevice){
766            skynet.sendActivity(getActivity('tb', socket, fromDevice));
767            if(fromDevice){
768              skynet.sendMessage(fromDevice, {payload: message}, 'tb');
769            }
770          });
771        }
772
773      }
774    });
775
776  });
777
778
779
780  socket.on('message', function (messageX) {
781
782    // socket.limiter.removeTokens(1, function(err, remainingRequests) {
783    skynet.throttles.message.rateLimit(socket.id, function (err, limited) {
784      var message = messageX;
785
786      if (limited) {
787
788        // TODO: Emit rate limit exceeded message
789        console.log("Rate limit exceeded for socket:", socket.id);
790        console.log("message", message);
791
792      } else {
793        console.log("Sending message for socket:", socket.id, message);
794
795        if(typeof message !== 'object'){
796          return;
797        }else{
798          // Broadcast to room for pubsub
799          getDevice(socket, function(err, fromDevice){
800            skynet.sendActivity(getActivity('message', socket, fromDevice));
801            if(fromDevice){
802              message.api = "message";
803              skynet.sendMessage(fromDevice, message);
804            }
805          });
806        }
807
808      }
809    });
810
811  });
812
813  socket.on('directText', function (messageX) {
814
815    // socket.limiter.removeTokens(1, function(err, remainingRequests) {
816    skynet.throttles.message.rateLimit(socket.id, function (err, limited) {
817      var message = messageX;
818
819      if (limited) {
820
821        // TODO: Emit rate limit exceeded message
822        console.log("Rate limit exceeded for socket:", socket.id);
823        console.log("message", message);
824
825      } else {
826        console.log("Sending message for socket:", socket.id, message);
827
828        getDevice(socket, function(err, fromDevice){
829          skynet.sendActivity(getActivity('directText', socket, fromDevice));
830          if(fromDevice){
831            skynet.sendMessage(fromDevice, message, 'tb');
832          }
833        });
834
835      }
836    });
837
838  });
839
840}
841
842
843module.exports = socketLogic;