Server recoding to reload the server codebase without a restart
[KiwiIRC.git] / node / kiwi.js
1 /*jslint continue: true, forin: true, regexp: true, undef: false, node: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
2 "use strict";
3 var tls = require('tls'),
4 net = require('net'),
5 http = require('http'),
6 https = require('https'),
7 fs = require('fs'),
8 url = require('url'),
9 dns = require('dns'),
10 crypto = require('crypto'),
11 ws = require('socket.io'),
12 jsp = require("uglify-js").parser,
13 pro = require("uglify-js").uglify,
14 _ = require('./lib/underscore.min.js'),
15 starttls = require('./lib/starttls.js'),
16 app = require(__dirname + '/app.js');
17
18
19
20
21
22 // Libraries may need to know kiwi.js path as __dirname
23 // only gives that librarys path. Set it here for usage later.
24 this.kiwi_root = __dirname;
25
26
27
28 /*
29 * Configuration and rehashing routines
30 */
31 var config_filename = 'config.json',
32 config_dirs = ['/etc/kiwiirc/', __dirname + '/'];
33
34 this.config = {};
35 this.loadConfig = function () {
36 var i, j,
37 nconf = {},
38 cconf = {},
39 found_config = false;
40
41 for (i in config_dirs) {
42 try {
43 if (fs.lstatSync(config_dirs[i] + config_filename).isDirectory() === false) {
44 found_config = true;
45 nconf = JSON.parse(fs.readFileSync(config_dirs[i] + config_filename, 'ascii'));
46 for (j in nconf) {
47 // If this has changed from the previous config, mark it as changed
48 if (!_.isEqual(this.config[j], nconf[j])) {
49 cconf[j] = nconf[j];
50 }
51
52 this.config[j] = nconf[j];
53 }
54
55 console.log('Loaded config file ' + config_dirs[i] + config_filename);
56 break;
57 }
58 } catch (e) {
59 switch (e.code) {
60 case 'ENOENT': // No file/dir
61 break;
62 default:
63 console.log('An error occured parsing the config file ' + config_dirs[i] + config_filename + ': ' + e.message);
64 return false;
65 }
66 continue;
67 }
68 }
69 if (Object.keys(this.config).length === 0) {
70 if (!found_config) {
71 console.log('Couldn\'t find a config file!');
72 }
73 return false;
74 }
75 return [nconf, cconf];
76 };
77
78
79 // Reloads the config during runtime
80 this.rehash = function () {
81 return app.rehash();
82 }
83
84 // Reloads app.js during runtime for any recoding
85 this.recode = function () {
86 if (typeof require.cache[__dirname + '/app.js'] !== 'undefined'){
87 delete require.cache[__dirname + '/app.js'];
88 }
89
90 app = null;
91 app = require(__dirname + '/app.js');
92
93 var objs = {tls:tls, net:net, http:http, https:https, fs:fs, url:url, dns:dns, crypto:crypto, ws:ws, jsp:jsp, pro:pro, _:_, starttls:starttls};
94 app.init(objs);
95
96 return true;
97 }
98
99
100
101
102
103
104 /*
105 * Before we continue we need the config loaded
106 */
107 if (!this.loadConfig()) {
108 process.exit(0);
109 }
110
111
112
113
114
115
116
117 /*
118 * HTTP file serving
119 */
120 if (this.config.handle_http) {
121 this.fileServer = new (require('node-static').Server)(__dirname + this.config.public_http);
122 this.jade = require('jade');
123 this.cache = {alljs: '', html: []};
124 }
125 this.httpServer = null;
126 this.httpHandler = function (request, response) {
127 return app.httpHandler(request, response);
128 }
129
130
131
132
133
134
135 /*
136 * Websocket handling
137 */
138 this.connections = {};
139 this.io = null;
140 this.websocketListen = function (port, host, handler, secure, key, cert) {
141 return app.websocketListen(port, host, handler, secure, key, cert);
142 }
143 this.websocketConnection = function (websocket) {
144 return app.websocketConnection(websocket);
145 }
146 this.websocketDisconnect = function () {
147 return app.websocketDisconnect();
148 }
149 this.websocketMessage = function (msg, callback) {
150 return app.websocketMessage(this, msg, callback);
151 }
152 this.websocketIRCConnect = function (nick, host, port, ssl, callback) {
153 return app.websocketIRCConnect(this, nick, host, port, ssl, callback);
154 }
155
156
157
158
159 /*
160 * IRC handling
161 */
162 this.parseIRCMessage = function (websocket, ircSocket, data) {
163 return app.parseIRCMessage(websocket, ircSocket, data);
164 }
165 this.ircSocketDataHandler = function (data, websocket, ircSocket) {
166 return app.ircSocketDataHandler(data, websocket, ircSocket);
167 }
168
169
170
171
172
173
174
175
176
177 /*
178 * Load up main application source
179 */
180 if (!this.recode()) {
181 process.exit(0);
182 }
183
184
185
186 // Set the process title
187 app.setTitle();
188
189
190
191 /*
192 * Load the modules as set in the config and print them out
193 */
194 this.kiwi_mod = require('./lib/kiwi_mod.js');
195 this.kiwi_mod.loadModules(this.kiwi_root, this.config);
196 this.kiwi_mod.printMods();
197
198
199
200
201 // Start the server up
202 this.websocketListen(this.config.port, this.config.bind_address, this.httpHandler, this.config.listen_ssl, this.config.ssl_key, this.config.ssl_cert);
203
204 // Now we're listening on the network, set our UID/GIDs if required
205 app.changeUser();
206
207 // Listen for controll messages
208 app.startControll();
209
210
211