var util = require('util'),
events = require('events'),
- _ = require('underscore'),
- config = require('./configuration.js'),
+ crypto = require('crypto'),
+ _ = require('lodash'),
+ State = require('./irc/state.js'),
IrcConnection = require('./irc/connection.js').IrcConnection,
- IrcCommands = require('./irc/commands.js'),
- ClientCommands = require('./clientcommands.js');
+ ClientCommands = require('./clientcommands.js'),
+ WebsocketRpc = require('./websocketrpc.js');
var Client = function (websocket) {
var that = this;
-
+
events.EventEmitter.call(this);
this.websocket = websocket;
-
- this.irc_connections = [];
- this.next_connection = 0;
-
+ this.rpc = new WebsocketRpc(this.websocket);
+
+ // Clients address
+ this.real_address = this.websocket.kiwi.real_address;
+
+ // A hash to identify this client instance
+ this.hash = crypto.createHash('sha256')
+ .update(this.real_address)
+ .update('' + Date.now())
+ .update(Math.floor(Math.random() * 100000).toString())
+ .digest('hex');
+
+ this.state = new State(this);
+
this.buffer = {
list: [],
motd: ''
};
-
+
// Handler for any commands sent from the client
this.client_commands = new ClientCommands(this);
- websocket.on('irc', function () {
- handleClientMessage.apply(that, arguments);
+ this.rpc.on('irc', function (response, data) {
+ handleClientMessage.call(that, data, response);
});
- websocket.on('kiwi', function () {
- kiwiCommand.apply(that, arguments);
+ this.rpc.on('kiwi', function (response, data) {
+ kiwiCommand.call(that, data, response);
});
- websocket.on('disconnect', function () {
+ websocket.on('close', function () {
websocketDisconnect.apply(that, arguments);
});
websocket.on('error', function () {
websocketError.apply(that, arguments);
});
+
+ this.disposed = false;
};
util.inherits(Client, events.EventEmitter);
Client.prototype.sendIrcCommand = function (command, data, callback) {
var c = {command: command, data: data};
- this.websocket.emit('irc', c, callback);
+ this.rpc.call('irc', c, callback);
};
Client.prototype.sendKiwiCommand = function (command, data, callback) {
var c = {command: command, data: data};
- this.websocket.emit('kiwi', c, callback);
+ this.rpc.call('kiwi', c, callback);
+};
+
+Client.prototype.dispose = function () {
+ this.disposed = true;
+ this.emit('dispose');
+ this.removeAllListeners();
};
function handleClientMessage(msg, callback) {
- var server, args, obj, channels, keys;
+ var server;
// Make sure we have a server number specified
if ((msg.server === null) || (typeof msg.server !== 'number')) {
return (typeof callback === 'function') ? callback('server not specified') : undefined;
- } else if (!this.irc_connections[msg.server]) {
+ } else if (!this.state.irc_connections[msg.server]) {
return (typeof callback === 'function') ? callback('not connected to server') : undefined;
}
// The server this command is directed to
- server = this.irc_connections[msg.server];
+ server = this.state.irc_connections[msg.server];
if (typeof callback !== 'function') {
callback = null;
function kiwiCommand(command, callback) {
- var that = this;
-
if (typeof callback !== 'function') {
callback = function () {};
}
+
switch (command.command) {
- case 'connect':
- if (command.hostname && command.port && command.nick) {
- var con = new IrcConnection(command.hostname, command.port, command.ssl,
- command.nick, {hostname: this.websocket.handshake.revdns, address: this.websocket.handshake.address.address},
- command.password);
-
- var con_num = this.next_connection++;
- this.irc_connections[con_num] = con;
-
- var irc_commands = new IrcCommands(con, con_num, this);
- irc_commands.bindEvents();
-
- con.on('connected', function () {
- console.log("con.on('connected')");
- return callback(null, con_num);
- });
-
- con.on('error', function (err) {
- // TODO: Once multiple servers implemented, specify which server failed
- //that.sendKiwiCommand('error', {server: con_num, error: err});
- return callback(err.code, null);
- });
-
- con.on('close', function () {
- that.irc_connections[con_num] = null;
- });
- } else {
- return callback('Hostname, port and nickname must be specified');
- }
- break;
- default:
- callback();
+ case 'connect':
+ if (command.hostname && command.port && command.nick) {
+ var options = {};
+
+ // Get any optional parameters that may have been passed
+ if (command.encoding)
+ options.encoding = command.encoding;
+
+ options.password = global.config.restrict_server_password || command.password;
+
+ this.state.connect(
+ (global.config.restrict_server || command.hostname),
+ (global.config.restrict_server_port || command.port),
+ (typeof global.config.restrict_server_ssl !== 'undefined' ?
+ global.config.restrict_server_ssl :
+ command.ssl),
+ command.nick,
+ {hostname: this.websocket.kiwi.revdns, address: this.websocket.kiwi.real_address},
+ options,
+ callback);
+ } else {
+ return callback('Hostname, port and nickname must be specified');
+ }
+ break;
+ default:
+ callback();
}
-};
+}
// Websocket has disconnected, so quit all the IRC connections
function websocketDisconnect() {
- _.each(this.irc_connections, function (irc_connection, i, cons) {
- if (irc_connection) {
- irc_connection.end('QUIT :' + (config.get().quit_message || ''));
- cons[i] = null;
- }
- });
- this.emit('destroy');
-};
+ this.emit('disconnect');
+
+ this.dispose();
+}
// TODO: Should this close all the websocket connections too?
function websocketError() {
- this.emit('destroy');
-};
+ this.dispose();
+}