/lib/socketLogic.js

https://github.com/SYCCON/skynet · JavaScript · 843 lines · 598 code · 207 blank · 38 comment · 89 complexity · b735bd6514a9a4740f3abe19d71ee5f2 MD5 · raw file

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