PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/documents/npush-versions/v1/newicon-s-v1.io.js

https://bitbucket.org/newicon/npush-server
JavaScript | 590 lines | 401 code | 129 blank | 60 comment | 32 complexity | 58793073b12c0966fa87382b930b7612 MD5 | raw file
  1. /*! NEWICON PUSHER build:0.0.1, development. Copyright(c) 2012 NEWICON LTD */
  2. /**
  3. * Krzysztof Stasiak
  4. * newicon-s.io
  5. * Copyright(c) 2012 NEWICON LTD <newicon@newicon.net>
  6. * GPL Licensed
  7. */
  8. /**
  9. * Module dependencies.
  10. */
  11. var express = require('express')
  12. , stylus = require('stylus')
  13. , nib = require('nib')
  14. , sio = require('socket.io')
  15. , databaseUrl = "ni_sockets" //'username:password@example.com:port/mydb'
  16. , collections = ["messages_public", "messages_private", "accounts"]
  17. , db = require("mongojs").connect(databaseUrl, collections)
  18. , port = process.argv[2]
  19. , qs = require('querystring');
  20. var logToConsole = 1;
  21. /**
  22. * App.
  23. */
  24. var app = express.createServer();
  25. /**
  26. * App configuration.
  27. */
  28. app.configure(function () {
  29. app.use(stylus.middleware({
  30. src: __dirname + '/public',
  31. compile: compile
  32. }));
  33. app.use(express.static(__dirname + '/public'));
  34. app.set('views', __dirname);
  35. app.set('view engine', 'jade');
  36. function compile (str, path) {
  37. return stylus(str)
  38. .set('filename', path)
  39. .use(nib());
  40. };
  41. });
  42. /**
  43. * App routes.
  44. */
  45. app.get('/', function (req, res) {
  46. res.render('index', {
  47. layout: false
  48. });
  49. });
  50. /**
  51. * App listen.
  52. */
  53. app.listen(port, function () {
  54. var addr = app.address();
  55. console.log(' app listening on http://' + addr.address + ':' + addr.port);
  56. });
  57. /**
  58. * Socket.IO server (single process only)
  59. */
  60. var io = sio.listen(app)
  61. , nicknames = new Object();
  62. // socket.io settings
  63. io.configure('production', function(){
  64. io.enable('browser client minification'); // send minified client
  65. io.enable('browser client etag'); // apply etag caching logic based on version number
  66. io.enable('browser client gzip'); // gzip the file
  67. io.set('log level', 1); // reduce logging
  68. io.set('transports', [ // enable all transports (optional if you want flashsocket)
  69. 'websocket'
  70. , 'flashsocket'
  71. , 'htmlfile'
  72. , 'xhr-polling'
  73. , 'jsonp-polling'
  74. ]);
  75. });
  76. io.configure('development', function(){
  77. io.set('transports', ['websocket']);
  78. });
  79. nicknames = {};
  80. // AUTHORIZATION
  81. io.configure(function (){
  82. io.set('authorization', function (handshakeData, callback) {
  83. var _search_msg = ' { "api_key" : "' + handshakeData.query.k + '" } ';
  84. _search = JSON.parse(_search_msg);
  85. db.accounts.find(_search).forEach(function(err, doc) {
  86. if (!doc) {
  87. callback(null, false);
  88. }
  89. else
  90. {
  91. handshakeData.client_room = doc['client_room'];
  92. handshakeData.client_wellcome_msg = doc['wellcome_message'];
  93. handshakeData.address = handshakeData.address.address;
  94. handshakeData.port = handshakeData.address.port;
  95. handshakeData.api_key = handshakeData.query.k;
  96. handshakeData.channel = handshakeData.query.c;
  97. handshakeData.user_id = handshakeData.query.id;
  98. handshakeData.user_name = handshakeData.query.name;
  99. handshakeData.user_room = handshakeData.query.room;
  100. if(!nicknames[handshakeData.client_room]) {
  101. nicknames[handshakeData.client_room] = {};
  102. }
  103. if(!nicknames[handshakeData.client_room][handshakeData.channel]) {
  104. nicknames[handshakeData.client_room][handshakeData.channel] = {};
  105. }
  106. if(!nicknames[handshakeData.client_room][handshakeData.channel][handshakeData.user_room]) {
  107. nicknames[handshakeData.client_room][handshakeData.channel][handshakeData.user_room] = {};
  108. }
  109. callback(null, true);
  110. }
  111. });
  112. });
  113. });
  114. // SOCKETS AND EVENTS
  115. function convert(name, value)
  116. {
  117. var doc = {};
  118. doc[name] = value;
  119. return doc;
  120. }
  121. // make a data object from the socket object
  122. function makeMsgData(msg, socket){
  123. var _time = new Date();
  124. return {
  125. user_id:socket.user_id,
  126. user_name:socket.nickname,
  127. msg:msg,
  128. room:socket.room,
  129. channel:socket.channel,
  130. time:_time.getTime()
  131. };
  132. }
  133. // make a data object from the db
  134. // also see makeMsgData
  135. function makeMsgDataDb(doc){
  136. return {
  137. nickname:doc['user']['name'],
  138. msg:doc['message'],
  139. room:doc['room'],
  140. channel:'',
  141. time:doc['date']
  142. };
  143. }
  144. io.sockets.on('connection', function (socket) {
  145. // USER LOGIN AND ENVIRONMENT SETTINGS
  146. io.sockets.socket(socket.id).emit('announcement', socket.handshake.client_wellcome_msg);
  147. nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room][socket.handshake.user_id] = socket.nickname = socket.handshake.user_name;
  148. socket.api_key = socket.handshake.api_key;
  149. socket.channel = socket.handshake.channel;
  150. socket.client = socket.handshake.client_room;
  151. socket.path = socket.handshake.client_room + '/' + socket.handshake.channel + '/' + socket.handshake.user_room;
  152. socket.room = socket.handshake.user_room;
  153. socket.user_id = socket.handshake.user_id;
  154. socket.user_name = socket.handshake.user_name;
  155. socket.join(socket.path);
  156. io.sockets.in(socket.path).emit('announcement', socket.handshake.user_name + ' connected in room ' + socket.path);
  157. // SEND NEW USER LIST FOR USERS IN ROOM
  158. io.sockets.in(socket.path).emit('usersroom', nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room]);
  159. // SEND NEW USER LIST FOR USERS IN APP
  160. io.sockets.emit('usersapp', nicknames[socket.handshake.client_room]);
  161. // SEND NEW USER LIST FOR USERS IN ROOMS IN CHANNEL
  162. var rooms = io.sockets.manager.rooms;
  163. var _path = '/' + socket.client + '/' + socket.channel + '/';
  164. for(room in rooms) {
  165. if(room.search(_path) == 0)
  166. {
  167. io.sockets.in(room.substr(1, room.length)).emit('userschannel', nicknames[socket.handshake.client_room][socket.handshake.channel]);
  168. }
  169. }
  170. // EVENTS START
  171. // USERS MESSAGES
  172. socket.on('message', function (msg) {
  173. var _data = makeMsgData(msg, socket);
  174. db.messages_public.save({
  175. "api_key": socket.api_key,
  176. "room" : '/' + socket.handshake.client_room + '/' + socket.channel + '/' + socket.room + '/',
  177. "user" : {
  178. "id" : socket.user_id,
  179. "name" : socket.user_name
  180. } ,
  181. "date": _data.time,
  182. "message" : msg,
  183. "client" : socket.handshake.address + ':' + socket.handshake.port
  184. });
  185. io.sockets.in(socket.path).emit('message', _data);
  186. });
  187. // BROADCAST MESSAGES
  188. socket.on('message boradcast rooms', function (msg, fn) {
  189. var _data = makeMsgData(msg, socket);
  190. var rooms = io.sockets.manager.rooms;
  191. var _path = '/' + socket.client + '/' + socket.channel + '/';
  192. db.messages_public.save({
  193. "api_key": socket.api_key,
  194. "room" : _path,
  195. "user" : {
  196. "id" : socket.user_id,
  197. "name" : socket.user_name
  198. } ,
  199. "date": _data.time,
  200. "message" : msg,
  201. "client" : socket.handshake.address + ':' + socket.handshake.port,
  202. });
  203. for(room in rooms) {
  204. if(room.search(_path) == 0) {
  205. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  206. }
  207. }
  208. });
  209. socket.on('message broadcast app', function (msg, fn) {
  210. var _data = makeMsgData(msg, socket);
  211. var rooms = io.sockets.manager.rooms;
  212. var _path = '/' + socket.client + '/';
  213. var _time = new Date();
  214. db.messages_public.save({
  215. "api_key": socket.api_key,
  216. "room" : _path,
  217. "user" : {
  218. "id" : socket.user_id,
  219. "name" : socket.user_name
  220. } ,
  221. "date": _data.time,
  222. "message" : msg,
  223. "client" : socket.handshake.address + ':' + socket.handshake.port,
  224. });
  225. for(room in rooms) {
  226. if(room.search(_path) == 0)
  227. {
  228. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  229. }
  230. }
  231. });
  232. socket.on('message broadcast channel', function (channel, msg, fn) {
  233. var _data = makeMsgData(msg, socket);
  234. var rooms = io.sockets.manager.rooms;
  235. var _path = '/' + socket.client + '/' + channel + '/';
  236. var _time = new Date();
  237. db.messages_public.save({
  238. "api_key": socket.api_key,
  239. "room" : _path,
  240. "user" : {
  241. "id" : socket.user_id,
  242. "name" : socket.user_name
  243. } ,
  244. "date": _data.time,
  245. "message" : msg,
  246. "client" : socket.handshake.address + ':' + socket.handshake.port,
  247. });
  248. for(room in rooms) {
  249. if(room.search(_path) == 0)
  250. {
  251. io.sockets.in(room.substr(1, room.length)).emit('message', _data);
  252. }
  253. }
  254. });
  255. // READ TIME OF LAST ACTIVITY IN MS FROM DB AND SEND UNREAD MESSAGES
  256. socket.on('public_activity_ms', function (_period, fn) {
  257. var _search_time = ' { "users_activity.' + socket.user_id + './' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : {"$exists": true}, "api_key" : "' + socket.api_key + '" } ';
  258. _search = JSON.parse(_search_time);
  259. db.accounts.find(_search).forEach(function(err, doc) {
  260. if (!doc) {
  261. return;
  262. }
  263. else
  264. {
  265. var _time = new Date();
  266. socket.user_last_activity = _time.getTime() - _period;
  267. var _time_info = new Date(socket.user_last_activity*1);
  268. io.sockets.socket(socket.id).emit('announcement', 'last activity ' + _time_info);
  269. // SEARCH FOR MESSAGES FOR ROOM
  270. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/' + socket.room + '/" } ';
  271. _search = JSON.parse(_search_msg);
  272. db.messages_public.find(_search).forEach(function(err, doc) {
  273. if (!doc) {
  274. return;
  275. }
  276. else
  277. {
  278. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  279. }
  280. });
  281. // SEARCH FOR MESSAGES FOR CHANNEL
  282. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/" } ';
  283. _search = JSON.parse(_search_msg);
  284. db.messages_public.find(_search).forEach(function(err, doc) {
  285. if (!doc) {
  286. return;
  287. }
  288. else
  289. {
  290. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  291. }
  292. });
  293. // SEARCH FOR MESSAGES FOR APP
  294. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/" } ';
  295. _search = JSON.parse(_search_msg);
  296. db.messages_public.find(_search).forEach(function(err, doc) {
  297. if (!doc) {
  298. return;
  299. }
  300. else
  301. {
  302. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  303. }
  304. });
  305. }
  306. });
  307. });
  308. // READ TIME OF LAST ACTIVITY FROM DB AND SEND UNREAD MESSAGES
  309. socket.on('public_activity', function (nick, fn) {
  310. var _search_time = ' { "users_activity.' + socket.user_id + './' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : {"$exists": true}, "api_key" : "' + socket.api_key + '" } ';
  311. _search = JSON.parse(_search_time);
  312. db.accounts.find(_search).forEach(function(err, doc) {
  313. if (!doc) {
  314. return;
  315. }
  316. else
  317. {
  318. socket.user_last_activity = doc['users_activity'][socket.user_id]['/' + socket.client + '/' + socket.channel + '/' + socket.room + '/']['date'];
  319. var _time = new Date(socket.user_last_activity*1);
  320. io.sockets.socket(socket.id).emit('announcement', 'last activity ' + _time);
  321. // SEARCH FOR MESSAGES FOR ROOM
  322. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/' + socket.room + '/" } ';
  323. _search = JSON.parse(_search_msg);
  324. db.messages_public.find(_search).forEach(function(err, doc) {
  325. if (!doc) {
  326. return;
  327. }
  328. else
  329. {
  330. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  331. }
  332. });
  333. // SEARCH FOR MESSAGES FOR CHANNEL
  334. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/' + socket.channel + '/" } ';
  335. _search = JSON.parse(_search_msg);
  336. db.messages_public.find(_search).forEach(function(err, doc) {
  337. if (!doc) {
  338. return;
  339. }
  340. else
  341. {
  342. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  343. }
  344. });
  345. // SEARCH FOR MESSAGES FOR APP
  346. var _search_msg = ' { "date" : { "$gt" : ' + socket.user_last_activity + ' }, "room" : "/' + socket.client + '/" } ';
  347. _search = JSON.parse(_search_msg);
  348. db.messages_public.find(_search).forEach(function(err, doc) {
  349. if (!doc) {
  350. return;
  351. }
  352. else
  353. {
  354. io.sockets.socket(socket.id).emit('message', makeMsgDataDb(doc));
  355. }
  356. });
  357. }
  358. });
  359. });
  360. // DISCONNECT AND SAVE TIME OF EVENT IN DB
  361. socket.on('disconnect', function () {
  362. if (!socket.nickname) return;
  363. var _time = new Date();
  364. var _date = "users_activity." + socket.user_id + ".date";
  365. var _room = "users_activity." + socket.user_id + ".room";
  366. var _date = convert(_date, {
  367. $exists: true
  368. });
  369. var _update_time = convert(_date, _time.getTime());
  370. var _update_room = convert(_room, socket.room);
  371. var _search_json = '{ "api_key" : "' + socket.api_key + '" }';
  372. var _update_json = '{ "users_activity.' + socket.user_id + '.date" : "' + _time.getTime() + '", \n\
  373. "users_activity.' + socket.user_id + './' + socket.client + '/' + socket.channel + '/' + socket.room + '/.date" : "' + _time.getTime() + '" } '; //, \n\
  374. _search = JSON.parse(_search_json);
  375. _update = JSON.parse(_update_json);
  376. db.accounts.update(_search, {
  377. $set : _update
  378. } , {
  379. upsert : true
  380. } );
  381. delete nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room][socket.user_id];
  382. io.sockets.in(socket.path).emit('announcement', socket.nickname + ' disconnected');
  383. //io.sockets.in(socket.path).emit('nicknames', nicknames[socket.handshake.client_room ]);
  384. io.sockets.in(socket.path).emit('usersroom', nicknames[socket.handshake.client_room][socket.handshake.channel][socket.handshake.user_room]);
  385. io.sockets.emit('usersapp', nicknames[socket.handshake.client_room]);
  386. // SEND NEW USER LIST FOR USERS IN ROOMS IN CHANNEL
  387. var rooms = io.sockets.manager.rooms;
  388. var _path = '/' + socket.client + '/' + socket.channel + '/';
  389. for(room in rooms) {
  390. if(room.search(_path) == 0)
  391. {
  392. io.sockets.in(room.substr(1, room.length)).emit('userschannel', nicknames[socket.handshake.client_room][socket.handshake.channel]);
  393. }
  394. }
  395. });
  396. });
  397. app.post('/api/channel/:c/room/:r/api/:k/t/:t/suid/:suid/suname/:sun', function (req, res) {
  398. // :c - destination channel
  399. // :r - destination room
  400. // :k - api key
  401. // :t - time stamp
  402. // :suid - sender user id
  403. // :sun - sender user name
  404. // EXAMPLE:
  405. // curl -H "Content-Type: application/post"
  406. // -d '{"object":"helloworld"}'
  407. // "http://push.vm.newicon.net:80/api/channel/ch1/room/room1/api/ab3245cbeaf456244abcdfa/t/234324/suid/1/suname/me"
  408. if(req.method == 'POST') {
  409. // DATA
  410. var body ='';
  411. var _time_server = new Date();
  412. req.on('data', function (data) {
  413. body += data;
  414. });
  415. req.on('end', function () {
  416. var _search_msg = ' { "api_key" : "' + req.params.k + '" } ';
  417. _search = JSON.parse(_search_msg);
  418. db.accounts.find(_search).forEach(function(err, doc) {
  419. if (!doc) {
  420. res.send('AUTH_ERROR');
  421. return;
  422. } else {
  423. var _path = doc['client_room'] + '/' + req.params.c + '/' + req.params.r;
  424. try {
  425. _msg_object = JSON.parse(body);
  426. }
  427. catch (e) {
  428. _msg_object = body
  429. }
  430. try {
  431. _time_stamp = parseInt(req.params.t);
  432. } catch(e) {
  433. _time_stamp = req.params.t;
  434. }
  435. var data = {
  436. user_id:req.params.suid,
  437. user_name:req.params.sun,
  438. msg: _msg_object,
  439. room:req.params.sur,
  440. channel:req.params.suc,
  441. time:_time_server.getTime()
  442. }
  443. db.messages_public.save({
  444. "api_key": req.params.k,
  445. "room" : '/' + doc['client_room']+ '/' + req.params.c + '/' + req.params.r + '/',
  446. "user" : {
  447. "id" : req.params.suid,
  448. "name" : req.params.sun
  449. } ,
  450. "date": _time_server.getTime(),
  451. "message" : _msg_object,
  452. "client" : req.connection.remoteAddress + ':' + req.connection.remotePort
  453. });
  454. io.sockets.in(_path).emit('message', data);
  455. res.send('OK');
  456. return;
  457. }
  458. });
  459. });
  460. }
  461. });