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