Clients side IRC event names normalised
[KiwiIRC.git] / client / src / models / gateway.js
1 _kiwi.model.Gateway = function () {
2
3 // Set to a reference to this object within initialize()
4 var that = null;
5
6 this.initialize = function () {
7 that = this;
8
9 // For ease of access. The socket.io object
10 this.socket = this.get('socket');
11
12 // Used to check if a disconnection was unplanned
13 this.disconnect_requested = false;
14 };
15
16
17
18 this.reconnect = function (callback) {
19 var that = this,
20 transport_path;
21
22 this.disconnect_requested = true;
23 this.socket.close();
24
25 this.socket = null;
26 this.connect(callback);
27 };
28
29
30
31 /**
32 * Connects to the server
33 * @param {Function} callback A callback function to be invoked once Kiwi's server has connected to the IRC server
34 */
35 this.connect = function (callback) {
36 this.connect_callback = callback;
37
38 // Keep note of the server we are connecting to
39 this.set('kiwi_server', _kiwi.app.kiwi_server);
40
41 this.socket = new EngineioTools.ReconnectingSocket(this.get('kiwi_server'), {
42 transports: _kiwi.app.server_settings.transports || ['websocket', 'polling'],
43 path: _kiwi.app.get('base_path') + '/transport',
44 reconnect_max_attempts: 5,
45 reconnect_delay: 2000
46 });
47
48 this.rpc = new EngineioTools.Rpc(this.socket);
49
50 this.socket.on('connect_failed', function (reason) {
51 this.socket.disconnect();
52 this.trigger("connect_fail", {reason: reason});
53 });
54
55 this.socket.on('error', function (e) {
56 console.log("_kiwi.gateway.socket.on('error')", {reason: e});
57 if (that.connect_callback) {
58 that.connect_callback(e);
59 delete that.connect_callback;
60 }
61
62 that.trigger("connect_fail", {reason: e});
63 });
64
65 this.socket.on('connecting', function (transport_type) {
66 console.log("_kiwi.gateway.socket.on('connecting')");
67 that.trigger("connecting");
68 });
69
70 /**
71 * Once connected to the kiwi server send the IRC connect command along
72 * with the IRC server details.
73 * A `connect` event is sent from the kiwi server once connected to the
74 * IRCD and the nick has been accepted.
75 */
76 this.socket.on('open', function () {
77 // Reset the disconnect_requested flag
78 that.disconnect_requested = false;
79
80 console.log("_kiwi.gateway.socket.on('open')");
81 });
82
83 this.rpc.on('too_many_connections', function () {
84 that.trigger("connect_fail", {reason: 'too_many_connections'});
85 });
86
87 this.rpc.on('irc', function (response, data) {
88 that.parse(data.command, data.data);
89 });
90
91 this.rpc.on('kiwi', function (response, data) {
92 that.parseKiwi(data.command, data.data);
93 });
94
95 this.socket.on('close', function () {
96 that.trigger("disconnect", {});
97 console.log("_kiwi.gateway.socket.on('close')");
98 });
99
100 this.socket.on('reconnecting', function (status) {
101 console.log("_kiwi.gateway.socket.on('reconnecting')");
102 that.trigger("reconnecting", {delay: status.delay, attempts: status.attempts});
103 });
104
105 this.socket.on('reconnecting_failed', function () {
106 console.log("_kiwi.gateway.socket.on('reconnect_failed')");
107 });
108 };
109
110
111 /**
112 * Return a new network object with the new connection details
113 */
114 this.newConnection = function(connection_info, callback_fn) {
115 var that = this;
116
117 // If not connected, connect first then re-call this function
118 if (!this.isConnected()) {
119 this.connect(function(err) {
120 if (err) {
121 callback_fn(err);
122 return;
123 }
124
125 that.newConnection(connection_info, callback_fn);
126 });
127
128 return;
129 }
130
131 this.makeIrcConnection(connection_info, function(err, server_num) {
132 var connection;
133
134 if (!err) {
135 if (!_kiwi.app.connections.getByConnectionId(server_num)){
136 var inf = {
137 connection_id: server_num,
138 nick: connection_info.nick,
139 address: connection_info.host,
140 port: connection_info.port,
141 ssl: connection_info.ssl,
142 password: connection_info.password
143 };
144 connection = new _kiwi.model.Network(inf);
145 _kiwi.app.connections.add(connection);
146 }
147
148 console.log("_kiwi.gateway.socket.on('connect')", connection);
149 callback_fn && callback_fn(err, connection);
150
151 } else {
152 console.log("_kiwi.gateway.socket.on('error')", {reason: err});
153 callback_fn && callback_fn(err);
154 }
155 });
156 };
157
158
159 /**
160 * Make a new IRC connection and return its connection ID
161 */
162 this.makeIrcConnection = function(connection_info, callback_fn) {
163 var server_info = {
164 command: 'connect',
165 nick: connection_info.nick,
166 hostname: connection_info.host,
167 port: connection_info.port,
168 ssl: connection_info.ssl,
169 password: connection_info.password
170 };
171
172 connection_info.options = connection_info.options || {};
173
174 // A few optional parameters
175 if (connection_info.options.encoding)
176 server_info.encoding = connection_info.options.encoding;
177
178 this.rpc.call('kiwi', server_info, function (err, server_num) {
179 if (!err) {
180 callback_fn && callback_fn(err, server_num);
181
182 } else {
183 callback_fn && callback_fn(err);
184 }
185 });
186 };
187
188
189 this.isConnected = function () {
190 // TODO: Check this. Might want to use .readyState
191 return this.socket;
192 };
193
194
195
196 this.parseKiwi = function (command, data) {
197 var client_info_data;
198
199 this.trigger('kiwi:' + command, data);
200 this.trigger('kiwi', data);
201
202 switch (command) {
203 case 'connected':
204 // Send some info on this client to the server
205 client_info_data = {
206 command: 'client_info',
207 build_version: _kiwi.global.build_version
208 };
209 this.rpc.call('kiwi', client_info_data);
210
211 this.connect_callback && this.connect_callback();
212 delete this.connect_callback;
213
214 break;
215 }
216 };
217 /*
218 Events:
219 msg
220 action
221 server_connect
222 options
223 motd
224 notice
225 userlist
226 nick
227 join
228 topic
229 part
230 kick
231 quit
232 whois
233 syncchannel_redirect
234 debug
235 */
236 /**
237 * Parses the response from the server
238 */
239 this.parse = function (command, data) {
240 //console.log('gateway event', command, data);
241
242 if (command !== undefined) {
243 switch (command) {
244 case 'options':
245 $.each(data.options, function (name, value) {
246 switch (name) {
247 case 'CHANTYPES':
248 that.set('channel_prefix', value.join(''));
249 break;
250 case 'NETWORK':
251 that.set('name', value);
252 break;
253 case 'PREFIX':
254 that.set('user_prefixes', value);
255 break;
256 }
257 });
258 that.set('cap', data.cap);
259 break;
260
261 /*
262 case 'sync':
263 if (_kiwi.gateway.onSync && _kiwi.gateway.syncing) {
264 _kiwi.gateway.syncing = false;
265 _kiwi.gateway.onSync(item);
266 }
267 break;
268 */
269
270 case 'kiwi':
271 this.emit('_kiwi.' + data.namespace, data.data);
272 break;
273 }
274 }
275
276
277 // Trigger the connection specific events (used by Network objects)
278 if (typeof data.server !== 'undefined') {
279 that.trigger('connection:' + data.server.toString(), {
280 event_name: command,
281 event_data: data
282 });
283 }
284
285 // Trigger the global events
286 that.trigger(command, data);
287 };
288
289 /**
290 * Sends data to the server
291 * @private
292 * @param {Object} data The data to send
293 * @param {Function} callback A callback function
294 */
295 this.sendData = function (connection_id, data, callback) {
296 if (typeof connection_id === 'undefined' || connection_id === null)
297 connection_id = _kiwi.app.connections.active_connection.get('connection_id');
298
299 var data_buffer = {
300 server: connection_id,
301 data: JSON.stringify(data)
302 };
303 this.rpc.call('irc', data_buffer, callback);
304 };
305
306 /**
307 * Sends a PRIVMSG message
308 * @param {String} target The target of the message (e.g. a channel or nick)
309 * @param {String} msg The message to send
310 * @param {Function} callback A callback function
311 */
312 this.privmsg = function (connection_id, target, msg, callback) {
313 var data = {
314 method: 'privmsg',
315 args: {
316 target: target,
317 msg: msg
318 }
319 };
320
321 this.sendData(connection_id, data, callback);
322 };
323
324 /**
325 * Sends a NOTICE message
326 * @param {String} target The target of the message (e.g. a channel or nick)
327 * @param {String} msg The message to send
328 * @param {Function} callback A callback function
329 */
330 this.notice = function (connection_id, target, msg, callback) {
331 var data = {
332 method: 'notice',
333 args: {
334 target: target,
335 msg: msg
336 }
337 };
338
339 this.sendData(connection_id, data, callback);
340 };
341
342 /**
343 * Sends a CTCP message
344 * @param {Boolean} request Indicates whether this is a CTCP request (true) or reply (false)
345 * @param {String} type The type of CTCP message, e.g. 'VERSION', 'TIME', 'PING' etc.
346 * @param {String} target The target of the message, e.g a channel or nick
347 * @param {String} params Additional paramaters
348 * @param {Function} callback A callback function
349 */
350 this.ctcp = function (connection_id, request, type, target, params, callback) {
351 var data = {
352 method: 'ctcp',
353 args: {
354 request: request,
355 type: type,
356 target: target,
357 params: params
358 }
359 };
360
361 this.sendData(connection_id, data, callback);
362 };
363
364 /**
365 * @param {String} target The target of the message (e.g. a channel or nick)
366 * @param {String} msg The message to send
367 * @param {Function} callback A callback function
368 */
369 this.action = function (connection_id, target, msg, callback) {
370 this.ctcp(connection_id, true, 'ACTION', target, msg, callback);
371 };
372
373 /**
374 * Joins a channel
375 * @param {String} channel The channel to join
376 * @param {String} key The key to the channel
377 * @param {Function} callback A callback function
378 */
379 this.join = function (connection_id, channel, key, callback) {
380 var data = {
381 method: 'join',
382 args: {
383 channel: channel,
384 key: key
385 }
386 };
387
388 this.sendData(connection_id, data, callback);
389 };
390
391 /**
392 * Retrieves channel information
393 */
394 this.channelInfo = function (connection_id, channel, callback) {
395 var data = {
396 method: 'channel_info',
397 args: {
398 channel: channel
399 }
400 };
401
402 this.sendData(connection_id, data, callback);
403 };
404
405 /**
406 * Leaves a channel
407 * @param {String} channel The channel to part
408 * @param {Function} callback A callback function
409 */
410 this.part = function (connection_id, channel, callback) {
411 var data = {
412 method: 'part',
413 args: {
414 channel: channel
415 }
416 };
417
418 this.sendData(connection_id, data, callback);
419 };
420
421 /**
422 * Queries or modifies a channell topic
423 * @param {String} channel The channel to query or modify
424 * @param {String} new_topic The new topic to set
425 * @param {Function} callback A callback function
426 */
427 this.topic = function (connection_id, channel, new_topic, callback) {
428 var data = {
429 method: 'topic',
430 args: {
431 channel: channel,
432 topic: new_topic
433 }
434 };
435
436 this.sendData(connection_id, data, callback);
437 };
438
439 /**
440 * Kicks a user from a channel
441 * @param {String} channel The channel to kick the user from
442 * @param {String} nick The nick of the user to kick
443 * @param {String} reason The reason for kicking the user
444 * @param {Function} callback A callback function
445 */
446 this.kick = function (connection_id, channel, nick, reason, callback) {
447 var data = {
448 method: 'kick',
449 args: {
450 channel: channel,
451 nick: nick,
452 reason: reason
453 }
454 };
455
456 this.sendData(connection_id, data, callback);
457 };
458
459 /**
460 * Disconnects us from the server
461 * @param {String} msg The quit message to send to the IRC server
462 * @param {Function} callback A callback function
463 */
464 this.quit = function (connection_id, msg, callback) {
465 msg = msg || "";
466 var data = {
467 method: 'quit',
468 args: {
469 message: msg
470 }
471 };
472
473 this.sendData(connection_id, data, callback);
474 };
475
476 /**
477 * Sends a string unmodified to the IRC server
478 * @param {String} data The data to send to the IRC server
479 * @param {Function} callback A callback function
480 */
481 this.raw = function (connection_id, data, callback) {
482 data = {
483 method: 'raw',
484 args: {
485 data: data
486 }
487 };
488
489 this.sendData(connection_id, data, callback);
490 };
491
492 /**
493 * Changes our nickname
494 * @param {String} new_nick Our new nickname
495 * @param {Function} callback A callback function
496 */
497 this.changeNick = function (connection_id, new_nick, callback) {
498 var data = {
499 method: 'nick',
500 args: {
501 nick: new_nick
502 }
503 };
504
505 this.sendData(connection_id, data, callback);
506 };
507
508 /**
509 * Sets a mode for a target
510 */
511 this.mode = function (connection_id, target, mode_string, callback) {
512 data = {
513 method: 'raw',
514 args: {
515 data: 'MODE ' + target + ' ' + mode_string
516 }
517 };
518
519 this.sendData(connection_id, data, callback);
520 };
521
522
523 /**
524 * Sends ENCODING change request to server.
525 * @param {String} new_encoding The new proposed encode
526 * @param {Fucntion} callback A callback function
527 */
528 this.setEncoding = function (connection_id, new_encoding, callback) {
529 var data = {
530 method: 'encoding',
531 args: {
532 encoding: new_encoding
533 }
534 };
535 this.sendData(connection_id, data, callback);
536 };
537
538 /**
539 * Sends data to a fellow Kiwi IRC user
540 * @param {String} target The nick of the Kiwi IRC user to send to
541 * @param {String} data The data to send
542 * @param {Function} callback A callback function
543 */
544 this.kiwi = function (target, data, callback) {
545 data = {
546 method: 'kiwi',
547 args: {
548 target: target,
549 data: data
550 }
551 };
552
553 this.sendData(data, callback);
554 };
555
556
557 return new (Backbone.Model.extend(this))(arguments);
558 };