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