logger script, bug fixes

This commit is contained in:
Evert Prants 2016-11-14 17:20:27 +02:00
parent 0b703bfd25
commit cc0df245c6
6 changed files with 140 additions and 91 deletions

View File

@ -1,16 +1,23 @@
[server] [server]
# HTTP server port
port=8080 port=8080
# Debug information
debug=true debug=true
# Print statistics about the currently running instance periodically
printStats=true
[client] [client]
# IRC settings
username="teemant" username="teemant"
realname="A Teemant User" realname="A Teemant User"
default_quit_msg="Teemant IRC" default_quit_msg="Teemant IRC"
default_part_msg="Bye!" default_part_msg="Bye!"
# Socket settings
secure_by_default=false secure_by_default=false
timeout=3000 timeout=3000
encoding="utf-8" encoding="utf-8"
rejectUnauthorizedCertificates=false rejectUnauthorizedCertificates=false
[webirc] [webirc]
enabled=true
resolveInterval=43200 resolveInterval=43200

View File

@ -1,6 +1,6 @@
{ {
"name": "teemantirc", "name": "teemantirc",
"version": "1.0.0", "version": "1.1.0",
"description": "Web-based IRC client", "description": "Web-based IRC client",
"main": "teemant.js", "main": "teemant.js",
"scripts": { "scripts": {

51
server/logger.js Normal file
View File

@ -0,0 +1,51 @@
const util = require("util"),
config = require(__dirname+'/config');
module.exports.log = function() {
console.log.apply(null, arguments);
}
module.exports.debugLog = function() {
if(!config.server.debug) return;
console.log.apply(null, arguments);
}
module.exports.errorLog = function(errObj, specify) {
if(specify)
console.error(specify);
console.error(errObj);
if(errObj.stack)
console.error(errObj.stack);
}
module.exports.printRuntimeStats = function(runtime_stats, connections) {
if(!config.server.printStats) return;
let date = new Date();
let users = 0;
let servers = 0;
let serversPerUser = 0;
for(let uid in connections) {
let ca = connections[uid];
users += 1;
for(let snam in ca) {
if(!snam) continue;
if(snam == "host") continue;
servers += 1;
}
}
if(users != 0) // Don't divide by zero lmao
serversPerUser = servers/users;
console.log(date+": Currently connected users: "+users+";",
"IRC server connections: "+servers+";",
"Average servers per user: "+serversPerUser+";",
"Total connections made: "+runtime_stats.connectionsMade+";",
"Uptime: "+process.uptime()+"s;");
}

View File

@ -1,8 +1,7 @@
let EventEmitter = require('events').EventEmitter; const EventEmitter = require('events').EventEmitter,
let net = require('net'); net = require('net'),
let tls = require('tls'); tls = require('tls'),
parse = require(__dirname+"/parser");
let parse = require(__dirname+"/parser");
if (!String.prototype.format) { if (!String.prototype.format) {
String.prototype.format = function() { String.prototype.format = function() {
@ -96,6 +95,8 @@ class IRCConnectionHandler {
if(line[0] == "PING" && line[1] != null && line[1] != '') { if(line[0] == "PING" && line[1] != null && line[1] != '') {
resp = resp.format(line.slice(1).join(' ')); resp = resp.format(line.slice(1).join(' '));
} else if(line[0] == "CLIENTINFO") {
resp = resp.format("CLIENTINFO PING "+Object.keys(this.conn.extras.ctcps).join(" "));
} else if(this.conn.extras.ctcps && this.conn.extras.ctcps[line[0]] != null) { } else if(this.conn.extras.ctcps && this.conn.extras.ctcps[line[0]] != null) {
resp = resp.format(this.conn.extras.ctcps[line[0]](data, this.conn)); resp = resp.format(this.conn.extras.ctcps[line[0]](data, this.conn));
} else { } else {
@ -163,7 +164,13 @@ class IRCConnectionHandler {
} }
break; break;
case "JOIN": case "JOIN":
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.trailing, server: serverName }); if(line.trailing) {
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.trailing, server: serverName });
} else {
for(let i in line.arguments) {
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.arguments[i], server: serverName });
}
}
break; break;
case "PART": case "PART":
this.conn.emit('pass_to_client', {type: "event_part_channel", user: line.user, channel: line.arguments[0], reason: line.trailing, server: serverName }); this.conn.emit('pass_to_client', {type: "event_part_channel", user: line.user, channel: line.arguments[0], reason: line.trailing, server: serverName });
@ -195,6 +202,7 @@ class IRCConnectionHandler {
if(Object.keys(this.conn.queue["names"]).length == 0) if(Object.keys(this.conn.queue["names"]).length == 0)
delete this.conn.queue["names"]; delete this.conn.queue["names"];
break; break;
case "PRIVMSG": case "PRIVMSG":
if(line.trailing.indexOf('\x01') == 0 && line.trailing.indexOf('\x01ACTION') != 0) if(line.trailing.indexOf('\x01') == 0 && line.trailing.indexOf('\x01ACTION') != 0)
@ -389,8 +397,10 @@ class IRCConnectionHandler {
case "318": case "318":
if(!this.conn.queue.whois || !this.conn.queue.whois[line.arguments[1]]) if(!this.conn.queue.whois || !this.conn.queue.whois[line.arguments[1]])
return; return;
this.conn.emit('pass_to_client', {type: "whoisResponse", whois: this.conn.queue.whois[line.arguments[1]], this.conn.emit('pass_to_client', {type: "whoisResponse", whois: this.conn.queue.whois[line.arguments[1]],
server: serverName, from: realServerName}); server: serverName, from: realServerName});
delete this.conn.queue.whois[line.arguments[1]]; delete this.conn.queue.whois[line.arguments[1]];
break; break;
case "321": case "321":

View File

@ -2,6 +2,7 @@ const dns = require("dns"),
fs = require("fs"), fs = require("fs"),
path = require("path"), path = require("path"),
config = require(__dirname+'/config'), config = require(__dirname+'/config'),
logger = require(__dirname+'/logger'),
webirc_data_path = path.resolve(__dirname+'/../webirc.data.json'); webirc_data_path = path.resolve(__dirname+'/../webirc.data.json');
let webirc_data = {}; let webirc_data = {};
@ -11,23 +12,25 @@ function writeToFile() {
fs.writeFile(webirc_data_path, JSON.stringify(webirc_data, null, '\t'), function (err) {if (err) throw err;}); fs.writeFile(webirc_data_path, JSON.stringify(webirc_data, null, '\t'), function (err) {if (err) throw err;});
} }
function resolveAddress(address) { function timeoutRefresh(address, seconds) {
if(config.server.debug) if(timeouts[address])
console.log("** WEBIRC ** Attempting to update IP for "+address); clearTimeout(timeouts[address]);
timeouts[address] = setTimeout(()=>{resolveAddress(address)}, seconds*1000);
}
function resolveAddress(address, force) {
logger.debugLog("** WEBIRC ** Attempting to update IP for "+address);
let obj = webirc_data[address]; let obj = webirc_data[address];
if(!obj) return; if(!obj) return;
if((Date.now() - obj.last_update)/1000 < config.webirc.resolveInterval) { if((Date.now() - obj.last_update)/1000 < config.webirc.resolveInterval && !force) {
let nextTime = (config.webirc.resolveInterval - (Date.now() - obj.last_update)/1000); let nextTime = (config.webirc.resolveInterval - (Date.now() - obj.last_update)/1000);
if(config.server.debug)
console.log("** WEBIRC ** "+address+" IP is "+obj.cached_ip+", refresh in "+nextTime+" seconds");
if(timeouts[address]) logger.debugLog("** WEBIRC ** "+address+" IP is "+obj.cached_ip+", refresh in "+nextTime+" seconds");
clearTimeout(timeouts[address]);
timeouts[address] = setTimeout(()=>{resolveAddress(address)}, nextTime*1000 ); return timeoutRefresh(address, nextTime);
return;
} }
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
@ -41,25 +44,23 @@ function resolveAddress(address) {
} }
}); });
}).then((data) => { }).then((data) => {
if(config.server.debug) logger.debugLog("** WEBIRC ** Updated DNS for "+address+"; IP is now "+data);
console.log("** WEBIRC ** Updated DNS for "+address+"; IP is now "+data);
webirc_data[address].last_update = Date.now(); webirc_data[address].last_update = Date.now();
webirc_data[address].cached_ip = data; webirc_data[address].cached_ip = data;
writeToFile(); writeToFile();
timeoutRefresh(address, config.webirc.resolveInterval);
if(timeouts[address])
clearTimeout(timeouts[address]);
timeouts[address] = setTimeout(()=>{resolveAddress(address)}, config.webirc.resolveInterval*1000);
}, (err) => { }, (err) => {
if(timeouts[address]) logger.debugLog("** WEBIRC ** Failed to updated DNS for "+address+"; IP is still "+webirc_data[address].cached_ip);
clearTimeout(timeouts[address]);
timeouts[address] = setTimeout(()=>{resolveAddress(address)}, (config.webirc.resolveInterval+60)*1000); timeoutRefresh(address, (config.webirc.resolveInterval+60));
}); });
} }
function reload() { function reload(force) {
if(!config.webirc.enabled) return;
try { try {
fs.accessSync(webirc_data_path, fs.F_OK); fs.accessSync(webirc_data_path, fs.F_OK);
@ -73,7 +74,7 @@ function reload() {
} }
for(let adr in webirc_data) { for(let adr in webirc_data) {
resolveAddress(adr); resolveAddress(adr, force);
} }
} }
@ -105,11 +106,11 @@ module.exports = {
authenticator: WebIRCAuthenticator, authenticator: WebIRCAuthenticator,
get_password: get_password, get_password: get_password,
writeToFile: writeToFile writeToFile: writeToFile
} };
process.on('SIGUSR1', () => { process.on('SIGUSR1', () => {
console.log("!!! Received SIGUSR1; Reloading webirc data.. !!!"); logger.log("\n!!! Received SIGUSR1; Reloading webirc data.. !!!\n");
reload(); reload(true);
}); });
reload(); reload(false);

