Use a space instead of colon as event delimiter
[KiwiIRC.git] / server / kiwi.js
1 var fs = require('fs'),
2 _ = require('lodash'),
3 WebListener = require('./weblistener.js'),
4 config = require('./configuration.js'),
5 rehash = require('./rehash.js'),
6 modules = require('./modules.js'),
7 Identd = require('./identd.js');
8
9
10
11 process.chdir(__dirname + '/../');
12 config.loadConfig();
13
14
15 // If we're not running in the forground and we have a log file.. switch
16 // console.log to output to a file
17 if (process.argv.indexOf('-f') === -1 && global.config && global.config.log) {
18 (function () {
19 var log_file_name = global.config.log;
20
21 if (log_file_name[0] !== '/') {
22 log_file_name = __dirname + '/../' + log_file_name;
23 }
24
25
26
27 console.log = function() {
28 var logfile = fs.openSync(log_file_name, 'a'),
29 out;
30
31 out = Array.prototype.join.apply(arguments, [' ']);
32
33 // Make sure we out somthing to log and we have an open file
34 if (!out || !logfile) return;
35
36 out += '\n';
37 fs.writeSync(logfile, out, null);
38
39 fs.closeSync(logfile);
40 };
41 })();
42 }
43
44
45
46 // Make sure we have a valid config file and at least 1 server
47 if (!global.config || Object.keys(global.config).length === 0) {
48 console.log('Couldn\'t find a valid config.js file (Did you copy the config.example.js file yet?)');
49 process.exit(1);
50 }
51
52 if ((!global.config.servers) || (global.config.servers.length < 1)) {
53 console.log('No servers defined in config file');
54 process.exit(2);
55 }
56
57
58
59
60 // Create a plugin interface
61 global.modules = new modules.Publisher();
62
63 // Register as the active interface
64 modules.registerPublisher(global.modules);
65
66 // Load any modules in the config
67 if (global.config.module_dir) {
68 (global.config.modules || []).forEach(function (module_name) {
69 if (modules.load(global.config.module_dir + module_name + '.js')) {
70 console.log('Module ' + module_name + ' loaded successfuly');
71 } else {
72 console.log('Module ' + module_name + ' failed to load');
73 }
74 });
75 }
76
77
78
79
80 // Holder for all the connected clients
81 global.clients = {
82 clients: Object.create(null),
83 addresses: Object.create(null),
84
85 add: function (client) {
86 this.clients[client.hash] = client;
87 if (typeof this.addresses[client.real_address] === 'undefined') {
88 this.addresses[client.real_address] = Object.create(null);
89 }
90 this.addresses[client.real_address][client.hash] = client;
91 },
92
93 remove: function (client) {
94 if (typeof this.clients[client.hash] !== 'undefined') {
95 delete this.clients[client.hash];
96 delete this.addresses[client.real_address][client.hash];
97 if (Object.keys(this.addresses[client.real_address]).length < 1) {
98 delete this.addresses[client.real_address];
99 }
100 }
101 },
102
103 numOnAddress: function (addr) {
104 if (typeof this.addresses[addr] !== 'undefined') {
105 return Object.keys(this.addresses[addr]).length;
106 } else {
107 return 0;
108 }
109 }
110 };
111
112 global.servers = {
113 servers: Object.create(null),
114
115 addConnection: function (connection) {
116 var host = connection.irc_host.hostname;
117 if (!this.servers[host]) {
118 this.servers[host] = [];
119 }
120 this.servers[host].push(connection);
121 },
122
123 removeConnection: function (connection) {
124 var host = connection.irc_host.hostname
125 if (this.servers[host]) {
126 this.servers[host] = _.without(this.servers[host], connection);
127 if (this.servers[host].length === 0) {
128 delete this.servers[host];
129 }
130 }
131 },
132
133 numOnHost: function (host) {
134 if (this.servers[host]) {
135 return this.servers[host].length;
136 } else {
137 return 0;
138 }
139 }
140 };
141
142
143
144
145 /*
146 * Identd server
147 */
148 if (global.config.identd && global.config.identd.enabled) {
149 new Identd({
150 bind_addr: global.config.identd.address,
151 bind_port: global.config.identd.port
152 }).start();
153 }
154
155
156
157
158 /*
159 * Web listeners
160 */
161
162
163 // Start up a weblistener for each found in the config
164 _.each(global.config.servers, function (server) {
165 var wl = new WebListener(server, global.config.transports);
166
167 wl.on('connection', function (client) {
168 clients.add(client);
169 });
170
171 wl.on('client_dispose', function (client) {
172 clients.remove(client);
173 });
174
175 wl.on('listening', function () {
176 console.log('Listening on %s:%s %s SSL', server.address, server.port, (server.ssl ? 'with' : 'without'));
177 webListenerRunning();
178 });
179
180 wl.on('error', function (err) {
181 console.log('Error listening on %s:%s: %s', server.address, server.port, err.code);
182 // TODO: This should probably be refactored. ^JA
183 webListenerRunning();
184 });
185 });
186
187 // Once all the listeners are listening, set the processes UID/GID
188 var num_listening = 0;
189 function webListenerRunning() {
190 num_listening++;
191 if (num_listening === global.config.servers.length) {
192 setProcessUid();
193 }
194 }
195
196
197
198
199 /*
200 * Process settings
201 */
202
203 // Set process title
204 process.title = 'kiwiirc';
205
206 // Change UID/GID
207 function setProcessUid() {
208 if ((global.config.group) && (global.config.group !== '')) {
209 process.setgid(global.config.group);
210 }
211 if ((global.config.user) && (global.config.user !== '')) {
212 process.setuid(global.config.user);
213 }
214 }
215
216
217 // Make sure Kiwi doesn't simply quit on an exception
218 process.on('uncaughtException', function (e) {
219 console.log('[Uncaught exception] ' + e);
220 console.log(e.stack);
221 });
222
223
224 process.on('SIGUSR1', function() {
225 if (config.loadConfig()) {
226 console.log('New config file loaded');
227 } else {
228 console.log("No new config file was loaded");
229 }
230 });
231
232
233
234
235 /*
236 * Listen for runtime commands
237 */
238
239 process.stdin.resume();
240 process.stdin.on('data', function (buffered) {
241 var data = buffered.toString().trim();
242
243 switch (data) {
244 case 'stats':
245 console.log('Connected clients: ' + _.size(global.clients.clients).toString());
246 console.log('Num. remote hosts: ' + _.size(global.clients.addresses).toString());
247 break;
248
249 case 'reconfig':
250 if (config.loadConfig()) {
251 console.log('New config file loaded');
252 } else {
253 console.log("No new config file was loaded");
254 }
255
256 break;
257
258
259 case 'rehash':
260 (function () {
261 rehash.rehashAll();
262 console.log('Rehashed');
263 })();
264
265 break;
266
267 default:
268 console.log('Unrecognised command: ' + data);
269 }
270 });