Refactor server for flexibility.
Esse commit está contido em:
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Ajax IM</title>
|
<title>Ajax IM</title>
|
||||||
<script src="js/jquery-1.11.0.js" type="text/javascript"></script>
|
<script src="js/jquery-1.11.1.js" type="text/javascript"></script>
|
||||||
<script src="js/md5.js" type="text/javascript"></script>
|
<script src="js/md5.js" type="text/javascript"></script>
|
||||||
<script src="js/store.js" type="text/javascript"></script>
|
<script src="js/store.js" type="text/javascript"></script>
|
||||||
<script src="js/dateformat.js" type="text/javascript"></script>
|
<script src="js/dateformat.js" type="text/javascript"></script>
|
||||||
|
|||||||
+50
-48
@@ -55,7 +55,7 @@ AjaxIM = function(options, actions) {
|
|||||||
}, actions);
|
}, actions);
|
||||||
|
|
||||||
if (!store.get('sessionid')) {
|
if (!store.get('sessionid')) {
|
||||||
store.set('sessionid', uid(40));
|
store.set('sessionid', AjaxIM.uid(40));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Socket.IO is available, create a socket
|
// If Socket.IO is available, create a socket
|
||||||
@@ -63,24 +63,26 @@ AjaxIM = function(options, actions) {
|
|||||||
$.getScript(this.settings.pollServer+'/socket.io/socket.io.js', function(){
|
$.getScript(this.settings.pollServer+'/socket.io/socket.io.js', function(){
|
||||||
self.socket = io(self.settings.pollServer);
|
self.socket = io(self.settings.pollServer);
|
||||||
self.socket.on('client', function(event) {
|
self.socket.on('client', function(event) {
|
||||||
event = $.extend(true, {}, event);
|
event = $.extend(true, {}, event);
|
||||||
self.dispatchEvent(event);
|
self.dispatchEvent(event);
|
||||||
});
|
});
|
||||||
var event = {type: 'hello', from: store.get('user'), sessionID: store.get('sessionid')};
|
var event = {type: 'hello', from: store.get('user')};
|
||||||
self.sendEvent(event);
|
self.sendEvent(event, function() {}, function() {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// We load the theme dynamically based on the passed
|
// We load the theme dynamically based on the passed
|
||||||
// settings. If the theme is set to false, we assume
|
// settings. If the theme is set to false, we assume
|
||||||
// that the user is going to load it himself.
|
// that the user is going to load it himself.
|
||||||
this.themeLoaded = false;
|
this.themeLoaded = false;
|
||||||
if(this.settings.theme) {
|
if (this.settings.theme) {
|
||||||
if(typeof document.createStyleSheet == 'function')
|
if(typeof document.createStyleSheet == 'function') {
|
||||||
document.createStyleSheet(this.settings.theme + '/theme.css');
|
document.createStyleSheet(this.settings.theme + '/theme.css');
|
||||||
else
|
} else {
|
||||||
$('body').append('<link rel="stylesheet" href="' +
|
$('body').append('<link rel="stylesheet" href="' +
|
||||||
this.settings.theme + '/theme.css" />');
|
this.settings.theme + '/theme.css" />');
|
||||||
$('<div>').appendTo('body').load(this.settings.theme + '/theme.html #imjs-bar, .imjs-tooltip',
|
}
|
||||||
|
$('<div>').appendTo('body').load(this.settings.theme +
|
||||||
|
'/theme.html #imjs-bar, .imjs-tooltip',
|
||||||
function() {
|
function() {
|
||||||
self.themeLoaded = true;
|
self.themeLoaded = true;
|
||||||
self.setup();
|
self.setup();
|
||||||
@@ -115,7 +117,6 @@ AjaxIM = function(options, actions) {
|
|||||||
var obj = $(this);
|
var obj = $(this);
|
||||||
self.send(obj.parents('.imjs-chatbox').data('username'), obj.val());
|
self.send(obj.parents('.imjs-chatbox').data('username'), obj.val());
|
||||||
}
|
}
|
||||||
|
|
||||||
var obj = $(this);
|
var obj = $(this);
|
||||||
obj.val('');
|
obj.val('');
|
||||||
obj.height(obj.data('height'));
|
obj.height(obj.data('height'));
|
||||||
@@ -371,7 +372,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
var msglog = this.chats[activeTab].find('.imjs-msglog');
|
var msglog = this.chats[activeTab].find('.imjs-msglog');
|
||||||
msglog[0].scrollTop = msglog[0].scrollHeight;
|
msglog[0].scrollTop = msglog[0].scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set username in Friends list
|
// Set username in Friends list
|
||||||
var header = $('#imjs-friends-panel .imjs-header');
|
var header = $('#imjs-friends-panel .imjs-header');
|
||||||
header.html(header.html().replace('{username}', this.username));
|
header.html(header.html().replace('{username}', this.username));
|
||||||
@@ -409,7 +410,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
self.request(
|
self.request(
|
||||||
this.actions.listen,
|
this.actions.listen,
|
||||||
'GET',
|
'GET',
|
||||||
{},
|
{type: 'hello', from: store.get('user'), sessionid: store.get('sessionid')},
|
||||||
function(event) {
|
function(event) {
|
||||||
if($.isArray(event)) {
|
if($.isArray(event)) {
|
||||||
$.each(event, function(key, event) {
|
$.each(event, function(key, event) {
|
||||||
@@ -471,7 +472,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onMessage: function(event) {
|
onMessage: function(event) {
|
||||||
this.incoming(event.from, event.body);
|
this.incoming(event.from, event.body);
|
||||||
},
|
},
|
||||||
|
|
||||||
onStatus: function(event) {
|
onStatus: function(event) {
|
||||||
@@ -909,7 +910,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
if($('#imjs-friends').hasClass('imjs-selected'))
|
if($('#imjs-friends').hasClass('imjs-selected'))
|
||||||
this.activateTab($('#imjs-friends'));
|
this.activateTab($('#imjs-friends'));
|
||||||
},
|
},
|
||||||
|
|
||||||
_showReconnect: function() {
|
_showReconnect: function() {
|
||||||
$('#imjs-reconnect').show();
|
$('#imjs-reconnect').show();
|
||||||
},
|
},
|
||||||
@@ -969,6 +970,10 @@ $.extend(AjaxIM.prototype, {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
signOff: function() {
|
||||||
|
this.status('offline', '');
|
||||||
|
},
|
||||||
|
|
||||||
// === {{{AjaxIM.}}}**{{{status(s, message)}}}** ===
|
// === {{{AjaxIM.}}}**{{{status(s, message)}}}** ===
|
||||||
//
|
//
|
||||||
// Sets the user's status and status message. It is possible to not
|
// Sets the user's status and status message. It is possible to not
|
||||||
@@ -1001,7 +1006,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
self.offline = true;
|
self.offline = true;
|
||||||
$('.imjs-input').attr('disabled', true);
|
$('.imjs-input').attr('disabled', true);
|
||||||
|
|
||||||
var event = {type: 'signoff'};
|
var event = {type: 'signoff', message: message};
|
||||||
this.sendEvent(event, function(result) {
|
this.sendEvent(event, function(result) {
|
||||||
if(result.type == 'success')
|
if(result.type == 'success')
|
||||||
$(self).trigger('changeStatusSuccessful', [value, null]);
|
$(self).trigger('changeStatusSuccessful', [value, null]);
|
||||||
@@ -1302,8 +1307,8 @@ $.extend(AjaxIM.prototype, {
|
|||||||
|
|
||||||
var tab_pos = tab.position();
|
var tab_pos = tab.position();
|
||||||
if(tab_pos.top >= $('#imjs-bar').height() ||
|
if(tab_pos.top >= $('#imjs-bar').height() ||
|
||||||
tab_pos.left < 0 ||
|
tab_pos.left < 0 ||
|
||||||
tab_pos.right > $(document).width()) {
|
tab_pos.right > $(document).width()) {
|
||||||
$('.imjs-scroll').css('display', '');
|
$('.imjs-scroll').css('display', '');
|
||||||
tab.css('display', 'none');
|
tab.css('display', 'none');
|
||||||
needScrollers = true;
|
needScrollers = true;
|
||||||
@@ -1356,6 +1361,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
sendEvent: function(event, successFunc, failureFunc) {
|
sendEvent: function(event, successFunc, failureFunc) {
|
||||||
|
event.sessionid = store.get('sessionid');
|
||||||
event.id = this.eventId++;
|
event.id = this.eventId++;
|
||||||
var evt = $.extend({}, event);
|
var evt = $.extend({}, event);
|
||||||
evt['_status'] = {
|
evt['_status'] = {
|
||||||
@@ -1402,19 +1408,19 @@ $.extend(AjaxIM.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
dispatchEvent: function(event) {
|
dispatchEvent: function(event) {
|
||||||
if (event.id && this.unconfirmedEvents[event.id]) {
|
if (event.id && this.unconfirmedEvents[event.id]) {
|
||||||
event['_status'] = $.extend({}, this.unconfirmedEvents[event.id]['_status'], event['_status']);
|
event['_status'] = $.extend({}, this.unconfirmedEvents[event.id]['_status'], event['_status']);
|
||||||
delete this.unconfirmedEvents[event.id];
|
delete this.unconfirmedEvents[event.id];
|
||||||
if (event['_status']['sent']) {
|
if (event['_status']['sent']) {
|
||||||
event['_status']['successFunc'](event);
|
event['_status']['successFunc'](event);
|
||||||
} else {
|
} else {
|
||||||
event['_status']['failureFunc'](event);
|
event['_status']['failureFunc'](event);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(this).trigger(event.type, event);
|
$(this).trigger(event.type, event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** ===
|
// === {{{AjaxIM.}}}**{{{request(url, data, successFunc, failureFunc)}}}** ===
|
||||||
//
|
//
|
||||||
// Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}},
|
// Wrapper around {{{$.jsonp}}}, the JSON-P library for jQuery, and {{{$.ajax}}},
|
||||||
@@ -1437,7 +1443,6 @@ $.extend(AjaxIM.prototype, {
|
|||||||
|
|
||||||
var jsonp = (url.substring(0, 1) !== '/');
|
var jsonp = (url.substring(0, 1) !== '/');
|
||||||
var success = false;
|
var success = false;
|
||||||
data['sessionid'] = store.get('sessionid');
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: data,
|
data: data,
|
||||||
@@ -1465,8 +1470,7 @@ $.extend(AjaxIM.prototype, {
|
|||||||
};
|
};
|
||||||
var noopfn = function() {
|
var noopfn = function() {
|
||||||
var noopdone = false;
|
var noopdone = false;
|
||||||
var event = {type: 'noop'};
|
var event = {type: 'noop', from: store.get('user'), sessionid: store.get('sessionid')};
|
||||||
event['sessionid'] = store.get('sessionid');
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: self.actions.noop,
|
url: self.actions.noop,
|
||||||
data: event,
|
data: event,
|
||||||
@@ -1548,7 +1552,19 @@ AjaxIM.incoming = function(event) {
|
|||||||
$(AjaxIM.client).trigger(event.type, event);
|
$(AjaxIM.client).trigger(event.type, event);
|
||||||
};
|
};
|
||||||
|
|
||||||
AjaxIM.eventID = 1;
|
AjaxIM.uid = function(n){
|
||||||
|
var chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', nn='';
|
||||||
|
for(var c=0; c < n; c++){
|
||||||
|
nn += chars.substr(0|Math.random() * chars.length, 1);
|
||||||
|
}
|
||||||
|
return nn;
|
||||||
|
};
|
||||||
|
|
||||||
|
AjaxIM.onObj = function(obj, func) {
|
||||||
|
return function(evt, event) {
|
||||||
|
$.proxy(func, obj)(event);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// === {{{AjaxIM.}}}**{{{l10n}}}** ===
|
// === {{{AjaxIM.}}}**{{{l10n}}}** ===
|
||||||
//
|
//
|
||||||
@@ -1580,25 +1596,11 @@ AjaxIM.l10n = {
|
|||||||
notConnected: 'You are currently not connected or the server is not available. ' +
|
notConnected: 'You are currently not connected or the server is not available. ' +
|
||||||
'Please ensure that you are signed in and try again.',
|
'Please ensure that you are signed in and try again.',
|
||||||
notConnectedTip: 'You are currently not connected.',
|
notConnectedTip: 'You are currently not connected.',
|
||||||
|
|
||||||
defaultAway: 'I\'m away.'
|
|
||||||
};
|
|
||||||
|
|
||||||
AjaxIM.onObj = function(obj, func) {
|
defaultAway: 'I\'m away.'
|
||||||
return function(evt, event) {
|
|
||||||
$.proxy(func, obj)(event);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AjaxIM.debug = true;
|
AjaxIM.debug = true;
|
||||||
function _dbg(msg) {
|
function _dbg(msg) {
|
||||||
if(AjaxIM.debug && window.console) console.log(msg);
|
if(AjaxIM.debug && window.console) console.log(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function uid(n){
|
|
||||||
var chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', nn='';
|
|
||||||
for(var c=0; c < n; c++){
|
|
||||||
nn += chars.substr(0|Math.random() * chars.length, 1);
|
|
||||||
}
|
|
||||||
return nn;
|
|
||||||
}
|
|
||||||
|
|||||||
externo
+1
-1
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,22 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Ajax IM
|
|
||||||
* Ajax Instant Messeneger
|
|
||||||
* http://ajaxim.com/
|
|
||||||
*
|
|
||||||
* Copyright 2010, Joshua Gross
|
|
||||||
* Licensed under the MIT license.
|
|
||||||
* [License URL]
|
|
||||||
*
|
|
||||||
* Includes:
|
|
||||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
|
||||||
* v2.1, Copyright 2002, Paul Johnston
|
|
||||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
||||||
* Distributed under the BSD License
|
|
||||||
* See http://pajhome.org.uk/crypt/md5 for more info
|
|
||||||
*
|
|
||||||
* Date Format 1.2.3
|
|
||||||
* http://blog.stevenlevithan.com/archives/date-time-format
|
|
||||||
* Copyright 2009 Steven Levithan
|
|
||||||
* MIT license
|
|
||||||
*/
|
|
||||||
(function($) {
|
|
||||||
externo
-4
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+320
-349
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
externo
+4
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
})(jQuery || $);
|
|
||||||
+63
-64
@@ -2,26 +2,27 @@
|
|||||||
var express = require('express'),
|
var express = require('express'),
|
||||||
app = express(),
|
app = express(),
|
||||||
http = require('http').Server(app),
|
http = require('http').Server(app),
|
||||||
io = require('socket.io')(http),
|
// io = require('socket.io')(http), // uncomment to enable Socket.IO
|
||||||
bodyParser = require('body-parser'),
|
bodyParser = require('body-parser'),
|
||||||
sys = require('sys'),
|
sys = require('sys'),
|
||||||
packages = require('./libs/packages'),
|
|
||||||
o_ = require('./libs/utils');
|
o_ = require('./libs/utils');
|
||||||
|
|
||||||
o_.merge(global, require('./settings'));
|
o_.merge(global, require('./settings'));
|
||||||
try { o_.merge(global, require('./settings.local')); } catch(e) {}
|
try { o_.merge(global, require('./settings.local')); } catch(e) {}
|
||||||
|
|
||||||
|
var reapInterval = (typeof io === 'undefined')? 60 * 1000: -1;
|
||||||
|
|
||||||
//app.set('env', 'development');
|
//app.set('env', 'development');
|
||||||
app.use(require('method-override')());
|
app.use(require('method-override')());
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded());
|
app.use(bodyParser.urlencoded({extended: true}));
|
||||||
var mw = require('./middleware/im')({
|
var mw = require('./middleware/im')({
|
||||||
maxAge: 60 * 1000,
|
maxAge: 60 * 1000,
|
||||||
reapInterval: 60 * 1000,
|
reapInterval: reapInterval,
|
||||||
authentication: require('./libs/authentication/' + AUTH_LIBRARY)
|
authentication: require('./libs/authentication/' + AUTH_LIBRARY)
|
||||||
});
|
});
|
||||||
app.use(mw.session);
|
app.use(mw.session);
|
||||||
var hub = mw.hub;
|
var store = mw.store;
|
||||||
|
|
||||||
app.set('root', __dirname);
|
app.set('root', __dirname);
|
||||||
|
|
||||||
@@ -29,29 +30,53 @@ if ('development' == app.get('env')) {
|
|||||||
app.set('views', __dirname + '/dev/views');
|
app.set('views', __dirname + '/dev/views');
|
||||||
app.set('view engine', 'jade');
|
app.set('view engine', 'jade');
|
||||||
|
|
||||||
app.use(require("morgan")());
|
app.use(require("morgan")('combined'));
|
||||||
require('./dev/app')('/dev', app);
|
require('./dev/app')('/dev', app);
|
||||||
app.use(express.static(
|
app.use(express.static(
|
||||||
require('path').join(__dirname, '../client')));
|
require('path').join(__dirname, '../client')));
|
||||||
app.use(require('express-error-handler')({dumpExceptions: true, showStack: true}));
|
app.use(require('express-error-handler')({dumpExceptions: true, showStack: true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
io.on('connection', function(socket){
|
// Socket.IO handlers
|
||||||
socket.on('server', function(event) {
|
if (typeof io !== 'undefined') {
|
||||||
if (event.type == 'hello') {
|
io.on('connection', function(socket){
|
||||||
event.socketio = socket;
|
var username = null;
|
||||||
hub.get(event, function(err, sess) {
|
socket.on('server', function(event) {
|
||||||
sess.touch();
|
event.reply = function(status) {
|
||||||
store.set(event.sessionID, sess);
|
if (status) {
|
||||||
});
|
this._status = status;
|
||||||
} else {
|
}
|
||||||
hub.find(event.from, function(from) {
|
delete this.reply;
|
||||||
from.socketio = socket;
|
socket.emit('client', this);
|
||||||
from.dispatch(hub, event);
|
};
|
||||||
});
|
var unauthenticated = function() {
|
||||||
}
|
event.reply({sent: false, e: 'unauthenticated'});
|
||||||
|
};
|
||||||
|
store.get(event, function(event, user) {
|
||||||
|
if ((event.type == 'hello') && user) {
|
||||||
|
username = user.data('username');
|
||||||
|
store.set(username, user);
|
||||||
|
event.reply({sent: true});
|
||||||
|
} else if ((event.type != 'hello')) {
|
||||||
|
store.find('username', event.from, function(from) {
|
||||||
|
if (from) {
|
||||||
|
from.dispatch(event);
|
||||||
|
} else {
|
||||||
|
unauthenticated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
unauthenticated();
|
||||||
|
}
|
||||||
|
}, socket);
|
||||||
|
});
|
||||||
|
socket.on('disconnect', function() {
|
||||||
|
if (username) {
|
||||||
|
store.reap(username);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
http.listen(APP_PORT, APP_HOST, function(){
|
http.listen(APP_PORT, APP_HOST, function(){
|
||||||
console.log('Ajax IM server started...');
|
console.log('Ajax IM server started...');
|
||||||
@@ -60,50 +85,24 @@ http.listen(APP_PORT, APP_HOST, function(){
|
|||||||
// Listener endpoint; handled in middleware
|
// Listener endpoint; handled in middleware
|
||||||
app.get('/app/listen', function(){});
|
app.get('/app/listen', function(){});
|
||||||
|
|
||||||
app.use('/app/message', function(req, res) {
|
// HTTP handlers
|
||||||
res.find(req.param('to'), function(to) {
|
|
||||||
if(to) {
|
|
||||||
res.message(to, req.event);
|
|
||||||
} else {
|
|
||||||
req.event._status = {sent: false, e: 'not online'};
|
|
||||||
res.jsonp(req.event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/app/message/typing', function(req, res) {
|
|
||||||
if(~packages.TYPING_STATES.indexOf('typing' + req.param('state'))) {
|
|
||||||
res.find(req.param('to'), function(user) {
|
|
||||||
if(user) {
|
|
||||||
req.event.status = 'typing' + req.param('state');
|
|
||||||
res.message(user, req.event);
|
|
||||||
} else {
|
|
||||||
// Typing updates do not receive confirmations,
|
|
||||||
// as they are not important enough.
|
|
||||||
req.event._status = {sent: false, e: 'invalid user'};
|
|
||||||
res.jsonp(req.event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
req.event._status = {sent: false, e: 'invalid state'};
|
|
||||||
res.jsonp(req.event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/app/status', function(req, res) {
|
|
||||||
if(~packages.STATUSES.indexOf(req.param('status'))) {
|
|
||||||
res.status(req.event);
|
|
||||||
} else {
|
|
||||||
req.event._status = {sent: false, e: 'invalid status'};
|
|
||||||
res.jsonp(req.event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/app/noop', function(req, res) {
|
app.use('/app/noop', function(req, res) {
|
||||||
req.event._status = {sent: true};
|
req.event._status = {sent: true};
|
||||||
res.jsonp(req.event);
|
res.jsonp(req.event);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use('/app/signoff', function(req, res) {
|
app.use('/app/message', function(req, res) {
|
||||||
res.signOff(req.event);
|
res.message();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use('/app/message/typing', function(req, res) {
|
||||||
|
res.typing();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use('/app/status', function(req, res) {
|
||||||
|
res.status();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use('/app/signoff', function(req, res) {
|
||||||
|
res.signOff();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ doctype html
|
|||||||
html(lang="en")
|
html(lang="en")
|
||||||
head
|
head
|
||||||
title Ajax IM
|
title Ajax IM
|
||||||
script(src='/js/jquery-1.11.0.js', type='text/javascript')
|
script(src='/js/jquery-1.11.1.js', type='text/javascript')
|
||||||
script(src='/js/md5.js', type='text/javascript')
|
script(src='/js/md5.js', type='text/javascript')
|
||||||
script(src='/js/store.js', type='text/javascript')
|
script(src='/js/store.js', type='text/javascript')
|
||||||
script(src='/js/dateformat.js', type='text/javascript')
|
script(src='/js/dateformat.js', type='text/javascript')
|
||||||
|
|||||||
@@ -1,22 +1,53 @@
|
|||||||
var o_ = require('../../utils');
|
var o_ = require('../../utils');
|
||||||
|
var User = require('../../../middleware/im/user');
|
||||||
|
|
||||||
exports.authenticate = function(request, callback, hub) {
|
exports.authenticate = function(store, event, callback) {
|
||||||
// Verify user based on request.
|
// remove authentication from event
|
||||||
// On failure, redirect user to auth form
|
var sessionid = event.sessionid;
|
||||||
var username = request.from;
|
delete event.sessionid;
|
||||||
if (!username) {
|
|
||||||
username = 'username' + (++hub.uid);
|
// find the user
|
||||||
|
var user = event.from? store.sessions[event.from]: undefined;
|
||||||
|
|
||||||
|
// create, validate or reject user
|
||||||
|
if (user) {
|
||||||
|
// found the user so check authentication
|
||||||
|
if (sessionid && (sessionid === user.data('sessionid'))) {
|
||||||
|
event.from = user.data('username');
|
||||||
|
callback(event, user);
|
||||||
|
} else {
|
||||||
|
event._status = {sent: false, e: 'not authenticated'};
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
|
} else if (event.type == 'hello') {
|
||||||
|
store.find('sessionid', sessionid, function(user) {
|
||||||
|
if (user) {
|
||||||
|
// relogin as same user
|
||||||
|
event.from = user.data('username');
|
||||||
|
callback(event, user);
|
||||||
|
} else {
|
||||||
|
// if no username requested, assign user name
|
||||||
|
if (!event.from) {
|
||||||
|
event.from = 'username' + (++store.uid);
|
||||||
|
}
|
||||||
|
// everybody is your friend!
|
||||||
|
var friends = o_.values(store.sessions).map(function(friend) {
|
||||||
|
return friend.data('username');
|
||||||
|
});
|
||||||
|
// you're even friends with yourself!
|
||||||
|
friends.push(event.from);
|
||||||
|
// create new user
|
||||||
|
user = new User(store, {
|
||||||
|
username: event.from,
|
||||||
|
sessionid: sessionid,
|
||||||
|
displayname: 'John Smith',
|
||||||
|
otherinfo: 'any other relevant key/values'
|
||||||
|
}, friends);
|
||||||
|
callback(event, user);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event._status = {sent: false, e: 'not authenticated'};
|
||||||
|
callback(event);
|
||||||
}
|
}
|
||||||
callback({
|
|
||||||
username: username,
|
|
||||||
displayname: 'John Smith',
|
|
||||||
otherinfo: 'any other relevant key/values'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.friends = function(request, data, callback, hub) {
|
|
||||||
// Create a friends list based on given user data
|
|
||||||
callback(o_.values(hub.sessions).map(function(friend) {
|
|
||||||
return friend.data('username');
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
+55
-40
@@ -1,63 +1,80 @@
|
|||||||
var url = require('url'),
|
var url = require('url'),
|
||||||
Hub = require('./im/hub'),
|
Hub = require('./im/hub'),
|
||||||
|
packages = require('../libs/packages'),
|
||||||
o_ = require('../libs/utils');
|
o_ = require('../libs/utils');
|
||||||
|
|
||||||
module.exports = function setupHub(options) {
|
module.exports = function setupHub(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
store = new Hub(options);
|
var store = new Hub(options);
|
||||||
|
|
||||||
return {hub: store, session: function session(req, res, next) {
|
return {store: store, session: function session(req, res, next) {
|
||||||
req.sessionStore = store;
|
req.sessionStore = store;
|
||||||
|
|
||||||
req.sessionID = req.param('sessionid');
|
// create the event object
|
||||||
|
req.event = o_.extend({}, req.query, req.body, req.params);
|
||||||
|
o_.deletekey(req.event, 'callback');
|
||||||
|
o_.deletekey(req.event, '_');
|
||||||
|
|
||||||
if(url.parse(req.url).pathname.substring(0, 5) !== '/app/') {
|
req.event.reply = function(status) {
|
||||||
next();
|
if (status) {
|
||||||
return;
|
this._status = status;
|
||||||
}
|
}
|
||||||
|
delete this.reply;
|
||||||
|
res.jsonp(this);
|
||||||
|
};
|
||||||
|
|
||||||
if(req.sessionID) {
|
var unauthenticated = function() {
|
||||||
store.get(req, function(err, sess) {
|
req.event.reply({sent: false, e: 'unauthenticated'});
|
||||||
if(err) {
|
};
|
||||||
next(err);
|
|
||||||
|
// set event handlers to unauthenticated by default
|
||||||
|
res.message = res.typing = res.status = res.signOff = unauthenticated;
|
||||||
|
|
||||||
|
if(url.parse(req.url).pathname.substring(0, 5) === '/app/') {
|
||||||
|
store.get(req.event, function(event, user) {
|
||||||
|
if(!user) {
|
||||||
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sess) {
|
user.touch();
|
||||||
next(new Error(JSON.stringify({
|
|
||||||
type: 'error',
|
|
||||||
error: 'not authenticated'})));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sess.touch();
|
|
||||||
if(url.parse(req.url).pathname === '/app/listen') {
|
if(url.parse(req.url).pathname === '/app/listen') {
|
||||||
req.connection.setTimeout(5 * 60 * 1000);
|
req.connection.setTimeout(5 * 60 * 1000);
|
||||||
sess.listener(res);
|
user.listener(res);
|
||||||
store.set(req.sessionID, sess);
|
store.set(user.data('username'), user);
|
||||||
|
|
||||||
if(msg = sess.message_queue.shift())
|
if(msg = user.message_queue.shift()) {
|
||||||
sess._send.apply(sess, msg);
|
user._send.apply(user, msg);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
req.event = o_.extend({}, req.query, req.body, req.params);
|
req.event.from = user.data('username');
|
||||||
o_.deletekey(req.event, 'callback');
|
|
||||||
o_.deletekey(req.event, 'sessionid');
|
|
||||||
o_.deletekey(req.event, '_');
|
|
||||||
req.event.from = sess.data('username');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.session = sess;
|
res.message = function() {
|
||||||
res.session = sess;
|
user.message(req.event);
|
||||||
res.find = store.find.bind(store);
|
|
||||||
res.message = function(to, event) {
|
|
||||||
store.message(res, to, event);
|
|
||||||
};
|
};
|
||||||
res.status = function(event) {
|
res.typing = function() {
|
||||||
req.session.status(res, event);
|
if(~packages.TYPING_STATES.indexOf('typing' + req.event.state)) {
|
||||||
|
store.find('username', req.event.to, function(to) {
|
||||||
|
if(to) {
|
||||||
|
req.event.status = 'typing' + req.event.state;
|
||||||
|
user.message(req.event);
|
||||||
|
} else {
|
||||||
|
// Typing updates do not receive confirmations,
|
||||||
|
// as they are not important enough.
|
||||||
|
req.event.reply({sent: true});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
req.event.reply({sent: false, e: 'invalid state'});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
res.signOff = function(event) {
|
res.status = function() {
|
||||||
store.signOff(req.sessionID, res, event);
|
user.status(req.event);
|
||||||
|
};
|
||||||
|
res.signOff = function() {
|
||||||
|
user.signOff(req.event);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(url.parse(req.url).pathname !== '/app/listen') {
|
if(url.parse(req.url).pathname !== '/app/listen') {
|
||||||
@@ -65,9 +82,7 @@ module.exports = function setupHub(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
next(new Error(JSON.stringify({
|
next();
|
||||||
type: 'error',
|
|
||||||
error: 'not authenticated'})));
|
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ var Hub = module.exports = function Hub(options) {
|
|||||||
|
|
||||||
if(this.reapInterval !== -1) {
|
if(this.reapInterval !== -1) {
|
||||||
setInterval(function(self) {
|
setInterval(function(self) {
|
||||||
self.reap(self.maxAge);
|
self.reapCheck(self.maxAge);
|
||||||
}, this.reapInterval, this);
|
}, this.reapInterval, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,9 +24,10 @@ var Hub = module.exports = function Hub(options) {
|
|||||||
var sids = Object.keys(this.sessions), sid, sess;
|
var sids = Object.keys(this.sessions), sid, sess;
|
||||||
for(sid in this.sessions) {
|
for(sid in this.sessions) {
|
||||||
sess = this.sessions[sid];
|
sess = this.sessions[sid];
|
||||||
if(sess.data('username') == event.from) {
|
if (sess.data('username') == event.from) {
|
||||||
if(sess.listeners.length)
|
if (sess.listeners.length) {
|
||||||
sess.send({type: 'goodbye'});
|
sess.send({type: 'goodbye'});
|
||||||
|
}
|
||||||
delete this.sessions[sid];
|
delete this.sessions[sid];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -35,66 +36,56 @@ var Hub = module.exports = function Hub(options) {
|
|||||||
}, this));
|
}, this));
|
||||||
};
|
};
|
||||||
|
|
||||||
Hub.prototype.destroy = function(sid, fn) {
|
Hub.prototype.reapCheck = function(ms) {
|
||||||
this.set(sid, null, fn);
|
var threshold = +new Date - ms;
|
||||||
};
|
var sids = Object.keys(this.sessions);
|
||||||
|
|
||||||
Hub.prototype.reap = function(ms) {
|
|
||||||
var threshold = +new Date - ms,
|
|
||||||
sids = Object.keys(this.sessions);
|
|
||||||
for(var i = 0, len = sids.length; i < len; ++i) {
|
for(var i = 0, len = sids.length; i < len; ++i) {
|
||||||
var sid = sids[i], sess = this.sessions[sid];
|
var sid = sids[i];
|
||||||
if(sess.lastAccess < threshold) {
|
if(this.sessions[sid].lastAccess < threshold) {
|
||||||
var event = {type: 'status', from: sess.data('username'), status: 'offline', message: ''};
|
this.reap(sid);
|
||||||
this.events.emit('update', event);
|
|
||||||
delete this.sessions[sid];
|
|
||||||
sess.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Hub.prototype.get = function(req, fn) {
|
Hub.prototype.reap = function(sid) {
|
||||||
if(this.sessions[req.sessionID]) {
|
var sess = this.sessions[sid];
|
||||||
if (!this.sessions[req.sessionID].req) {
|
console.log('reaping '+sess.data('username'));
|
||||||
this.sessions[req.sessionID].req = req;
|
var event = {type: 'status', from: sess.data('username'), status: 'offline', message: ''};
|
||||||
}
|
this.events.emit('update', event);
|
||||||
fn(null, this.sessions[req.sessionID]);
|
delete this.sessions[sid];
|
||||||
} else {
|
sess.close();
|
||||||
this.auth.authenticate(req, o_.bind(function(data) {
|
};
|
||||||
if(data) {
|
|
||||||
var session = new User(req, data);
|
|
||||||
if (req.socketio) {
|
|
||||||
session.socketio = req.socketio;
|
|
||||||
}
|
|
||||||
this.set(req.sessionID, session);
|
|
||||||
|
|
||||||
this.auth.friends(req, data, o_.bind(function(friends) {
|
Hub.prototype.get = function(event, fn, socket) {
|
||||||
var friends_copy = friends.slice();
|
this.auth.authenticate(this, event, o_.bind(function(event, user) {
|
||||||
o_.values(this.sessions).filter(function(friend) {
|
if (user) {
|
||||||
return ~friends.indexOf(friend.data('username'));
|
if (socket) {
|
||||||
}).forEach(function(friend) {
|
user.socketio = socket;
|
||||||
var username = friend.data('username');
|
|
||||||
friends_copy[friends_copy.indexOf(username)] =
|
|
||||||
[username, friend.status()];
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
session._friends(friends_copy);
|
|
||||||
session.events.addListener('status',
|
|
||||||
o_.bind(function(value, message) {
|
|
||||||
var event = {type: 'status', from: session.data('username'), status: value, message: message};
|
|
||||||
this.events.emit('update', event);
|
|
||||||
}, this));
|
|
||||||
this.events.addListener('update',
|
|
||||||
o_.bind(session.receivedUpdate, session));
|
|
||||||
this.set(req.sessionID, session);
|
|
||||||
fn(null, session);
|
|
||||||
}, this), this);
|
|
||||||
session.status(null, {status: packages.STATUSES[0], message: ''});
|
|
||||||
} else {
|
|
||||||
fn();
|
|
||||||
}
|
}
|
||||||
}, this), this);
|
if (this.sessions[user.data('username')]) {
|
||||||
}
|
fn(event, user);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.set(user.data('username'), user);
|
||||||
|
var friends = user.friends;
|
||||||
|
var friends_copy = friends.slice();
|
||||||
|
o_.values(this.sessions).filter(function(friend) {
|
||||||
|
return ~friends.indexOf(friend.data('username'));
|
||||||
|
}).forEach(function(friend) {
|
||||||
|
var username = friend.data('username');
|
||||||
|
friends_copy[friends_copy.indexOf(username)] = [username, friend.status()];
|
||||||
|
}, this);
|
||||||
|
user._friends(friends_copy);
|
||||||
|
user.events.addListener('status', o_.bind(function(value, message) {
|
||||||
|
var event = {type: 'status', from: user.data('username'), status: value, message: message};
|
||||||
|
this.events.emit('update', event);
|
||||||
|
}, this));
|
||||||
|
this.events.addListener('update', o_.bind(user.receivedUpdate, user));
|
||||||
|
fn(event, user);
|
||||||
|
} else {
|
||||||
|
fn(event);
|
||||||
|
}
|
||||||
|
}, this));
|
||||||
};
|
};
|
||||||
|
|
||||||
Hub.prototype.set = function(sid, sess, fn) {
|
Hub.prototype.set = function(sid, sess, fn) {
|
||||||
@@ -102,11 +93,11 @@ Hub.prototype.set = function(sid, sess, fn) {
|
|||||||
fn && fn();
|
fn && fn();
|
||||||
};
|
};
|
||||||
|
|
||||||
Hub.prototype.find = function(username, fn) {
|
Hub.prototype.find = function(key, value, fn) {
|
||||||
for(var sid in this.sessions) {
|
for(var sid in this.sessions) {
|
||||||
var session = this.sessions[sid],
|
var session = this.sessions[sid];
|
||||||
sess_username = session.data('username');
|
var user_value = session.data(key);
|
||||||
if(sess_username == username) {
|
if (user_value == value) {
|
||||||
fn(session);
|
fn(session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -114,31 +105,12 @@ Hub.prototype.find = function(username, fn) {
|
|||||||
fn(false);
|
fn(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
Hub.prototype.message = function(res, to, event) {
|
Hub.prototype.dispatch = function(event) {
|
||||||
try {
|
this.find('username', event.from, function(from) {
|
||||||
to.send(event);
|
if (from) {
|
||||||
event._status = {sent: true};
|
from.dispatch(event);
|
||||||
if (res) {
|
|
||||||
res.jsonp(event);
|
|
||||||
} else {
|
} else {
|
||||||
this.find(event.from, function(from) {
|
event.reply({sent: false, e: 'not authenticated'});
|
||||||
from.socketio.emit('client', event);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch(e) {
|
});
|
||||||
event._status = {sent: false, e: e.description};
|
|
||||||
res.jsonp(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Hub.prototype.signOff = function(sid, res, event) {
|
|
||||||
if (sid in this.sessions) {
|
|
||||||
event.status = 'offline';
|
|
||||||
event.message = '';
|
|
||||||
this.events.emit('update', event);
|
|
||||||
}
|
|
||||||
event._status = {sent: true};
|
|
||||||
if (res) {
|
|
||||||
res.jsonp(event);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ var events = require('events'),
|
|||||||
packages = require('../../libs/packages'),
|
packages = require('../../libs/packages'),
|
||||||
o_ = require('../../libs/utils');
|
o_ = require('../../libs/utils');
|
||||||
|
|
||||||
var User = module.exports = function(req, data) {
|
var User = module.exports = function(store, data, friends) {
|
||||||
this.req = req;
|
this.store = store;
|
||||||
this.id = req.sessionID;
|
|
||||||
this.connection = null;
|
this.connection = null;
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.message_queue = [];
|
this.message_queue = [];
|
||||||
this.convos = {};
|
|
||||||
this._data = data;
|
this._data = data;
|
||||||
|
this.friends = friends;
|
||||||
|
|
||||||
this.events = new events.EventEmitter();
|
this.events = new events.EventEmitter();
|
||||||
this._status = packages.STATUSES[0];
|
this._status = packages.STATUSES[0];
|
||||||
@@ -102,7 +101,6 @@ User.prototype._send = function(type, event, res) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
User.prototype.data = function(key, def) {
|
User.prototype.data = function(key, def) {
|
||||||
if(key == 'id') return this.id;
|
|
||||||
return this._data[key] || this['_' + key] ||
|
return this._data[key] || this['_' + key] ||
|
||||||
(typeof this[key] != 'function' && this[key]) ||
|
(typeof this[key] != 'function' && this[key]) ||
|
||||||
def || false;
|
def || false;
|
||||||
@@ -112,24 +110,49 @@ User.prototype.touch = function() {
|
|||||||
this.lastAccess = +new Date;
|
this.lastAccess = +new Date;
|
||||||
};
|
};
|
||||||
|
|
||||||
User.prototype.status = function(res, event) {
|
User.prototype.message = function(event) {
|
||||||
if(!event)
|
var self = this;
|
||||||
|
try {
|
||||||
|
self.store.find('username', event.to, function(to) {
|
||||||
|
if(to) {
|
||||||
|
to.send(event);
|
||||||
|
event.reply({sent: true});
|
||||||
|
} else {
|
||||||
|
event.reply({sent: false, e: 'not online'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
event.reply({sent: false, e: e.description});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.prototype.status = function(event) {
|
||||||
|
if (!event) {
|
||||||
return this._status;
|
return this._status;
|
||||||
|
}
|
||||||
|
|
||||||
this._status = event.status;
|
this._status = event.status;
|
||||||
this._status_message = event.message;
|
this._status_message = event.message;
|
||||||
this.events.emit('status', event.status, event.message);
|
this.events.emit('status', event.status, event.message);
|
||||||
event._status = {sent: true};
|
if (event.reply) {
|
||||||
if (res) {
|
event.reply({sent: true});
|
||||||
res.jsonp(event);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
User.prototype.dispatch = function(hub, event) {
|
User.prototype.signOff = function(event) {
|
||||||
|
event.status = 'offline';
|
||||||
|
this.store.events.emit('update', event);
|
||||||
|
event.reply({sent: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
User.prototype.dispatch = function(event) {
|
||||||
if (event.type == 'message') {
|
if (event.type == 'message') {
|
||||||
hub.find(event.to, function(to) {
|
this.message(event);
|
||||||
hub.message(null, to, event);
|
} else if (event.type == 'status') {
|
||||||
});
|
this.status(event);
|
||||||
|
} else if (event.type == 'signoff') {
|
||||||
|
this.signOff(event);
|
||||||
|
} else {
|
||||||
|
event.reply({sent: false, e: 'invalid event type'});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário