Merge branch 'backbone_ui' of github.com:prawnsalad/KiwiIRC into backbone_ui
[KiwiIRC.git] / server / client.js
1 var util = require('util'),
2 events = require('events'),
3 IRCConnection = require('./irc-connection.js').IRCConnection;
4 IRCCommands = require('./irc-commands.js'),
5 ClientCommandset = require('./client-commands.js').ClientCommandset;
6
7 var Client = function (websocket) {
8 var c = this;
9
10 events.EventEmitter.call(this);
11 this.websocket = websocket;
12
13 this.IRC_connections = [];
14 this.next_connection = 0;
15
16 this.buffer = {
17 list: [],
18 motd: ''
19 };
20
21 // Handler for any commands sent from the client
22 this.client_commands = new ClientCommandset(this);
23
24 websocket.on('irc', function () {
25 handleClientMessage.apply(c, arguments);
26 });
27 websocket.on('kiwi', function () {
28 kiwi_command.apply(c, arguments);
29 });
30 websocket.on('disconnect', function () {
31 disconnect.apply(c, arguments);
32 });
33 websocket.on('error', function () {
34 error.apply(c, arguments);
35 });
36 };
37 util.inherits(Client, events.EventEmitter);
38
39 module.exports.Client = Client;
40
41 // Callback API:
42 // Callbacks SHALL accept 2 arguments, error and response, in that order.
43 // error MUST be null where the command is successul.
44 // error MUST otherwise be a truthy value and SHOULD be a string where the cause of the error is known.
45 // response MAY be given even if error is truthy
46
47 Client.prototype.sendIRCCommand = function (command, data, callback) {
48 var c = {command: command, data: data};
49 console.log('C<--', c);
50 this.websocket.emit('irc', c, callback);
51 };
52
53 Client.prototype.sendKiwiCommand = function (command, callback) {
54 this.websocket.emit('kiwi', command, callback);
55 };
56
57 var handleClientMessage = function (msg, callback) {
58 var server, args, obj, channels, keys;
59
60 // Make sure we have a server number specified
61 if ((msg.server === null) || (typeof msg.server !== 'number')) {
62 return callback('server not specified');
63 } else if (!this.IRC_connections[msg.server]) {
64 return callback('not connected to server');
65 }
66
67 // The server this command is directed to
68 server = this.IRC_connections[msg.server];
69
70 if (typeof callback !== 'function') {
71 callback = null;
72 }
73
74 try {
75 msg.data = JSON.parse(msg.data);
76 } catch (e) {
77 kiwi.log('[handleClientMessage] JSON parsing error ' + msg.data);
78 return;
79 }
80
81 // Run the client command
82 this.client_commands.run(msg.data.method, msg.data.args, server, callback);
83 };
84
85
86
87
88 var kiwi_command = function (command, callback) {
89 var that = this;
90 console.log(typeof callback);
91 if (typeof callback !== 'function') {
92 callback = function () {};
93 }
94 switch (command.command) {
95 case 'connect':
96 if ((command.hostname) && (command.port) && (command.nick)) {
97 var con = new IRCConnection(command.hostname, command.port, command.ssl,
98 command.nick, {hostname: this.websocket.handshake.revdns, address: this.websocket.handshake.address.address},
99 command.password, null);
100
101 var con_num = this.next_connection++;
102 this.IRC_connections[con_num] = con;
103
104 var binder = new IRCCommands.Binder(con, con_num, this);
105 binder.bind_irc_commands();
106
107 con.on('connected', function () {
108 console.log("con.on('connected')");
109 return callback(null, con_num);
110 });
111
112 con.on('error', function (err) {
113 this.websocket.sendKiwiCommand('error', {server: con_num, error: err});
114 });
115
116 con.on('close', function () {
117 that.IRC_connections[con_num] = null;
118 });
119 } else {
120 return callback('Hostname, port and nickname must be specified');
121 }
122 break;
123 default:
124 callback();
125 }
126 };
127
128 var extension_command = function (command, callback) {
129 if (typeof callback === 'function') {
130 callback('not implemented');
131 }
132 };
133
134 var disconnect = function () {
135 _.each(this.IRC_connections, function (irc_connection, i, cons) {
136 if (irc_connection) {
137 irc_connection.end('QUIT :Kiwi IRC');
138 cons[i] = null;
139 }
140 });
141 this.emit('destroy');
142 };
143
144 var error = function () {
145 this.emit('destroy');
146 };