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