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