PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/documents/npush-versions/v2/npush-s-v2.io.js

https://bitbucket.org/newicon/npush-server
JavaScript | 1629 lines | 872 code | 398 blank | 359 comment | 172 complexity | ed60d4a5f64a661d224b4c2aed978d49 MD5 | raw file
  1. /*! NEWICON NPUSH SERVER build: 2.0.0 , development. Copyright(c) 2012 NEWICON LTD */
  2. /*
  3. * !!! CURRENTLY IN DEVELOPMENT !!!
  4. */
  5. /*
  6. * Proper command line to launch n:push
  7. *
  8. * Example command:
  9. * $ NODE_ENV=production node n-push-s.js 8080 10
  10. *
  11. * Description:
  12. * $ -environement- -node- -script_name- -port- -instances-
  13. */
  14. /*
  15. * TO DO
  16. * ok - optimize users list for app/channel/room - probably best solution is send
  17. * changes only for user subscribed for path /service/activity/users
  18. * ok - optimize api activity, maybe the best is send to /service/activity/api
  19. * ok - add activity for server, path should be /service/activity/system
  20. * ok - delete user from nicnames object when disconnected,
  21. * clear also not active api/channel/room from nicknames object
  22. * - add messeage-read event as an option in npush library
  23. * - merge 3 different function for API POST (brodcast, channel, room)
  24. * to one function
  25. * - api activity - calculate incoming and outgoing traffic
  26. * ok - add active sockets count to message - will be used in receipts area
  27. * - maybe good idea is create array like nicnames but with sockets - it could
  28. * imprvoe sendind messages to socket in app or in channel or in room
  29. * ok - on connect we should delete event appusers and channelusers. Only room
  30. * users should be still. appusers and channelusers should be moved to
  31. * apiactivty channel stats!
  32. * - add function to calculate number of sockets in api/channel/rooms -> should
  33. * be updated after each connect and disconnect
  34. * - add activity metter when send messages for public_activity history
  35. * - public_activity - messages history - ability to get messages
  36. * with recepit as option. the same functionality to public_activity and
  37. * public_activity_ms
  38. * - public_activiyt_XXX - optimize this functions, now both are too big
  39. * - new EVENT to get receipt for passed message_id
  40. * - probably good idea is handle event for each socket depends on events handle
  41. * when channel is created on client side. For this, we have to pass list
  42. * of events with data to hanfdhake process. if handshaked then we can
  43. * create event callback for user list. NOW ALL EVENTS ARE ALWAYS CREATED.
  44. * ok - dont send list of users every second. send only if something was chnaged
  45. * - size of nicknames array
  46. * - size of activity array
  47. * - add console start up arguments:
  48. *
  49. * npush-port
  50. * number-of-instances to run
  51. * mongo-adress:port:username:password:db
  52. * redis-store-address:port:password
  53. *
  54. * - MULTI INSTANCES PROBLEMS TO SOLVE
  55. * ok - now we have scokets belongs to API on diffrent node processes, so to calculate
  56. * statistics we have to send stats to MASTER, MERGE data and then send stats
  57. * to SLAVES; info we need are sockets, dbs
  58. * - important - data should be calculated and send only if any api_key/npush/*
  59. * channel exist
  60. *
  61. * BUGS
  62. * ok - on user connect the new users list is send to all api sockets. Should be
  63. * send only to sockets in api of joined user
  64. * - when looking for rooms name in socket.manager.rooms using _string.substr
  65. * need to check also length of string. now /service and service1
  66. * is the same for that method and it is really wrong
  67. *
  68. * SCARY
  69. * - when users receive list of user it generate huge traffic for each
  70. * user authorisation and disconnection, reconnect etc.
  71. * IT MUST BE AS OPTION AND ONLY FOR SPECIAL SERVICE CHANNEL
  72. * ok - doconnected user from room dont delete channel/room from history. IT IS THE
  73. * REASON WHY AFTER MANY CONNECTION AND DISCONNECTION ALL GO SLOWER...
  74. */
  75. /**
  76. * Krzysztof Stasiak
  77. * npush-s.js
  78. * Copyright(c) 2012 NEWICON LTD <newicon@newicon.net>
  79. * GPL Licensed
  80. */
  81. var cluster = require('cluster');
  82. var http = require('http');
  83. var startInstancesNumber = (process.argv[3]) || 1;
  84. /**
  85. * APIs Activity Manager
  86. *
  87. * Calcualte API activity and send information if any socket
  88. * handle that event.
  89. *
  90. * @param object socket
  91. */
  92. function PusherAPIStatsRecordCreate(socket)
  93. {
  94. return {
  95. s:{ // summary
  96. m:0, // m -> messages count
  97. pm:0, // pm -> messages count 1 second before
  98. mps:0, // mps -> messages per second
  99. mpm:0, // mpm -> messages per minute
  100. mph:0, // mph -> messages per hour
  101. dbrps:0, // dbr -> db reads per second
  102. dbwps:0, // dbw -> db writes per second
  103. dbups:0 // dbu -> db updates per second
  104. },
  105. t:{ // temp history
  106. mh: new Array(), // last 60 second history
  107. mhp: 0, // last 60 second history pointer
  108. hh: new Array(), // last 60 minute history
  109. hhp: 0 // last 60 minute history pointer
  110. },
  111. c:{ // connection
  112. s:false, // new list is waiting for send
  113. a:true // allow traffic
  114. },
  115. n:{ // npush
  116. as:0, // active sockets
  117. n:'n/a' // client name
  118. }
  119. };
  120. }
  121. /**
  122. * Master Server Instance
  123. *
  124. * 1. Master instance forks workers up to startInstancesNumber number.
  125. * 2. Master process receive worker messages and send own to workers.
  126. * 3. Master process manage load-balancer of TCP traffic in cluster.
  127. */
  128. if(cluster.isMaster) {
  129. // this object should keep all statistics sockets, db, process data for
  130. // all running instaneces
  131. var stats = {
  132. w:new Array(), // worker PID list
  133. a:new Object(), // activity for all socket
  134. n:new Object(), // global nicknames
  135. t:{ // traffic
  136. a:true // allow traffic
  137. }
  138. };
  139. // this object contain activity from all workers
  140. var activityGlobal = new Array();
  141. var nicknameGlobal = new Array();
  142. // do this when worker receive a message
  143. function messageHandler(data) {
  144. if(data.event == 'worker-activity') {
  145. // get feedback from worker if master send 'send-activity' event
  146. for(s in data.data.a) {
  147. if(!activityGlobal[s])
  148. activityGlobal[s] = new Array();
  149. activityGlobal[s][this.id] = data.data.a[s];
  150. }
  151. // merge nickanmes for all workers
  152. for(a in data.data.n) {
  153. for(c in data.data.n[a]) {
  154. for(r in data.data.n[a][c]) {
  155. for(u in data.data.n[a][c][r]) {
  156. if(!stats.n[a]) stats.n[a] = new Object();
  157. if(!stats.n[a][c]) stats.n[a][c] = new Object();
  158. if(!stats.n[a][c][r]) stats.n[a][c][r] = new Object();
  159. stats.n[a][c][r][u] = data.data.n[a][c][r][u];
  160. }
  161. }
  162. }
  163. }
  164. } else if(data.event == 'system-command') {
  165. if(data.data.action) {
  166. if(data.data.action == 'traffic') {
  167. if(data.data.value == '0') {
  168. stats.t.a = false;
  169. } else if(data.data.value == '1') {
  170. stats.t.a = true;
  171. }
  172. }
  173. }
  174. }
  175. }
  176. // create workers process
  177. for (var i = 0; i < startInstancesNumber; i++) {
  178. cluster.fork();
  179. }
  180. // listen for worker messages
  181. Object.keys(cluster.workers).forEach(function(id) {
  182. stats.w.push(cluster.workers[id].process.pid);
  183. cluster.workers[id].on('message', messageHandler);
  184. });
  185. // do this when worker died
  186. cluster.on('exit', function(worker, code, signal) {
  187. console.log('worker ' + worker.process.pid + ' died');
  188. });
  189. // calculate stats for all workers
  190. function ModuleMasterCalculateStats() {
  191. for(s in activityGlobal) {
  192. for(w in activityGlobal[s]) {
  193. if(!stats.a[s])
  194. stats.a[s] = PusherAPIStatsRecordCreate();
  195. stats.a[s].s.m += activityGlobal[s][w].s.m;
  196. stats.a[s].s.pm += activityGlobal[s][w].s.pm;
  197. stats.a[s].s.dbrps += activityGlobal[s][w].s.dbrps;
  198. stats.a[s].s.dbwps += activityGlobal[s][w].s.dbwps;
  199. stats.a[s].s.dbups += activityGlobal[s][w].s.dbups;
  200. stats.a[s].n.as += activityGlobal[s][w].n.as;
  201. if(activityGlobal[s][w].c.s)
  202. stats.a[s].c.s = true;
  203. }
  204. }
  205. Object.keys(cluster.workers).forEach(function(id) {
  206. // send data to worker who send message to master
  207. cluster.workers[id].send({event:'global-stats', data:stats});
  208. // ask for current stats from worker
  209. cluster.workers[id].send({event:'send-activity'});
  210. });
  211. // reset status before ask workers for new one
  212. stats.a = new Object();
  213. stats.n = new Object();
  214. activityGlobal = new Array();
  215. // set new timeout
  216. _tseconds = setTimeout(function(){ModuleMasterCalculateStats(); },1000);
  217. }
  218. // start stats for all workers
  219. var _tseconds = setTimeout(function(){ModuleMasterCalculateStats(); },1000);
  220. } else {
  221. /**
  222. * THIS CODE IS LAUNCH ONLY FOR SLAVE/WORKERS
  223. *
  224. * Private Server / Cluster Keys for management
  225. */
  226. var NPUSH_SERVER_STATUS_APIKEY = '12345678987654321';
  227. var NPUSH_SERVER_CONTROL_APIKEY = '12345678987654321';
  228. /**
  229. * Module dependencies.
  230. */
  231. var express = require('express')
  232. , stylus = require('stylus')
  233. , nib = require('nib')
  234. , sio = require('socket.io')
  235. , RedisStore = sio.RedisStore
  236. , databaseUrl = "ni_sockets" //'username:password@example.com:port/mydb'
  237. , collections = ["messages_public", "messages_private", "accounts"]
  238. , db = require("mongojs").connect(databaseUrl, collections)
  239. , port = process.argv[2]
  240. , qs = require('querystring')
  241. , util = require('util')
  242. , os = require('os-utils');
  243. /*******************************************************************************
  244. * App.
  245. ******************************************************************************/
  246. var app = express.createServer();
  247. /*******************************************************************************
  248. * App configuration.
  249. ******************************************************************************/
  250. app.configure(function () {
  251. app.use(stylus.middleware({
  252. src: __dirname + '/public',
  253. compile: compile
  254. }));
  255. app.use(express.static(__dirname + '/public'));
  256. app.set('views', __dirname);
  257. app.set('view engine', 'jade');
  258. function compile (str, path) {
  259. return stylus(str)
  260. .set('filename', path)
  261. .use(nib());
  262. };
  263. });
  264. /*******************************************************************************
  265. * App routes.
  266. *
  267. * This function redirect standard http traffic to index.html file
  268. ******************************************************************************/
  269. app.get('/', function (req, res) {
  270. res.render('public/index', {
  271. layout: false
  272. });
  273. });
  274. /**
  275. * App listen.
  276. */
  277. app.listen(port, function () {
  278. var addr = app.address();
  279. console.log(' app listening on http://' + addr.address + ':' + addr.port);
  280. });
  281. /*******************************************************************************
  282. * Socket.IO server (single process only)
  283. ******************************************************************************/
  284. var io = sio.listen(app)
  285. , nicknames = new Object()
  286. , activity = new Object()
  287. , activityGlobal = new Object()
  288. , nicknameGlobal = new Object()
  289. , system = os.platform()
  290. , workersInstances = new Array()
  291. , allowGlobalTraffic = true;
  292. // detect system
  293. if(system == 'linux') {
  294. system = 1;
  295. } else {
  296. system = 2;
  297. }
  298. // list of active users
  299. nicknames = {};
  300. // activity
  301. activity = {};
  302. // socket.io SETTINGS
  303. io.configure('production', function(){
  304. io.enable('browser client minification'); // send minified client
  305. io.enable('browser client etag'); // apply etag caching logic based on version number
  306. io.enable('browser client gzip'); // gzip the file
  307. io.set('log level', 1); // reduce logging
  308. io.set('transports', [ // enable all transports (optional if you want flashsocket)
  309. 'websocket'
  310. , 'flashsocket'
  311. , 'htmlfile'
  312. , 'xhr-polling'
  313. , 'jsonp-polling'
  314. ]);
  315. io.set('store', new RedisStore());
  316. });
  317. io.configure('development', function(){
  318. io.set('transports', ['websocket']);
  319. io.set('store', new RedisStore({ id: function () { cluster.worker.id } }));
  320. });
  321. /**
  322. * Socket.io configuration for:
  323. *
  324. * Authorisation process. This function looking for API key and on success
  325. * return object with proper socket data.
  326. *
  327. * @param object handshakeData
  328. * @param function callback
  329. */
  330. io.configure(function (){
  331. io.set('authorization', function (handshakeData, callback) {
  332. if(!allowGlobalTraffic && NPUSH_SERVER_STATUS_APIKEY != handshakeData.query.k
  333. && NPUSH_SERVER_CONTROL_APIKEY != handshakeData.query.k)
  334. return;
  335. db.collection('apis')
  336. .find(JSON.parse('{ "key" : "' + handshakeData.query.k + '", "enabled" : "true" }'))
  337. .forEach(function(err, doc) {
  338. if(!doc && NPUSH_SERVER_STATUS_APIKEY != handshakeData.query.k
  339. && NPUSH_SERVER_CONTROL_APIKEY != handshakeData.query.k) {
  340. callback(null, false);
  341. } else {
  342. handshakeData.client_room = handshakeData.query.k;
  343. handshakeData.client_wellcome_msg = 'Welcome in Newicon Pusher System V.2';
  344. handshakeData.address = handshakeData.address.address;
  345. handshakeData.port = handshakeData.address.port;
  346. handshakeData.api_key = handshakeData.query.k;
  347. handshakeData.channel = handshakeData.query.c;
  348. handshakeData.user_id = handshakeData.query.id;
  349. handshakeData.user_name = handshakeData.query.name;
  350. handshakeData.user_room = handshakeData.query.room;
  351. PusherAPIsActivity({client:handshakeData.query.k}, 0, 1, 0, 0);
  352. callback(null, true);
  353. }
  354. });
  355. });
  356. });
  357. /**
  358. * Create proper msg object using data sent form socket to server.
  359. * Return object ready to send from server to sockets.
  360. *
  361. * @param object msg - message from socket which must be broadcasted
  362. * @param object socket - message sender socket owner
  363. *
  364. * @return object
  365. */
  366. function PusherMakeMessage(msg, socket) {
  367. var _time = new Date();
  368. return {
  369. dataSystem : {
  370. user_id: socket.user_id,
  371. user_name: socket.nickname,
  372. room: socket.room,
  373. channel: socket.channel,
  374. time: parseInt(_time.getTime()),
  375. client: socket.client,
  376. type: 0, // 0 - room, 1 - channel, 2 - app
  377. archive: 0, // 0 - from socket, 1 - from db
  378. msg_id: 0, // msg id in db
  379. source: 0 // 0 - socket, 1 - POST
  380. },
  381. dataUser : msg.data,
  382. event : msg.event
  383. };
  384. }
  385. /**
  386. * Create proper msg object using mongo document. Return object
  387. * ready to send from server to socket.
  388. *
  389. * @param object doc - mongoDB document
  390. * @return object
  391. */
  392. function PusherMakeMessageFromDB(doc) {
  393. return {
  394. dataSystem : {
  395. user_id: doc['user']['id'],
  396. user_name: doc['user']['name'],
  397. room: doc['room'],
  398. channel: '',
  399. time: doc['date'],
  400. client: doc['api_key'],
  401. type: 0, // 0 - room, 1 - channel, 2 - app
  402. archive: 1, // 0 - from socket, 1 - from db
  403. msg_id: 0, // msg id in db
  404. source: doc['source'] // 0 - socket, 1 - POST
  405. },
  406. dataUser : doc['message']['data'],
  407. event : doc['message']['event']
  408. };
  409. }
  410. /**
  411. * Create proper msg object using POST Request. Return object
  412. * ready to send from server to socket.
  413. *
  414. * @param object request - POST data
  415. * @return object
  416. */
  417. function PusherMakeMessageFromPOST(req) {
  418. // must be implemented
  419. }
  420. /**
  421. * Updating users activity. Activity is updated for userId
  422. *
  423. * @param object socket
  424. */
  425. function PusherUserActivityUpdate(socket) {
  426. var _time = new Date();
  427. var _search_json = '{ "user_id" : "' + socket.user_id + '" }';
  428. var _update_json = '{ "user_id" : "' + socket.user_id + '", "date" : ' + _time.getTime() + ', "date_string" : "' + _time.getTime() + '", \n\
  429. "rooms./' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : "' + _time.getTime() + '",\n\
  430. "rooms./' + socket.client + '/' + socket.channel + '/' + socket.room + '/.name" : "/' + socket.client + '/' + socket.channel + '/' + socket.room + '/" } ';
  431. _search = JSON.parse(_search_json);
  432. _update = JSON.parse(_update_json);
  433. db.collection('act_' + socket.client).update(_search, {
  434. $set : _update
  435. } , {
  436. upsert : true
  437. } );
  438. PusherAPIsActivity(socket, 0, 0, 0, 1);
  439. }
  440. /**
  441. * Saving message sent by socket to server
  442. *
  443. * @param object msg
  444. * @param string path
  445. * @param object socket
  446. * @param function callback
  447. */
  448. function PusherUserMessageSave(msg, path, socket, callback)
  449. {
  450. var _data = PusherMakeMessage(msg, socket);
  451. db.collection('msg_' + socket.handshake.client_room).save({
  452. "api_key": socket.api_key,
  453. "room" : path,
  454. "user" : {
  455. "id" : socket.user_id,
  456. "name" : socket.user_name
  457. } ,
  458. "date": _data.dataSystem.time,
  459. "date_string": _data.dataSystem.time.toString(),
  460. "message" : msg,
  461. "client" : socket.handshake.address + ':' + socket.handshake.port,
  462. "source" : 0, // 0 - socket, 1 - POST
  463. "as" : 0 // active sockets
  464. }, function(err, obj){
  465. _data.dataSystem.msg_id = obj._id;
  466. callback.call(this, _data);
  467. // send activity stats for debuging
  468. PusherAPIsActivity(socket, 1, 0, 1, 0);
  469. });
  470. }
  471. /**
  472. * Saving message sent by POST to server
  473. *
  474. * @param object msg
  475. * @param string path
  476. * @param object socket
  477. * @param function callback
  478. */
  479. function PusherUserMessageSaveFromPOST(msg, path, req, callback)
  480. {
  481. // waiting for implementing. Needed for POST API.
  482. }
  483. /**
  484. * Updating Receipt Collection for each delivery confirmation
  485. *
  486. * @param object msg - object with message id as string
  487. * @param object socket
  488. */
  489. function PusherUserMessageRead(msg, socket)
  490. {
  491. var _time = new Date();
  492. var _search_json = '{ "msg_id" : "' + msg.msg_id + '" }';
  493. var _update_json = '{ "msg_id" : "' + msg.msg_id + '", "users.' + socket.user_id + '.date" : "' + _time.getTime() + '"} ';
  494. _search = JSON.parse(_search_json);
  495. _update = JSON.parse(_update_json);
  496. db.collection('msg_read_' + socket.client).update(_search, {
  497. $set : _update
  498. } , {
  499. upsert : true
  500. } );
  501. PusherAPIsActivity(socket, 1, 0, 0, 1);
  502. }
  503. /**
  504. * Increase counters of traffic in sockets and database
  505. *
  506. * @param int m - number of messages send in socket
  507. * @param int dbr - number of db read operations
  508. * @param int dbw - nubmer of db write operations
  509. * @param int dbu - number of db update operations
  510. */
  511. function PusherAPIsActivity(socket, m, dbr, dbw, dbu) {
  512. if(!activity[socket.client])
  513. activity[socket.client] = PusherAPIStatsRecordCreate(socket);
  514. // sockets sounters
  515. activity[socket.client].s.m += m;
  516. // db counters
  517. activity[socket.client].s.dbrps += dbr;
  518. activity[socket.client].s.dbwps += dbw;
  519. activity[socket.client].s.dbups += dbu;
  520. }
  521. /**
  522. * Send API Activity for socket on path npush/stats and npush/users
  523. * with subscribed event for "apiactivity"
  524. */
  525. function PusherAPIsActivityStats()
  526. {
  527. // finish here if worker is not first one
  528. if(cluster.worker.id > 1) return;
  529. // get list of rooms in socket.io
  530. var rooms = io.sockets.manager.rooms;
  531. // calculate statistics
  532. var pmem = process.memoryUsage();
  533. var ppid = process.pid;
  534. // temp object with important info for Administrator
  535. var sstats = {}; // all sockets stats
  536. var tstats = {mps:0,mpm:0,mph:0,dbr:0,dbw:0,dbu:0}; // global traffic stats
  537. var aconn = 0; // all active connections
  538. for(socket in activityGlobal) {
  539. if(!activity[socket])
  540. activity[socket] = PusherAPIStatsRecordCreate();
  541. // calculate how many messages was sent last second
  542. activityGlobal[socket].s.mps = activityGlobal[socket].s.m - activityGlobal[socket].s.pm;
  543. // calculate how many messages in last minute
  544. activity[socket].t.mh[activity[socket].t.mhp] = activityGlobal[socket].s.mps;
  545. if(activity[socket].t.mhp < 60) {
  546. activity[socket].t.mhp++
  547. } else {
  548. activity[socket].t.mhp = 0;
  549. activity[socket].t.hhp++
  550. }
  551. var mpm = 0;
  552. for(i=0; i<activity[socket].t.mh.length;i++)
  553. mpm += activity[socket].t.mh[i];
  554. activity[socket].s.mpm = mpm;
  555. // calculate how many messages in last hour
  556. activity[socket].t.hh[activity[socket].t.hhp] = activity[socket].s.mpm;
  557. if(activity[socket].t.hhp > 59) {
  558. activity[socket].t.hhp = 0;
  559. }
  560. var mph = 0;
  561. for(i=0; i<activity[socket].t.hh.length;i++)
  562. mph += activity[socket].t.hh[i];
  563. activity[socket].s.mph = mph;
  564. // send stats to subscribed sockets
  565. var _path = '/' + socket + '/npush/api/stats';
  566. activity[socket].s.proc = {mem:pmem.rss, pid:ppid};
  567. activityGlobal[socket].s.mpm = activity[socket].s.mpm;
  568. activityGlobal[socket].s.mph = activity[socket].s.mph;
  569. for(room in rooms)
  570. if(room.search(_path) == 0) {
  571. io.sockets.in(room.substr(1, room.length)).emit('apiactivity', activityGlobal[socket].s);
  572. PusherAPIsActivity({client:socket}, 1, 0, 0, 0);
  573. }
  574. // send users sockets list to subscribed sockets
  575. if(activityGlobal[socket].c.s) {
  576. var _path = '/' + socket + '/npush/api/users';
  577. for(room in rooms)
  578. if(room.search(_path) == 0) {
  579. io.sockets.in(room.substr(1, room.length)).emit('usersapp', nicknameGlobal[socket]);
  580. PusherAPIsActivity({client:socket}, 1, 0, 0, 0);
  581. }
  582. activityGlobal[socket].c.s = false;
  583. }
  584. // set admin-stats for this API
  585. sstats[socket] = {mps:activityGlobal[socket].s.mps,mpm:activityGlobal[socket].s.mpm,s:activityGlobal[socket].n.as,n:activityGlobal[socket].n.n};
  586. // gobal traffic info
  587. tstats.mps += activityGlobal[socket].s.mps;
  588. tstats.mpm += activityGlobal[socket].s.mpm;
  589. tstats.mph += activityGlobal[socket].s.mph;
  590. tstats.dbr += activityGlobal[socket].s.dbrps;
  591. tstats.dbw += activityGlobal[socket].s.dbwps;
  592. tstats.dbu += activityGlobal[socket].s.dbups;
  593. // summ all connections
  594. aconn += activityGlobal[socket].n.as;
  595. }
  596. // prepare system stats
  597. os.cpuUsage(function(v) {
  598. var _path = '/' + NPUSH_SERVER_STATUS_APIKEY + '/npush/system/stats';
  599. var _data = {
  600. node: new Array(),
  601. api:{
  602. act:sstats
  603. },
  604. os:{
  605. cpu:v,
  606. tm:os.totalmem(),
  607. fm:os.freemem(),
  608. node:{
  609. i: workersInstances.length,
  610. s: startInstancesNumber
  611. }
  612. },
  613. mongo: new Array(),
  614. sockets:{
  615. active:aconn,
  616. traffic:allowGlobalTraffic
  617. },
  618. traffic:tstats
  619. };
  620. if(system == 1) { // linux
  621. var command = 'top -n1 -b';
  622. require('child_process').exec(command, function(error, stdout, stderr) {
  623. var lines = stdout.split("\n");
  624. lines.forEach(function(_item,_i) {
  625. var _p = _item.replace( /[\s\n\r]+/g,' ').split(' ');
  626. if(String(_p[12]).indexOf('mongod') > -1) {
  627. _data.mongo.push({pid:_p[1],cpu:_p[9],pmem:_p[6],rss:_p[10],name:_p[12]});
  628. } else if(_p[0] == ppid) {
  629. _data.node = {pid:_p[0],cpu:_p[8],pmem:_p[5],rss:_p[9],name:_p[11]};
  630. }
  631. });
  632. for(room in rooms)
  633. if(room.search(_path) == 0) {
  634. io.sockets.in(room.substr(1, room.length)).emit('announcement', _data);
  635. PusherAPIsActivity({client:NPUSH_SERVER_STATUS_APIKEY}, 1, 0, 0, 0);
  636. }
  637. });
  638. } else { // mac
  639. var command = 'ps -eo pid,pcpu,pmem,rss,comm';
  640. //var command = 'top';
  641. require('child_process').exec(command, function(error, stdout, stderr) {
  642. var lines = stdout.split("\n");
  643. lines.forEach(function(_item,_i) {
  644. var _p = _item.replace( /[\s+\n\r]+/g,' ').split(' ');
  645. if(String(_p[4]).indexOf('mongod') > -1) {
  646. _data.mongo.push({pid:_p[0],cpu:_p[1],pmem:_p[2],rss:_p[3],name:_p[4]});
  647. } else if((parseInt(_p[0]) > 0 && PusherFindInArray(workersInstances ,_p[0]))
  648. || (_p[0] == '' && parseInt(_p[1]) > 0 && PusherFindInArray(workersInstances ,_p[1]))) {
  649. // we need get list of PIDs in cluster and get data for them
  650. if(_p[0] == '') {
  651. _data.node.push({pid:_p[1],cpu:_p[2],pmem:_p[3],rss:_p[4],name:_p[5]});
  652. } else {
  653. _data.node.push({pid:_p[0],cpu:_p[1],pmem:_p[2],rss:_p[3],name:_p[4]});
  654. }
  655. }
  656. });
  657. for(room in rooms)
  658. if(room.search(_path) == 0) {
  659. io.sockets.in(room.substr(1, room.length)).emit('announcement', _data);
  660. PusherAPIsActivity({client:NPUSH_SERVER_STATUS_APIKEY}, 1, 0, 0, 0);
  661. }
  662. });
  663. }
  664. });
  665. }
  666. /**
  667. * Listen for Master Cluster Messages
  668. * Send Respond for Master requests.
  669. *
  670. * @param object data as message from master process
  671. */
  672. function ModulePusherMessageHandler(data) {
  673. if(data.event == 'global-stats') {
  674. // all worker PIDs
  675. workersInstances = data.data.w;
  676. // data activity from master (all workers)
  677. activityGlobal = data.data.a;
  678. // data nicknames from master (all workers)
  679. nicknameGlobal = data.data.n;
  680. // global traffic
  681. allowGlobalTraffic = data.data.t.a;
  682. // send stats to scokets
  683. PusherAPIsActivityStats();
  684. } else if(data.event == 'send-activity') {
  685. // data actovity from worker to master
  686. process.send({
  687. event:'worker-activity', data:{a:activity,n:nicknames} });
  688. // some action after send stats to master
  689. for(socket in activity) {
  690. activity[socket].s.pm = activity[socket].s.m;
  691. activity[socket].s.dbrps = activity[socket].s.dbwps = activity[socket].s.dbups = 0;
  692. }
  693. }
  694. }
  695. /**
  696. * Cluster messages handler
  697. */
  698. process.on('message', ModulePusherMessageHandler);
  699. /*
  700. * Handle event for each socket. This 'connection' event function is called
  701. * when handshake proccess return true.
  702. *
  703. * Events:
  704. * - message
  705. * - message-read
  706. * - message boradcast rooms
  707. * - message broadcast app
  708. * - message broadcast channel
  709. * - public_activity_ms
  710. * - public_activity
  711. * - disconnect
  712. *
  713. */
  714. io.sockets.on('connection', function (socket) {
  715. // USER LOGIN AND ENVIRONMENT SETTINGS
  716. // SEND WELCOME MESSAGE
  717. io.sockets.socket(socket.id).emit('announcement', socket.handshake.client_wellcome_msg);
  718. // SET USER SOCKET PARAMETERS
  719. socket.api_key = socket.handshake.api_key; // THIS IS API KEY
  720. socket.channel = socket.handshake.channel;
  721. socket.client = socket.handshake.client_room; // THIS IS API KEY
  722. socket.path = socket.handshake.client_room + '/' + socket.handshake.channel + '/' + socket.handshake.user_room;
  723. socket.room = socket.handshake.user_room;
  724. socket.user_id = socket.handshake.user_id;
  725. socket.user_name = socket.handshake.user_name;
  726. // ADD USER TO LIST
  727. if(!nicknames[socket.handshake.client_room])
  728. nicknames[socket.handshake.client_room] = {};
  729. if(!activity[socket.handshake.client_room])
  730. activity[socket.handshake.client_room] = PusherAPIStatsRecordCreate(socket);
  731. if(!nicknames[socket.handshake.client_room][socket.handshake.channel])
  732. nicknames[socket.handshake.client_room][socket.handshake.channel] = {};
  733. if(!nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room])
  734. nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room] = {};
  735. nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room][socket.handshake.user_id] = socket.nickname = socket.handshake.user_name;
  736. // JOIN ROOM
  737. socket.join(socket.path);
  738. // set info in activity object - list will be send to watchers
  739. activity[socket.client].c.s = true;
  740. // update connected user in socket -> as is active-sockets
  741. activity[socket.client].n.as++;
  742. // USER MESSAGES
  743. socket.on('message', function (_msg) {
  744. if(!allowGlobalTraffic) return;
  745. // set path to room
  746. var _path = '/' + socket.handshake.client_room + '/' + socket.channel + '/' + socket.room + '/';
  747. // save message in db
  748. PusherUserMessageSave(_msg, _path, socket, function(_data) {
  749. // send message
  750. io.sockets.in(socket.path).emit('message', _data);
  751. });
  752. });
  753. socket.on('message-read', function (_msg) {
  754. PusherUserActivityUpdate(socket);
  755. PusherUserMessageRead(_msg, socket);
  756. });
  757. // BROADCAST MESSAGES
  758. socket.on('message boradcast rooms', function (_msg, fn) {
  759. if(!allowGlobalTraffic) return;
  760. var _path = '/' + socket.client + '/' + socket.channel + '/';
  761. // save message in db
  762. PusherUserMessageSave(_msg, _path, socket, function(_data) {
  763. // broadcast to app
  764. _data.dataSystem.type = 1;
  765. // get all rooms
  766. var rooms = io.sockets.manager.rooms;
  767. for(room in rooms)
  768. if(room.search(_path) == 0)
  769. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  770. });
  771. });
  772. socket.on('message broadcast app', function (_msg, fn) {
  773. if(!allowGlobalTraffic) return;
  774. var _path = '/' + socket.client + '/';
  775. // save message in db
  776. PusherUserMessageSave(_msg, _path, socket, function(_data) {
  777. // broadcast to app
  778. _data.dataSystem.type = 3;
  779. // get all rooms
  780. var rooms = io.sockets.manager.rooms;
  781. for(room in rooms)
  782. if(room.search(_path) == 0)
  783. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  784. });
  785. });
  786. socket.on('message broadcast channel', function (_channel, _msg, fn) {
  787. if(!allowGlobalTraffic) return;
  788. var _path = '/' + socket.client + '/' + _channel + '/';
  789. // save message in db
  790. PusherUserMessageSave(_msg, _path, socket, function(_data) {
  791. // broadcast to app
  792. _data.dataSystem.type = 2;
  793. // get all rooms
  794. var rooms = io.sockets.manager.rooms;
  795. for(room in rooms)
  796. if(room.search(_path) == 0)
  797. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  798. });
  799. });
  800. // READ TIME OF LAST ACTIVITY IN MS FROM DB AND SEND UNREAD MESSAGES
  801. socket.on('public_activity_ms', function (_period, fn) {
  802. if(!allowGlobalTraffic) return;
  803. var _search_time = ' { "user_id" : "' + socket.user_id + '", "rooms./' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : {"$exists": true} } ';
  804. _search = JSON.parse(_search_time);
  805. db.collection('act_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  806. if (!doc) return;
  807. var _time = new Date();
  808. socket.user_last_activity = _time.getTime() - _period;
  809. var _time_info = new Date(socket.user_last_activity*1);
  810. // send info
  811. io.sockets.socket(socket.id).emit('announcement', 'activity since ' + _time_info + ' on '
  812. + '/' + socket.client + '/' + socket.channel + '/' + socket.room + '/');
  813. // SEARCH FOR MESSAGES FOR ROOM
  814. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/' + socket.room + '/" } ';
  815. _search = JSON.parse(_search_msg);
  816. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  817. if (!doc) return;
  818. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  819. PusherAPIsActivity(socket, 1, 1, 0, 0);
  820. });
  821. // SEARCH FOR MESSAGES FOR CHANNEL
  822. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/" } ';
  823. _search = JSON.parse(_search_msg);
  824. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  825. if (!doc) return;
  826. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  827. PusherAPIsActivity(socket, 1, 1, 0, 0);
  828. });
  829. // SEARCH FOR MESSAGES FOR APP
  830. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/" } ';
  831. _search = JSON.parse(_search_msg);
  832. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  833. if (!doc) return;
  834. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  835. PusherAPIsActivity(socket, 1, 1, 0, 0);
  836. });
  837. });
  838. });
  839. // READ TIME OF LAST ACTIVITY FROM DB AND SEND UNREAD MESSAGES
  840. socket.on('public_activity', function (nick, fn) {
  841. if(!allowGlobalTraffic) return;
  842. var _search_time = ' { "user_id" : "' + socket.user_id + '", "rooms./' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : {"$exists": true} } ';
  843. search = JSON.parse(_search_time);
  844. db.collection('act_' + socket.handshake.client_room).find(search).forEach(function(err, doc) {
  845. if (!doc) return;
  846. socket.user_last_activity = doc['rooms']['/' + socket.client + '/' + socket.channel + '/' + socket.room + '/']['date'];
  847. var _time = new Date(socket.user_last_activity*1);
  848. // send info
  849. io.sockets.socket(socket.id).emit('announcement', 'last activity ' + _time + ' on '
  850. + '/' + socket.client + '/' + socket.channel + '/' + socket.room + '/');
  851. // SEARCH FOR MESSAGES FOR ROOM
  852. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/' + socket.room + '/" } ';
  853. _search = JSON.parse(_search_msg);
  854. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  855. if (!doc) return;
  856. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  857. PusherAPIsActivity(socket, 1, 1, 0, 0);
  858. });
  859. // SEARCH FOR MESSAGES FOR CHANNEL
  860. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/" } ';
  861. _search = JSON.parse(_search_msg);
  862. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  863. if (!doc) return;
  864. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  865. PusherAPIsActivity(socket, 1, 1, 0, 0);
  866. });
  867. // SEARCH FOR MESSAGES FOR APP
  868. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/" } ';
  869. _search = JSON.parse(_search_msg);
  870. db.collection('msg_' + socket.handshake.client_room).find(_search).forEach(function(err, doc) {
  871. if (!doc) return;
  872. io.sockets.socket(socket.id).emit('message', PusherMakeMessageFromDB(doc));
  873. PusherAPIsActivity(socket, 1, 1, 0, 0);
  874. });
  875. });
  876. });
  877. // SERVER CONTROLL COMMAND
  878. socket.on('system', function(data) {
  879. process.send({
  880. event:'system-command', data:data });
  881. });
  882. // DISCONNECT AND SAVE TIME OF EVENT IN DB
  883. socket.on('disconnect', function () {
  884. // delete user from list
  885. if (!socket.nickname) return;
  886. PusherUserActivityUpdate(socket);
  887. try {
  888. // delete user_id from array
  889. delete nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room][socket.user_id];
  890. // delete room space in array if no user exist
  891. if(Object.keys(nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room]).length == 0)
  892. delete nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room];
  893. // delete channe; space in array if no channel exist
  894. if(Object.keys(nicknames[socket.handshake.client_room][socket.handshake.channel]).length == 0)
  895. delete nicknames[socket.handshake.client_room][socket.handshake.channel];
  896. // delete channe; space in array if no channel exist
  897. if(Object.keys(nicknames[socket.handshake.client_room]).length == 0) {
  898. delete nicknames[socket.handshake.client_room];
  899. delete activity[socket.handshake.client_room];
  900. } else {
  901. // set info in activity object - list will be send to watchers
  902. activity[socket.client].c.s = true;
  903. // update connected user in socket -> as is active-sockets
  904. activity[socket.client].n.as--;
  905. }
  906. } catch(e) {
  907. console.log('error on disconnect');
  908. }
  909. });
  910. });
  911. /*******************************************************************************
  912. * POST REQUESTS
  913. * NEED OPTIMIZATION IN VERSION 3.0
  914. *
  915. * TO DO !!!!!!!!!!!!!!!!!!!!!!
  916. * - implement universal function to save/update for POST API INTERFACE
  917. *
  918. ******************************************************************************/
  919. function PusherSendMessageFromPOST(req, res, type, callback) {
  920. if(req.method == 'POST' && allowGlobalTraffic) {
  921. // DATA
  922. var body ='';
  923. var _time_server = new Date();
  924. req.on('data', function (data) {
  925. body += data;
  926. });
  927. req.on('end', function () {
  928. var _search_msg = ' { "key" : "' + req.params.k + '", "enabled" : "true" } ';
  929. _search = JSON.parse(_search_msg);
  930. db.collection('apis').find(_search).forEach(function(err, doc) {
  931. if (!doc) {
  932. res.send('AUTH_ERROR');
  933. return;
  934. } else {
  935. var _path = '';
  936. try {
  937. _msg_object = JSON.parse(body);
  938. }
  939. catch (e) {
  940. _msg_object = { data : body, event : 'message' }
  941. }
  942. try {
  943. _time_stamp = parseInt(req.params.t);
  944. } catch(e) {
  945. _time_stamp = req.params.t;
  946. }
  947. var data = {
  948. dataSystem : {
  949. client:req.params.k,
  950. user_id:req.params.suid,
  951. user_name:req.params.sun,
  952. room:req.params.r, // becarefull here
  953. channel:req.params.c, // becarefull here
  954. time:Math.floor(_time_server.getTime()),
  955. type:type, // becarefull here
  956. archive:0,
  957. msg_id:0,
  958. source:1
  959. },
  960. dataUser : _msg_object.data,
  961. event : _msg_object.event
  962. }
  963. if(req.params.k != '')
  964. _path = req.params.k;
  965. if(req.params.c != '')
  966. _path = _path + '/' + req.params.c; // becarefull here
  967. if(req.params.r != '')
  968. _path = _path + '/' + req.params.r // becarefull here
  969. db.collection('msg_'+req.params.k).save({
  970. "api_key": req.params.k,
  971. "room" : '/' + _path + '/',
  972. "user" : {
  973. "id" : req.params.suid,
  974. "name" : req.params.sun
  975. } ,
  976. "date": _time_server.getTime(),
  977. "date_string": _time_server.getTime().toString(),
  978. "message" : _msg_object,
  979. "client" : req.connection.remoteAddress + ':' + req.connection.remotePort,
  980. "source" : 1,
  981. "as" : 0
  982. }, function(err, obj) {
  983. data.dataSystem.msg_id = obj._id;
  984. PusherUserActivityUpdate(data.dataSystem);
  985. // update API Activity Stats
  986. PusherAPIsActivity({client:req.params.k}, 1, 1, 1, 0);
  987. callback.call(this, true, data, _path);
  988. });
  989. }
  990. });
  991. });
  992. } else {
  993. res.send('TRAFFIC_STOPPED');
  994. return;
  995. }
  996. }
  997. // POST FOR APP/CHANNEL/ROOM
  998. app.post('/api/channel/:c/room/:r/api/:k/version/:v/t/:t/suid/:suid/suname/:sun', function (req, res) {
  999. // :c - destination channel
  1000. // :r - destination room
  1001. // :k - api key
  1002. // :v - api version
  1003. // :t - time stamp
  1004. // :suid - sender user id
  1005. // :sun - sender user name
  1006. // EXAMPLE:
  1007. // curl -H "Content-Type: application/post"
  1008. // -d '{"object":"helloworld"}'
  1009. // "http://push.vm.newicon.net:80/api/channel/ch1/room/room1/api/ab3245cbeaf456244abcdfa/version/2.0/t/234324/suid/1/suname/me"
  1010. PusherSendMessageFromPOST(req, res, 0, function(status, data, path) {
  1011. if(status) {
  1012. if(req.params.r != '') {
  1013. io.sockets.in(path).emit('message', data);
  1014. }
  1015. res.send('OK');
  1016. } else {
  1017. res.send('AUTH_ERROR');
  1018. }
  1019. });
  1020. });
  1021. // POST FOR /APP/CHANNEL
  1022. app.post('/api/channel/:c/api/:k/version/:v/t/:t/suid/:suid/suname/:sun', function (req, res) {
  1023. // :c - destination channel
  1024. // :r - destination room
  1025. // :k - api key
  1026. // :v - api version
  1027. // :t - time stamp
  1028. // :suid - sender user id
  1029. // :sun - sender user name
  1030. // EXAMPLE:
  1031. // curl -H "Content-Type: application/post"
  1032. // -d '{"object":"helloworld"}'
  1033. // "http://push.vm.newicon.net:80/api/channel/ch1/api/ab3245cbeaf456244abcdfa/version/2.0/t/234324/suid/1/suname/me"
  1034. if(req.method == 'POST' && allowGlobalTraffic) {
  1035. // DATA
  1036. var body ='';
  1037. var _time_server = new Date();
  1038. req.on('data', function (data) {
  1039. body += data;
  1040. });
  1041. req.on('end', function () {
  1042. var _search_msg = ' { "key" : "' + req.params.k + '", "enabled" : "true" } ';
  1043. _search = JSON.parse(_search_msg);
  1044. db.collection('apis').find(_search).forEach(function(err, doc) {
  1045. if (!doc) {
  1046. res.send('AUTH_ERROR');
  1047. return;
  1048. } else {
  1049. var rooms = io.sockets.manager.rooms;
  1050. var _path = '';
  1051. try {
  1052. _msg_object = JSON.parse(body);
  1053. }
  1054. catch (e) {
  1055. _msg_object = { data : body, event : 'message' }
  1056. }
  1057. try {
  1058. _time_stamp = parseInt(req.params.t);
  1059. } catch(e) {
  1060. _time_stamp = req.params.t;
  1061. }
  1062. var data = {
  1063. dataSystem : {
  1064. client:req.params.k,
  1065. user_id:req.params.suid,
  1066. user_name:req.params.sun,
  1067. room:'',
  1068. channel:req.params.c,
  1069. time:Math.floor(_time_server.getTime()),
  1070. type:2,
  1071. archive:0,
  1072. msg_id:0,
  1073. source:1
  1074. },
  1075. dataUser : _msg_object.data,
  1076. event : _msg_object.event
  1077. }
  1078. if(req.params.k != '')
  1079. _path = req.params.k;
  1080. if(req.params.c != '')
  1081. _path = _path + '/' + req.params.c;
  1082. db.collection('msg_'+req.params.k).save({
  1083. "api_key": req.params.k,
  1084. "room" : '/' + _path + '/',
  1085. "user" : {
  1086. "id" : req.params.suid,
  1087. "name" : req.params.sun
  1088. } ,
  1089. "date": _time_server.getTime(),
  1090. "date_string": _time_server.getTime().toString(),
  1091. "message" : _msg_object,
  1092. "client" : req.connection.remoteAddress + ':' + req.connection.remotePort,
  1093. "source" : 1,
  1094. "as" : 0
  1095. }, function(err, obj) {
  1096. data.dataSystem.msg_id = obj._id;
  1097. PusherUserActivityUpdate(data.dataSystem);
  1098. if(req.params.c != '') {
  1099. for(room in rooms) {
  1100. if(room.search('/'+_path + '/') == 0) {
  1101. io.sockets.in(room.substr(1, room.length)).emit('message', data);
  1102. }
  1103. }
  1104. }
  1105. // update API Activity Stats
  1106. PusherAPIsActivity({client:req.params.k}, 1, 1, 1, 0);
  1107. res.send('OK');
  1108. return;
  1109. });
  1110. }
  1111. });
  1112. });
  1113. } else {
  1114. res.send('TRAFFIC_STOPPED');
  1115. return;
  1116. }
  1117. });
  1118. // POST FOR APP/
  1119. app.post('/api/api/:k/version/:v/t/:t/suid/:suid/suname/:sun', function (req, res) {
  1120. // :c - destination channel
  1121. // :r - destination room
  1122. // :k - api key
  1123. // :v - api version
  1124. // :t - time stamp
  1125. // :suid - sender user id
  1126. // :sun - sender user name
  1127. // EXAMPLE:
  1128. // curl -H "Content-Type: application/post"
  1129. // -d '{"object":"helloworld"}'
  1130. // "http://push.vm.newicon.net:80/api/api/ab3245cbeaf456244abcdfa/version/2.0/t/234324/suid/1/suname/me"
  1131. if(req.method == 'POST' && allowGlobalTraffic) {
  1132. // DATA
  1133. var body ='';
  1134. var _time_server = new Date();
  1135. req.on('data', function (data) {
  1136. body += data;
  1137. });
  1138. req.on('end', function () {
  1139. var _search_msg = ' { "key" : "' + req.params.k + '", "enabled" : "true" } ';
  1140. _search = JSON.parse(_search_msg);
  1141. db.collection('apis').find(_search).forEach(function(err, doc) {
  1142. if (!doc) {
  1143. res.send('AUTH_ERROR');
  1144. return;
  1145. } else {
  1146. var rooms = io.sockets.manager.rooms;
  1147. var _path = '';
  1148. try {
  1149. _msg_object = JSON.parse(body);
  1150. }
  1151. catch (e) {
  1152. _msg_object = { data : body, event : 'message' }
  1153. }
  1154. try {
  1155. _time_stamp = parseInt(req.params.t);
  1156. } catch(e) {
  1157. _time_stamp = req.params.t;
  1158. }
  1159. var data = {
  1160. dataSystem : {
  1161. client:req.params.k,
  1162. user_id:req.params.suid,
  1163. user_name:req.params.sun,
  1164. room:'',
  1165. channel:'',
  1166. time:Math.floor(_time_server.getTime()),
  1167. type:3,
  1168. archive:0,
  1169. msg_id:0,
  1170. source:1
  1171. },
  1172. dataUser : _msg_object.data,
  1173. event : _msg_object.event
  1174. }
  1175. if(req.params.k != '')
  1176. _path = req.params.k;
  1177. db.collection('msg_'+req.params.k).save({
  1178. "api_key": req.params.k,
  1179. "room" : '/' + _path + '/',
  1180. "user" : {
  1181. "id" : req.params.suid,
  1182. "name" : req.params.sun
  1183. } ,
  1184. "date": _time_server.getTime(),
  1185. "date_string": _time_server.getTime().toString(),
  1186. "message" : _msg_object,
  1187. "client" : req.connection.remoteAddress + ':' + req.connection.remotePort,
  1188. "source" : 1,
  1189. "as" : 0
  1190. }, function(err, obj) {
  1191. data.dataSystem.msg_id = obj._id;
  1192. PusherUserActivityUpdate(data.dataSystem);
  1193. if(req.params.k != '') {
  1194. for(room in rooms) {
  1195. if(room.search('/'+_path + '/') == 0)
  1196. {
  1197. io.sockets.in(room.substr(1, room.length)).emit('message', data);
  1198. }
  1199. }
  1200. }
  1201. // update API Activity Stats
  1202. PusherAPIsActivity({client:req.params.k}, 1, 1, 1, 0);
  1203. res.send('OK');
  1204. return;
  1205. });
  1206. }
  1207. });
  1208. });
  1209. } else {
  1210. res.send('TRAFFIC_STOPPED');
  1211. return;
  1212. }
  1213. });
  1214. /**
  1215. * Helpers function
  1216. *
  1217. * PusherRoundNumber
  1218. * @param float num
  1219. * @param int decimal
  1220. */
  1221. function PusherRoundNumber(num, dec) {
  1222. return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
  1223. }
  1224. function PusherFindInArray(_array, _value) {
  1225. for(_x in _array) {
  1226. if(_value == _array[_x]) return true;
  1227. }
  1228. return false;
  1229. }
  1230. // end of cluster worker
  1231. }