View File

@ -1,21 +1,23 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; 'use strict';
let express = require("express"); const express = require("express"),
let path = require("path"); path = require("path"),
let sockio = require("socket.io"); sockio = require("socket.io"),
let dns = require("dns"); dns = require("dns"),
let app = express(); app = express(),
let router = express.Router(); router = express.Router(),
let pubdir = path.join(__dirname, "public"); pubdir = path.join(__dirname, "public"),
let pkg = require(__dirname+"/package.json"); pkg = require(__dirname+"/package.json"),
config = require(__dirname+'/server/config'),
logger = require(__dirname+'/server/logger'),
port = config.server.port || 8080;
let config = require(__dirname+'/server/config');
let irclib = require(__dirname+'/server/teemant_irc'); let irclib = require(__dirname+'/server/teemant_irc');
let webirc = require(__dirname+'/server/webirc'); let webirc = require(__dirname+'/server/webirc');
let port = config.server.port || 8080;
let runtime_stats = { let runtime_stats = {
connectionsMade: 0 connectionsMade: 0
}; };
@ -45,31 +47,12 @@ app.use('/', express.static(pubdir, { maxAge: 365*24*60*60*1000 }));
app.use('/:server', express.static(pubdir, { maxAge: 365*24*60*60*1000 })); app.use('/:server', express.static(pubdir, { maxAge: 365*24*60*60*1000 }));
app.use('/', router); app.use('/', router);
function printRuntimeStats() { const io = sockio.listen(app.listen(port, function() {
let date = new Date(); logger.log("*** Listening on http://localhost:" + port + "/");
let users = 0;
let servers = 0;
let serversPerUser = 0;
for(let uid in connections) { setInterval(() => {
let ca = connections[uid]; logger.printRuntimeStats(runtime_stats, connections);
users += 1; }, 3600000);
for(let snam in ca) {
if(!snam) continue;
if(snam == "host") continue;
servers += 1;
}
}
if(users != 0) // Don't divide by zero lmao
serversPerUser = servers/users;
console.log(date+": Currently connected users: "+users+"; IRC server connections: "+servers+"; Average servers per user: "+serversPerUser+"; Total connections made: "+runtime_stats.connectionsMade);
}
let io = sockio.listen(app.listen(port, function() {
console.log("*** Listening on http://localhost:" + port + "/");
setInterval(printRuntimeStats, 3600000);
})); }));
function resolveHostname(ipaddr) { function resolveHostname(ipaddr) {
@ -89,8 +72,7 @@ io.sockets.on('connection', function (socket) {
if(userip.indexOf('::ffff:') == 0) if(userip.indexOf('::ffff:') == 0)
userip = userip.substring(7); userip = userip.substring(7);
if(config.server.debug) logger.debugLog('clientID: '+socket.id+' from: ', userip);
console.log('clientID: '+socket.id+' from: ', userip);
// New object for connections // New object for connections
connections[socket.id] = { connections[socket.id] = {
@ -106,12 +88,10 @@ io.sockets.on('connection', function (socket) {
if(arr.length > 0) if(arr.length > 0)
connections[socket.id].host.hostname = arr[0]; connections[socket.id].host.hostname = arr[0];
}).catch((err) => { }).catch((err) => {
if(config.server.debug) logger.debugLog("Host resolve for "+socket.id+" failed: ", err);
console.log("Host resolve for "+socket.id+" failed: ", err);
}); });
if(config.server.debug) logger.debugLog("Hostname of "+socket.id+" was determined to be "+connections[socket.id].host.hostname);
console.log("Hostname of "+socket.id+" was determined to be "+connections[socket.id].host.hostname);
socket.on('disconnect', function() { socket.on('disconnect', function() {
for (let d in connections[socket.id]) { for (let d in connections[socket.id]) {
@ -122,12 +102,11 @@ io.sockets.on('connection', function (socket) {
delete connections[socket.id]; delete connections[socket.id];
if(config.server.debug) logger.debugLog('clientID: '+socket.id+' disconnect');
console.log('clientID: '+socket.id+' disconnect');
}); });
socket.on('error', (e) => { socket.on('error', (e) => {
console.log(e); logger.errorLog(e, "Socket error");
}); });
socket.on('userinput', (data) => { socket.on('userinput', (data) => {
@ -135,20 +114,23 @@ io.sockets.on('connection', function (socket) {
if(!serv) return; if(!serv) return;
if(serv.authenticated == false) return; if(serv.authenticated == false) return;
if(config.server.debug) logger.debugLog("["+socket.id+"] ->", data);
console.log("["+socket.id+"] ->", data);
serv.handler.handleUserLine(data); serv.handler.handleUserLine(data);
}) })
socket.on('irc_create', function(connectiondata) { socket.on('irc_create', function(connectiondata) {
if(config.server.debug) logger.debugLog(socket.id+" created irc connection: ", connectiondata);
console.log(socket.id+" created irc connection: ", connectiondata);
socket.emit('act_client', {type: 'connect_message', message: "Connecting to server..", error: false}); socket.emit('act_client', {type: 'connect_message', message: "Connecting to server..", error: false});
let newConnection = new irclib.IRCConnection(connectiondata, config.client, let newConnection = new irclib.IRCConnection(connectiondata, config.client,
{authenticationSteps: [new webirc.authenticator(connections[socket.id].host)], ctcps: customCTCPs}); {
authenticationSteps: [
new webirc.authenticator(connections[socket.id].host)
],
ctcps: customCTCPs
});
newConnection.connect(); newConnection.connect();
@ -164,17 +146,16 @@ io.sockets.on('connection', function (socket) {
if(config.server.debug) { if(config.server.debug) {
newConnection.on('line', function(line) { newConnection.on('line', function(line) {
console.log("["+socket.id+"] <-", line); logger.debugLog("["+socket.id+"] <-", line);
}); });
newConnection.on('debug_log', function(data) { newConnection.on('debug_log', function(data) {
console.log("["+socket.id+"] <-", data); logger.debugLog("["+socket.id+"] <-", data);
}); });
} }
newConnection.on('connerror', (data) => { newConnection.on('connerror', (data) => {
if(config.server.debug) logger.debugLog(data);
console.log(data);
if(newConnection.authenticated == false) if(newConnection.authenticated == false)
socket.emit('act_client', {type: 'connect_message', server: connectiondata.server, socket.emit('act_client', {type: 'connect_message', server: connectiondata.server,
@ -186,8 +167,7 @@ io.sockets.on('connection', function (socket) {
}); });
newConnection.on('closed', (data) => { newConnection.on('closed', (data) => {
if(config.server.debug) logger.debugLog(data);
console.log(data);
if(newConnection.authenticated == false) if(newConnection.authenticated == false)
socket.emit('act_client', {type: 'connect_message', server: connectiondata.server, socket.emit('act_client', {type: 'connect_message', server: connectiondata.server,
@ -199,13 +179,13 @@ io.sockets.on('connection', function (socket) {
}); });
process.on('SIGINT', () => { process.on('SIGINT', () => {
console.log('!!! Received SIGINT; Terminating all IRC connections and exiting.. !!!'); logger.log('!!! Received SIGINT; Terminating all IRC connections and exiting.. !!!');
logger.printRuntimeStats(runtime_stats, connections);
for(let c in connections) { for(let c in connections) {
for(let ircconn in connections[c]) { for(let ircconn in connections[c]) {
if(connections[c][ircconn].ipaddr) continue; if(connections[c][ircconn].ipaddr) continue;
connections[c][ircconn].disconnect(); connections[c][ircconn].disconnect();
} }
} }
printRuntimeStats();
process.exit(); process.exit();
}); });