Tweaking SocksConnection internals/API
[KiwiIRC.git] / server / irc / connection.js
index 0d927c22ab6861639c07596583c6f2c1598e9791..ce24ece4a75d54eb8fd2c98286e887ab4705229c 100644 (file)
@@ -1,13 +1,22 @@
-var net     = require('net'),
-    tls     = require('tls'),
-    events  = require('events'),
-    util    = require('util'),
-    _       = require('lodash');
+var net             = require('net'),
+    tls             = require('tls'),
+    util            = require('util'),
+    _               = require('lodash'),
+    EventEmitter2   = require('eventemitter2').EventEmitter2,
+    EventBinder     = require('./eventbinder.js'),
+    IrcServer       = require('./server.js'),
+    IrcChannel      = require('./channel.js'),
+    IrcUser         = require('./user.js');
 
 
 var IrcConnection = function (hostname, port, ssl, nick, user, pass, state) {
     var that = this;
-    events.EventEmitter.call(this);
+
+    EventEmitter2.call(this,{
+        wildcard: true,
+        delimiter: ':'
+    });
+    this.setMaxListeners(0);
     
     // Socket state
     this.connected = false;
@@ -26,6 +35,15 @@ var IrcConnection = function (hostname, port, ssl, nick, user, pass, state) {
     
     // State object
     this.state = state;
+    
+    // IrcServer object
+    this.server = new IrcServer(this, hostname, port);
+    
+    // IrcUser objects
+    this.irc_users = Object.create(null);
+    
+    // IrcChannel objects
+    this.irc_channels = Object.create(null);
 
     // IRC connection information
     this.irc_host = {hostname: hostname, port: port};
@@ -42,6 +60,7 @@ var IrcConnection = function (hostname, port, ssl, nick, user, pass, state) {
     this.hold_last = false;
     this.held_data = '';
 
+    this.applyIrcEvents();
 
     // Call any modules before making the connection
     global.modules.emit('irc:connecting', {connection: this})
@@ -49,12 +68,29 @@ var IrcConnection = function (hostname, port, ssl, nick, user, pass, state) {
             that.connect();
         });
 };
-util.inherits(IrcConnection, events.EventEmitter);
+util.inherits(IrcConnection, EventEmitter2);
 
 module.exports.IrcConnection = IrcConnection;
 
 
 
+IrcConnection.prototype.applyIrcEvents = function () {
+    // Listen for events on the IRC connection
+    this.irc_events = {
+        'server:*:connect':  onServerConnect,
+        'channel:*:join':    onChannelJoin,
+
+        // TODO: uncomment when using an IrcUser per nick
+        //'user:*:privmsg':    onUserPrivmsg,
+        'user:*:nick':       onUserNick,
+        'channel:*:part':    onUserParts,
+        'channel:*:quit':    onUserParts,
+        'channel:*:kick':    onUserParts
+    };
+
+    EventBinder.bindIrcEvents('', this.irc_events, this, this);
+};
+
 
 /**
  * Start the connection to the IRCd
@@ -111,7 +147,13 @@ IrcConnection.prototype.connect = function () {
     });
 };
 
-
+/**
+ * Send an event to the client
+ */
+IrcConnection.prototype.clientEvent = function (event_name, data, callback) {
+    data.server = this.con_num;
+    this.state.sendIrcCommand(event_name, data, callback);
+};
 
 /**
  * Write a line of data to the IRCd
@@ -138,6 +180,20 @@ IrcConnection.prototype.end = function (data, callback) {
  * Clean up this IrcConnection instance and any sockets
  */
 IrcConnection.prototype.dispose = function () {
+    _.each(this.irc_users, function (user) {
+        user.dispose();
+    });
+    _.each(this.irc_channels, function (chan) {
+        chan.dispose();
+    });
+    this.irc_users = undefined;
+    this.irc_channels = undefined;
+
+    this.server.dispose();
+    this.server = undefined;
+
+    EventBinder.unbindIrcEvents('', this.irc_events, this);
+
     this.disposeSocket();
     this.removeAllListeners();
 };
@@ -149,6 +205,7 @@ IrcConnection.prototype.dispose = function () {
  */
 IrcConnection.prototype.disposeSocket = function () {
     if (this.socket) {
+        this.socket.end();
         this.socket.removeAllListeners();
         this.socket = null;
     }
@@ -156,6 +213,73 @@ IrcConnection.prototype.disposeSocket = function () {
 
 
 
+function onChannelJoin(event) {
+    var chan;
+
+    // Only deal with ourselves joining a channel
+    if (event.nick !== this.nick)
+        return;
+
+    // We should only ever get a JOIN command for a channel
+    // we're not already a member of.. but check we don't
+    // have this channel in case something went wrong somewhere
+    // at an earlier point
+    if (!this.irc_channels[event.channel]) {
+        chan = new IrcChannel(this, event.channel);
+        this.irc_channels[event.channel] = chan;
+        chan.irc_events.join.call(chan, event);
+    }
+}
+
+
+function onServerConnect(event) {
+    this.nick = event.nick;
+
+    // TODO: use `event.nick` instead of `'*'` when using an IrcUser per nick
+    this.irc_users[event.nick] = new IrcUser(this, '*');
+}
+
+
+function onUserPrivmsg(event) {
+    var user;
+
+    // Only deal with messages targetted to us
+    if (event.channel !== this.nick)
+        return;
+
+    if (!this.irc_users[event.nick]) {
+        user = new IrcUser(this, event.nick);
+        this.irc_users[event.nick] = user;
+        user.irc_events.privmsg.call(user, event);
+    }
+}
+
+
+function onUserNick(event) {
+    var user;
+
+    // Only deal with messages targetted to us
+    if (event.nick !== this.nick)
+        return;
+
+    this.nick = event.newnick;
+}
+
+
+function onUserParts(event) {
+    // Only deal with ourselves leaving a channel
+    if (event.nick !== this.nick)
+        return;
+
+    if (this.irc_channels[event.channel]) {
+        this.irc_channels[event.channel].dispose();
+        delete this.irc_channels[event.channel];
+    }
+}
+
+
+
+
 /**
  * Handle the socket connect event, starting the IRCd registration
  */