Renaming kiwi.connect to kiwi.connect_irc #509
[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 WebsocketRpc = require('./websocketrpc.js');
9
10
11 var Client = function (websocket) {
12 var that = this;
13
14 events.EventEmitter.call(this);
15 this.websocket = websocket;
16 this.rpc = new WebsocketRpc(this.websocket);
17
18 // Clients address
19 this.real_address = this.websocket.meta.real_address;
20
21 // A hash to identify this client instance
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');
27
28 this.state = new State(this);
29
30 this.buffer = {
31 list: [],
32 motd: ''
33 };
34
35 // Handler for any commands sent from the client
36 this.client_commands = new ClientCommands(this);
37 this.client_commands.addRpcEvents(this, this.rpc);
38
39 // Handles the kiwi.* RPC functions
40 this.attachKiwiCommands();
41
42 websocket.on('close', function () {
43 websocketDisconnect.apply(that, arguments);
44 });
45 websocket.on('error', function () {
46 websocketError.apply(that, arguments);
47 });
48
49 this.disposed = false;
50
51 // Let the client know it's finished connecting
52 this.sendKiwiCommand('connected');
53 };
54 util.inherits(Client, events.EventEmitter);
55
56 module.exports.Client = Client;
57
58 // Callback API:
59 // Callbacks SHALL accept 2 arguments, error and response, in that order.
60 // error MUST be null where the command is successul.
61 // error MUST otherwise be a truthy value and SHOULD be a string where the cause of the error is known.
62 // response MAY be given even if error is truthy
63
64 Client.prototype.sendIrcCommand = function (command, data, callback) {
65 var c = {command: command, data: data};
66 this.rpc.call('irc', c, callback);
67 };
68
69 Client.prototype.sendKiwiCommand = function (command, data, callback) {
70 var c = {command: command, data: data};
71 this.rpc.call('kiwi', c, callback);
72 };
73
74 Client.prototype.dispose = function () {
75 this.disposed = true;
76 this.rpc.dispose();
77 this.emit('dispose');
78 this.removeAllListeners();
79 };
80
81
82
83 Client.prototype.attachKiwiCommands = function() {
84 var that = this;
85
86 this.rpc.on('kiwi.connect_irc', function(callback, command) {
87 if (command.hostname && command.port && command.nick) {
88 var options = {};
89
90 // Get any optional parameters that may have been passed
91 if (command.encoding)
92 options.encoding = command.encoding;
93
94 options.password = global.config.restrict_server_password || command.password;
95
96 that.state.connect(
97 (global.config.restrict_server || command.hostname),
98 (global.config.restrict_server_port || command.port),
99 (typeof global.config.restrict_server_ssl !== 'undefined' ?
100 global.config.restrict_server_ssl :
101 command.ssl),
102 command.nick,
103 {hostname: that.websocket.meta.revdns, address: that.websocket.meta.real_address},
104 options,
105 callback);
106 } else {
107 return callback('Hostname, port and nickname must be specified');
108 }
109 });
110
111
112 this.rpc.on('kiwi.client_info', function(callback, args) {
113 // keep hold of selected parts of the client_info
114 that.client_info = {
115 build_version: args.build_version.toString() || undefined
116 };
117 });
118 };
119
120
121
122 // Websocket has disconnected, so quit all the IRC connections
123 function websocketDisconnect() {
124 this.emit('disconnect');
125
126 this.dispose();
127 }
128
129
130 // TODO: Should this close all the websocket connections too?
131 function websocketError() {
132 this.dispose();
133 }