Remove event bindings from commands.js
[KiwiIRC.git] / server / client.js
1 var util = require('util'),
2 events = require('events'),
3 crypto = require('crypto'),
4 _ = require('lodash'),
5 State = require('./irc/state.js');
6 IrcConnection = require('./irc/connection.js').IrcConnection,
7 ClientCommands = require('./clientcommands.js');
8
9
10 var Client = function (websocket) {
11 var that = this;
12
13 events.EventEmitter.call(this);
14 this.websocket = websocket;
15
16 // Clients address
17 this.real_address = this.websocket.handshake.real_address;
18
19 // A hash to identify this client instance
20 this.hash = crypto.createHash('sha256')
21 .update(this.real_address)
22 .update('' + Date.now())
23 .update(Math.floor(Math.random() * 100000).toString())
24 .digest('hex');
25
26 this.state = new State(this);
27
28 this.buffer = {
29 list: [],
30 motd: ''
31 };
32
33 // Handler for any commands sent from the client
34 this.client_commands = new ClientCommands(this);
35
36 websocket.on('irc', function () {
37 handleClientMessage.apply(that, arguments);
38 });
39 websocket.on('kiwi', function () {
40 kiwiCommand.apply(that, arguments);
41 });
42 websocket.on('disconnect', function () {
43 websocketDisconnect.apply(that, arguments);
44 });
45 websocket.on('error', function () {
46 websocketError.apply(that, arguments);
47 });
48 };
49 util.inherits(Client, events.EventEmitter);
50
51 module.exports.Client = Client;
52
53 // Callback API:
54 // Callbacks SHALL accept 2 arguments, error and response, in that order.
55 // error MUST be null where the command is successul.
56 // error MUST otherwise be a truthy value and SHOULD be a string where the cause of the error is known.
57 // response MAY be given even if error is truthy
58
59 Client.prototype.sendIrcCommand = function (command, data, callback) {
60 var c = {command: command, data: data};
61 this.websocket.emit('irc', c, callback);
62 };
63
64 Client.prototype.sendKiwiCommand = function (command, data, callback) {
65 var c = {command: command, data: data};
66 this.websocket.emit('kiwi', c, callback);
67 };
68
69 Client.prototype.dispose = function () {
70 this.emit('dispose');
71 this.removeAllListeners();
72 };
73
74 function handleClientMessage(msg, callback) {
75 var server, args, obj, channels, keys;
76
77 // Make sure we have a server number specified
78 if ((msg.server === null) || (typeof msg.server !== 'number')) {
79 return (typeof callback === 'function') ? callback('server not specified') : undefined;
80 } else if (!this.state.irc_connections[msg.server]) {
81 return (typeof callback === 'function') ? callback('not connected to server') : undefined;
82 }
83
84 // The server this command is directed to
85 server = this.state.irc_connections[msg.server];
86
87 if (typeof callback !== 'function') {
88 callback = null;
89 }
90
91 try {
92 msg.data = JSON.parse(msg.data);
93 } catch (e) {
94 kiwi.log('[handleClientMessage] JSON parsing error ' + msg.data);
95 return;
96 }
97
98 // Run the client command
99 this.client_commands.run(msg.data.method, msg.data.args, server, callback);
100 }
101
102
103
104
105 function kiwiCommand(command, callback) {
106 var that = this;
107
108 if (typeof callback !== 'function') {
109 callback = function () {};
110 }
111 switch (command.command) {
112 case 'connect':
113 if (command.hostname && command.port && command.nick) {
114 var con;
115
116 this.state.connect(
117 (global.config.restrict_server || command.hostname),
118 (global.config.restrict_server_port || command.port),
119 (global.config.restrict_server_ssl || command.ssl),
120 command.nick,
121 {hostname: this.websocket.handshake.revdns, address: this.websocket.handshake.real_address},
122 (global.config.restrict_server_password || command.password),
123 callback);
124 } else {
125 return callback('Hostname, port and nickname must be specified');
126 }
127 break;
128 default:
129 callback();
130 }
131 }
132
133
134 // Websocket has disconnected, so quit all the IRC connections
135 function websocketDisconnect() {
136 this.emit('disconnect');
137
138 this.dispose();
139 }
140
141
142 // TODO: Should this close all the websocket connections too?
143 function websocketError() {
144 this.dispose();
145 }