X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=server%2Fkiwi.js;h=58df8106a84b64f3c9f39b172137cdd33d372dff;hb=24dd1faa442897b5b915977f2dfb4880dc33c807;hp=26d5b9c14b06d7c8c43b2636ac61f97f87a91bd6;hpb=645fe41b105a0d29f28e4f7f4928fe760b4fd0b1;p=KiwiIRC.git diff --git a/server/kiwi.js b/server/kiwi.js index 26d5b9c..58df810 100755 --- a/server/kiwi.js +++ b/server/kiwi.js @@ -1,16 +1,33 @@ var fs = require('fs'), _ = require('lodash'), util = require('util'), + winston = require('winston'), WebListener = require('./weblistener.js'), config = require('./configuration.js'), - rehash = require('./rehash.js'), modules = require('./modules.js'), - Identd = require('./identd.js'); + Identd = require('./identd.js'), + Proxy = require('./proxy.js'), + ControlInterface = require('./controlinterface.js'); process.chdir(__dirname + '/../'); -config.loadConfig(); + +// Get our own version from package.json +global.build_version = require('../package.json').version; + +// Load the config, using -c argument if available +(function (argv) { + var conf_switch = argv.indexOf('-c'); + if (conf_switch !== -1) { + if (argv[conf_switch + 1]) { + return config.loadConfig(argv[conf_switch + 1]); + } + } + + config.loadConfig(); + +})(process.argv); // If we're not running in the forground and we have a log file.. switch @@ -23,22 +40,32 @@ if (process.argv.indexOf('-f') === -1 && global.config && global.config.log) { log_file_name = __dirname + '/../' + log_file_name; } + winston.add(winston.transports.File, { + filename: log_file_name, + json: false, + timestamp: function() { + var year, month, day, time_string, + d = new Date(); + year = String(d.getFullYear()); + month = String(d.getMonth() + 1); + if (month.length === 1) { + month = "0" + month; + } - console.log = function() { - var logfile = fs.openSync(log_file_name, 'a'), - out; + day = String(d.getDate()); + if (day.length === 1) { + day = "0" + day; + } - out = util.format.apply(util, arguments); + // Take the time from the existing toTimeString() format + time_string = (new Date()).toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1"); - // Make sure we out somthing to log and we have an open file - if (!out || !logfile) return; - - out += '\n'; - fs.writeSync(logfile, out, null); + return year + "-" + month + "-" + day + ' ' + time_string; + } + }); - fs.closeSync(logfile); - }; + winston.remove(winston.transports.Console); })(); } @@ -46,12 +73,12 @@ if (process.argv.indexOf('-f') === -1 && global.config && global.config.log) { // Make sure we have a valid config file and at least 1 server if (!global.config || Object.keys(global.config).length === 0) { - console.log('Couldn\'t find a valid config.js file (Did you copy the config.example.js file yet?)'); + winston.error('Couldn\'t find a valid config.js file (Did you copy the config.example.js file yet?)'); process.exit(1); } if ((!global.config.servers) || (global.config.servers.length < 1)) { - console.log('No servers defined in config file'); + winston.error('No servers defined in config file'); process.exit(2); } @@ -68,9 +95,9 @@ modules.registerPublisher(global.modules); if (global.config.module_dir) { (global.config.modules || []).forEach(function (module_name) { if (modules.load(module_name)) { - console.log('Module ' + module_name + ' loaded successfuly'); + winston.info('Module %s loaded successfully', module_name); } else { - console.log('Module ' + module_name + ' failed to load'); + winston.warn('Module %s failed to load', module_name); } }); } @@ -111,12 +138,52 @@ global.clients = { } else { return 0; } + }, + + broadcastKiwiCommand: function (command, data, callback) { + var clients = []; + + // Get an array of clients for us to work with + for (var client in global.clients.clients) { + clients.push(global.clients.clients[client]); + } + + + // Sending of the command in batches + var sendCommandBatch = function (list) { + var batch_size = 100, + cutoff; + + if (list.length >= batch_size) { + // If we have more clients than our batch size, call ourself with the next batch + setTimeout(function () { + sendCommandBatch(list.slice(batch_size)); + }, 200); + + cutoff = batch_size; + + } else { + cutoff = list.length; + } + + list.slice(0, cutoff).forEach(function (client) { + if (!client.disposed) { + client.sendKiwiCommand(command, data); + } + }); + + if (cutoff === list.length && typeof callback === 'function') { + callback(); + } + }; + + sendCommandBatch(clients); } }; global.servers = { servers: Object.create(null), - + addConnection: function (connection) { var host = connection.irc_host.hostname; if (!this.servers[host]) { @@ -124,7 +191,7 @@ global.servers = { } this.servers[host].push(connection); }, - + removeConnection: function (connection) { var host = connection.irc_host.hostname if (this.servers[host]) { @@ -134,7 +201,7 @@ global.servers = { } } }, - + numOnHost: function (host) { if (this.servers[host]) { return this.servers[host].length; @@ -146,10 +213,12 @@ global.servers = { +/** + * When a new config is loaded, send out an alert to the clients so + * so they can reload it + */ config.on('loaded', function () { - for (var client in global.clients.clients) { - global.clients.clients[client].sendKiwiCommand('reconfig'); - } + global.clients.broadcastKiwiCommand('reconfig'); }); @@ -187,26 +256,52 @@ if (global.config.identd && global.config.identd.enabled) { // Start up a weblistener for each found in the config _.each(global.config.servers, function (server) { - var wl = new WebListener(server, global.config.transports); + if (server.type == 'proxy') { + // Start up a kiwi proxy server + var serv = new Proxy.ProxyServer(); + serv.listen(server.port, server.address, server); - wl.on('connection', function (client) { - clients.add(client); - }); + serv.on('listening', function() { + winston.info('Kiwi proxy listening on %s:%s %s SSL', server.address, server.port, (server.ssl ? 'with' : 'without')); + }); - wl.on('client_dispose', function (client) { - clients.remove(client); - }); + serv.on('socket_connected', function(pipe) { + // SSL connections have the raw socket as a property + var socket = pipe.irc_socket.socket ? + pipe.irc_socket.socket : + pipe.irc_socket; - wl.on('listening', function () { - console.log('Listening on %s:%s %s SSL', server.address, server.port, (server.ssl ? 'with' : 'without')); - webListenerRunning(); - }); + pipe.identd_pair = socket.localPort.toString() + '_' + socket.remotePort.toString(); + global.clients.port_pairs[pipe.identd_pair] = pipe.meta; + }); - wl.on('error', function (err) { - console.log('Error listening on %s:%s: %s', server.address, server.port, err.code); - // TODO: This should probably be refactored. ^JA - webListenerRunning(); - }); + serv.on('connection_close', function(pipe) { + delete global.clients.port_pairs[pipe.identd_pair]; + }); + + } else { + // Start up a kiwi web server + var wl = new WebListener(server, global.config.transports); + + wl.on('connection', function (client) { + clients.add(client); + }); + + wl.on('client_dispose', function (client) { + clients.remove(client); + }); + + wl.on('listening', function () { + winston.info('Listening on %s:%s %s SSL', server.address, server.port, (server.ssl ? 'with' : 'without')); + webListenerRunning(); + }); + + wl.on('error', function (err) { + winston.info('Error listening on %s:%s: %s', server.address, server.port, err.code); + // TODO: This should probably be refactored. ^JA + webListenerRunning(); + }); + } }); // Once all the listeners are listening, set the processes UID/GID @@ -241,59 +336,27 @@ function setProcessUid() { // Make sure Kiwi doesn't simply quit on an exception process.on('uncaughtException', function (e) { - console.log('[Uncaught exception] ' + e); - console.log(e.stack); + winston.error('[Uncaught exception] %s', e, {stack: e.stack}); }); process.on('SIGUSR1', function() { if (config.loadConfig()) { - console.log('New config file loaded'); + winston.info('New config file loaded'); } else { - console.log("No new config file was loaded"); + winston.info('No new config file was loaded'); } }); process.on('SIGUSR2', function() { - console.log('Connected clients: ' + _.size(global.clients.clients).toString()); - console.log('Num. remote hosts: ' + _.size(global.clients.addresses).toString()); + winston.info('Connected clients: %s', _.size(global.clients.clients)); + winston.info('Num. remote hosts: %s', _.size(global.clients.addresses)); }); /* * Listen for runtime commands */ - process.stdin.resume(); -process.stdin.on('data', function (buffered) { - var data = buffered.toString().trim(); - - switch (data) { - case 'stats': - console.log('Connected clients: ' + _.size(global.clients.clients).toString()); - console.log('Num. remote hosts: ' + _.size(global.clients.addresses).toString()); - break; - - case 'reconfig': - if (config.loadConfig()) { - console.log('New config file loaded'); - } else { - console.log("No new config file was loaded"); - } - - break; - - - case 'rehash': - (function () { - rehash.rehashAll(); - console.log('Rehashed'); - })(); - - break; - - default: - console.log('Unrecognised command: ' + data); - } -}); +new ControlInterface(process.stdin, process.stdout, {prompt: ''});