|
|
|
@ -2,13 +2,13 @@
|
|
|
|
|
const Crypto = require('crypto');
|
|
|
|
|
const LogStore = require('./storage/LogStore');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const LAG_MAX_BEFORE_DISCONNECT = 30000;
|
|
|
|
|
const LAG_MAX_BEFORE_PING = 15000;
|
|
|
|
|
const HISTORY_KEEPER_ID = Crypto.randomBytes(8).toString('hex');
|
|
|
|
|
|
|
|
|
|
const USE_HISTORY_KEEPER = true;
|
|
|
|
|
const USE_FILE_BACKUP_STORAGE = true;
|
|
|
|
|
const LOG_MESSAGES = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let dropUser;
|
|
|
|
@ -17,7 +17,7 @@ const now = function () { return (new Date()).getTime(); };
|
|
|
|
|
|
|
|
|
|
const sendMsg = function (ctx, user, msg) {
|
|
|
|
|
try {
|
|
|
|
|
if (LOG_MESSAGES) { console.log('<' + JSON.stringify(msg)); }
|
|
|
|
|
if (ctx.config.logToStdout) { console.log('<' + JSON.stringify(msg)); }
|
|
|
|
|
user.socket.send(JSON.stringify(msg));
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log(e.stack);
|
|
|
|
@ -62,6 +62,24 @@ dropUser = function (ctx, user) {
|
|
|
|
|
if (chan.length === 0) {
|
|
|
|
|
console.log("Removing empty channel ["+chanName+"]");
|
|
|
|
|
delete ctx.channels[chanName];
|
|
|
|
|
|
|
|
|
|
/* Call removeChannel if it is a function and channel removal is
|
|
|
|
|
set to true in the config file */
|
|
|
|
|
if (ctx.config.removeChannels) {
|
|
|
|
|
if (typeof(ctx.store.removeChannel) === 'function') {
|
|
|
|
|
ctx.timeouts[chanName] = setTimeout(function () {
|
|
|
|
|
ctx.store.removeChannel(chanName, function (err) {
|
|
|
|
|
if (err) { console.error("[removeChannelErr]: %s", err); }
|
|
|
|
|
else {
|
|
|
|
|
console.log("Deleted channel [%s] history from database...", chanName);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}, ctx.config.channelRemovalTimeout);
|
|
|
|
|
} else {
|
|
|
|
|
console.error("You have configured your server to remove empty channels, " +
|
|
|
|
|
"however, the database adaptor you are using has not implemented this behaviour.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sendChannelMessage(ctx, chan, [user.id, 'LEAVE', chanName, 'Quit: [ dropUser() ]']);
|
|
|
|
|
}
|
|
|
|
@ -91,6 +109,12 @@ const handleMessage = function (ctx, user, msg) {
|
|
|
|
|
let chanName = obj || randName();
|
|
|
|
|
sendMsg(ctx, user, [seq, 'JACK', chanName]);
|
|
|
|
|
let chan = ctx.channels[chanName] = ctx.channels[chanName] || [];
|
|
|
|
|
|
|
|
|
|
// prevent removal of the channel if there is a pending timeout
|
|
|
|
|
if (ctx.config.removeChannels && ctx.timeouts[chanName]) {
|
|
|
|
|
clearTimeout(ctx.timeouts[chanName]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chan.id = chanName;
|
|
|
|
|
if (USE_HISTORY_KEEPER) {
|
|
|
|
|
sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'JOIN', chanName]);
|
|
|
|
@ -153,11 +177,19 @@ const handleMessage = function (ctx, user, msg) {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let run = module.exports.run = function (storage, socketServer) {
|
|
|
|
|
let run = module.exports.run = function (storage, socketServer, config) {
|
|
|
|
|
/* Channel removal timeout defaults to 60000ms (one minute) */
|
|
|
|
|
config.channelRemovalTimeout =
|
|
|
|
|
typeof(config.channelRemovalTimeout) === 'number'?
|
|
|
|
|
config.channelRemovalTimeout:
|
|
|
|
|
60000;
|
|
|
|
|
|
|
|
|
|
let ctx = {
|
|
|
|
|
users: {},
|
|
|
|
|
channels: {},
|
|
|
|
|
store: (USE_FILE_BACKUP_STORAGE) ? LogStore.create('messages.log', storage) : storage
|
|
|
|
|
timeouts: {},
|
|
|
|
|
store: (USE_FILE_BACKUP_STORAGE) ? LogStore.create('messages.log', storage) : storage,
|
|
|
|
|
config: config
|
|
|
|
|
};
|
|
|
|
|
setInterval(function () {
|
|
|
|
|
Object.keys(ctx.users).forEach(function (userId) {
|
|
|
|
@ -183,7 +215,7 @@ let run = module.exports.run = function (storage, socketServer) {
|
|
|
|
|
ctx.users[user.id] = user;
|
|
|
|
|
sendMsg(ctx, user, [0, '', 'IDENT', user.id]);
|
|
|
|
|
socket.on('message', function(message) {
|
|
|
|
|
if (LOG_MESSAGES) { console.log('>'+message); }
|
|
|
|
|
if (ctx.config.logToStdout) { console.log('>'+message); }
|
|
|
|
|
try {
|
|
|
|
|
handleMessage(ctx, user, message);
|
|
|
|
|
} catch (e) {
|
|
|
|
|