@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refactoring of the Aphlict server

Summary: Tidy the Aphlict server by splitting the functionality into two main modules, `AphlictClientServer` and `AphlictAdminServer. There is still further tidying that could be done here, but I feel that this puts us in a much better place.

Test Plan: Sent notifications via `/notification/status/`.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D11383

+268 -192
+19 -157
support/aphlict/server/aphlict_server.js
··· 44 44 45 45 process.on('uncaughtException', function(err) { 46 46 var context = null; 47 - if ((err.code == 'EACCES') && 48 - (err.path == config.log)) { 47 + if (err.code == 'EACCES' && err.path == config.log) { 49 48 context = util.format( 50 49 'Unable to open logfile ("%s"). Check that permissions are set ' + 51 50 'correctly.', ··· 65 64 process.exit(1); 66 65 }); 67 66 68 - var WebSocket; 69 67 try { 70 - WebSocket = require('ws'); 68 + require('ws'); 71 69 } catch (ex) { 72 70 throw new Error( 73 71 'You need to install the Node.js "ws" module for websocket support. ' + ··· 88 86 89 87 // Add the logfile so we'll fail if we can't write to it. 90 88 if (config.log) { 91 - debug.addLogfile(config.log); 89 + debug.addLog(config.log); 92 90 } 93 91 94 92 // If we're just doing a configuration test, exit here before starting any ··· 98 96 process.exit(0); 99 97 } 100 98 101 - var start_time = new Date().getTime(); 102 - var messages_out = 0; 103 - var messages_in = 0; 104 - 105 - var clients = new JX.AphlictListenerList(); 99 + JX.require('lib/AphlictAdminServer', __dirname); 100 + JX.require('lib/AphlictClientServer', __dirname); 106 101 107 - function https_discard_handler(req, res) { 108 - res.writeHead(501); 109 - res.end('HTTP/501 Use Websockets\n'); 110 - } 111 - 112 - var ws; 102 + var server; 113 103 if (ssl_config.enabled) { 114 - var https_server = https.createServer({ 104 + server = https.createServer({ 115 105 key: ssl_config.key, 116 106 cert: ssl_config.cert 117 - }, https_discard_handler).listen( 118 - config['client-port'], 119 - config['client-host']); 120 - 121 - ws = new WebSocket.Server({server: https_server}); 122 - } else { 123 - ws = new WebSocket.Server({ 124 - port: config['client-port'], 125 - host: config['client-host'], 126 - }); 127 - } 128 - 129 - ws.on('connection', function(ws) { 130 - var listener = clients.addListener(ws); 131 - 132 - function log() { 133 - debug.log( 134 - util.format('<%s>', listener.getDescription()) + 135 - ' ' + 136 - util.format.apply(null, arguments)); 137 - } 138 - 139 - log('Connected from %s.', ws._socket.remoteAddress); 140 - 141 - ws.on('message', function(data) { 142 - log('Received message: %s', data); 143 - 144 - var message; 145 - try { 146 - message = JSON.parse(data); 147 - } catch (err) { 148 - log('Message is invalid: %s', err.message); 149 - return; 150 - } 151 - 152 - switch (message.command) { 153 - case 'subscribe': 154 - log( 155 - 'Subscribed to: %s', 156 - JSON.stringify(message.data)); 157 - listener.subscribe(message.data); 158 - break; 159 - 160 - case 'unsubscribe': 161 - log( 162 - 'Unsubscribed from: %s', 163 - JSON.stringify(message.data)); 164 - listener.unsubscribe(message.data); 165 - break; 166 - 167 - default: 168 - log('Unrecognized command "%s".', message.command || '<undefined>'); 169 - } 170 - }); 171 - 172 - ws.on('close', function() { 173 - clients.removeListener(listener); 174 - log('Disconnected.'); 175 - }); 176 - 177 - ws.on('error', function(err) { 178 - log('Error: %s', err.message); 179 - }); 180 - }); 181 - 182 - function transmit(msg) { 183 - var listeners = clients.getListeners().filter(function(client) { 184 - return client.isSubscribedToAny(msg.subscribers); 107 + }, function(req, res) { 108 + res.writeHead(501); 109 + res.end('HTTP/501 Use Websockets\n'); 185 110 }); 186 - 187 - for (var i = 0; i < listeners.length; i++) { 188 - var listener = listeners[i]; 189 - 190 - try { 191 - listener.writeMessage(msg); 192 - 193 - ++messages_out; 194 - debug.log('<%s> Wrote Message', listener.getDescription()); 195 - } catch (error) { 196 - clients.removeListener(listener); 197 - debug.log('<%s> Write Error: %s', listener.getDescription(), error); 198 - } 199 - } 111 + } else { 112 + server = http.createServer(function() {}); 200 113 } 201 114 202 - http.createServer(function(request, response) { 203 - // Publishing a notification. 204 - if (request.url == '/') { 205 - if (request.method == 'POST') { 206 - var body = ''; 207 - 208 - request.on('data', function(data) { 209 - body += data; 210 - }); 211 - 212 - request.on('end', function() { 213 - try { 214 - var msg = JSON.parse(body); 115 + var client_server = new JX.AphlictClientServer(server); 116 + var admin_server = new JX.AphlictAdminServer(); 215 117 216 - debug.log('Received notification: ' + JSON.stringify(msg)); 217 - ++messages_in; 218 - 219 - try { 220 - transmit(msg); 221 - response.writeHead(200, {'Content-Type': 'text/plain'}); 222 - } catch (err) { 223 - debug.log( 224 - '<%s> Internal Server Error! %s', 225 - request.socket.remoteAddress, 226 - err); 227 - response.writeHead(500, 'Internal Server Error'); 228 - } 229 - } catch (err) { 230 - debug.log( 231 - '<%s> Bad Request! %s', 232 - request.socket.remoteAddress, 233 - err); 234 - response.writeHead(400, 'Bad Request'); 235 - } finally { 236 - response.end(); 237 - } 238 - }); 239 - } else { 240 - response.writeHead(405, 'Method Not Allowed'); 241 - response.end(); 242 - } 243 - } else if (request.url == '/status/') { 244 - var status = { 245 - 'uptime': (new Date().getTime() - start_time), 246 - 'clients.active': clients.getActiveListenerCount(), 247 - 'clients.total': clients.getTotalListenerCount(), 248 - 'messages.in': messages_in, 249 - 'messages.out': messages_out, 250 - 'log': config.log, 251 - 'version': 6 252 - }; 118 + client_server.setLogger(debug); 119 + admin_server.setLogger(debug); 120 + admin_server.setClientServer(client_server); 253 121 254 - response.writeHead(200, {'Content-Type': 'application/json'}); 255 - response.write(JSON.stringify(status)); 256 - response.end(); 257 - } else { 258 - response.writeHead(404, 'Not Found'); 259 - response.end(); 260 - } 261 - }).listen(config['admin-port'], config['admin-host']); 122 + client_server.listen(config['client-port'], config['client-host']); 123 + admin_server.listen(config['admin-port'], config['admin-host']); 262 124 263 125 debug.log('Started Server (PID %d)', process.pid);
+135
support/aphlict/server/lib/AphlictAdminServer.js
··· 1 + var JX = require('javelin').JX; 2 + 3 + JX.require('AphlictListenerList', __dirname); 4 + 5 + var http = require('http'); 6 + 7 + JX.install('AphlictAdminServer', { 8 + 9 + construct: function() { 10 + this.setLogger(new JX.AphlictLog()); 11 + 12 + this._startTime = new Date().getTime(); 13 + this._messagesIn = 0; 14 + this._messagesOut = 0; 15 + 16 + var handler = this._handler.bind(this); 17 + this._server = http.createServer(handler); 18 + }, 19 + 20 + members: { 21 + _messagesIn: null, 22 + _messagesOut: null, 23 + _server: null, 24 + _startTime: null, 25 + 26 + getListeners: function() { 27 + return this.getListenerList().getListeners(); 28 + }, 29 + 30 + getListenerList: function() { 31 + return this.getClientServer().getListenerList(); 32 + }, 33 + 34 + listen: function() { 35 + return this._server.listen.apply(this._server, arguments); 36 + }, 37 + 38 + _handler: function(request, response) { 39 + var self = this; 40 + 41 + // Publishing a notification. 42 + if (request.url == '/') { 43 + if (request.method == 'POST') { 44 + var body = ''; 45 + 46 + request.on('data', function(data) { 47 + body += data; 48 + }); 49 + 50 + request.on('end', function() { 51 + try { 52 + var msg = JSON.parse(body); 53 + 54 + self.getLogger().log( 55 + 'Received notification: ' + JSON.stringify(msg)); 56 + ++this._messagesIn; 57 + 58 + try { 59 + self._transmit(msg); 60 + response.writeHead(200, {'Content-Type': 'text/plain'}); 61 + } catch (err) { 62 + self.getLogger().log( 63 + '<%s> Internal Server Error! %s', 64 + request.socket.remoteAddress, 65 + err); 66 + response.writeHead(500, 'Internal Server Error'); 67 + } 68 + } catch (err) { 69 + self.getLogger().log( 70 + '<%s> Bad Request! %s', 71 + request.socket.remoteAddress, 72 + err); 73 + response.writeHead(400, 'Bad Request'); 74 + } finally { 75 + response.end(); 76 + } 77 + }); 78 + } else { 79 + response.writeHead(405, 'Method Not Allowed'); 80 + response.end(); 81 + } 82 + } else if (request.url == '/status/') { 83 + var status = { 84 + 'uptime': (new Date().getTime() - this._startTime), 85 + 'clients.active': this.getListenerList().getActiveListenerCount(), 86 + 'clients.total': this.getListenerList().getTotalListenerCount(), 87 + 'messages.in': this._messagesIn, 88 + 'messages.out': this._messagesOut, 89 + 'version': 6 90 + }; 91 + 92 + response.writeHead(200, {'Content-Type': 'application/json'}); 93 + response.write(JSON.stringify(status)); 94 + response.end(); 95 + } else { 96 + response.writeHead(404, 'Not Found'); 97 + response.end(); 98 + } 99 + }, 100 + 101 + /** 102 + * Transmits a message to all subscribed listeners. 103 + */ 104 + _transmit: function(message) { 105 + var listeners = this.getListeners().filter(function(client) { 106 + return client.isSubscribedToAny(message.subscribers); 107 + }); 108 + 109 + for (var i = 0; i < listeners.length; i++) { 110 + var listener = listeners[i]; 111 + 112 + try { 113 + listener.writeMessage(message); 114 + 115 + ++this._messagesOut; 116 + this.getLogger().log( 117 + '<%s> Wrote Message', 118 + listener.getDescription()); 119 + } catch (error) { 120 + this.getListenerList().removeListener(listener); 121 + this.getLogger().log( 122 + '<%s> Write Error: %s', 123 + listener.getDescription(), 124 + error); 125 + } 126 + } 127 + }, 128 + }, 129 + 130 + properties: { 131 + clientServer: null, 132 + logger: null, 133 + } 134 + 135 + });
+90
support/aphlict/server/lib/AphlictClientServer.js
··· 1 + var JX = require('javelin').JX; 2 + 3 + JX.require('AphlictListenerList', __dirname); 4 + JX.require('AphlictLog', __dirname); 5 + 6 + var util = require('util'); 7 + var WebSocket = require('ws'); 8 + 9 + JX.install('AphlictClientServer', { 10 + 11 + construct: function(server) { 12 + this.setListenerList(new JX.AphlictListenerList()); 13 + this.setLogger(new JX.AphlictLog()); 14 + this._server = server; 15 + }, 16 + 17 + members: { 18 + _server: null, 19 + 20 + listen: function() { 21 + var self = this; 22 + var server = this._server.listen.apply(this._server, arguments); 23 + var wss = new WebSocket.Server({server: server}); 24 + 25 + wss.on('connection', function(ws) { 26 + var listener = self.getListenerList().addListener(ws); 27 + 28 + function log() { 29 + self.getLogger().log( 30 + util.format('<%s>', listener.getDescription()) + 31 + ' ' + 32 + util.format.apply(null, arguments)); 33 + } 34 + 35 + log('Connected from %s.', ws._socket.remoteAddress); 36 + 37 + ws.on('message', function(data) { 38 + log('Received message: %s', data); 39 + 40 + var message; 41 + try { 42 + message = JSON.parse(data); 43 + } catch (err) { 44 + log('Message is invalid: %s', err.message); 45 + return; 46 + } 47 + 48 + switch (message.command) { 49 + case 'subscribe': 50 + log( 51 + 'Subscribed to: %s', 52 + JSON.stringify(message.data)); 53 + listener.subscribe(message.data); 54 + break; 55 + 56 + case 'unsubscribe': 57 + log( 58 + 'Unsubscribed from: %s', 59 + JSON.stringify(message.data)); 60 + listener.unsubscribe(message.data); 61 + break; 62 + 63 + default: 64 + log( 65 + 'Unrecognized command "%s".', 66 + message.command || '<undefined>'); 67 + } 68 + }); 69 + 70 + wss.on('close', function() { 71 + self.getListenerList().removeListener(listener); 72 + log('Disconnected.'); 73 + }); 74 + 75 + wss.on('error', function(err) { 76 + log('Error: %s', err.message); 77 + }); 78 + 79 + }); 80 + 81 + }, 82 + 83 + }, 84 + 85 + properties: { 86 + listenerList: null, 87 + logger: null, 88 + } 89 + 90 + });
+2 -4
support/aphlict/server/lib/AphlictListener.js
··· 50 50 51 51 writeMessage: function(message) { 52 52 this._socket.send(JSON.stringify(message)); 53 - } 54 - 55 - } 56 - 53 + }, 54 + }, 57 55 });
+4 -6
support/aphlict/server/lib/AphlictListenerList.js
··· 39 39 }, 40 40 41 41 getActiveListenerCount: function() { 42 - return Object.keys(this._listeners).length; 42 + return this._listeners.length; 43 43 }, 44 44 45 45 getTotalListenerCount: function() { ··· 48 48 49 49 _generateNextID: function() { 50 50 do { 51 - this._nextID = ((this._nextID + 1) % 1000000000000); 51 + this._nextID = (this._nextID + 1) % 1000000000000; 52 52 } while (this._nextID in this._listeners); 53 53 54 54 return this._nextID; 55 - } 56 - 57 - } 58 - 55 + }, 56 + }, 59 57 });
+18 -25
support/aphlict/server/lib/AphlictLog.js
··· 5 5 6 6 JX.install('AphlictLog', { 7 7 construct: function() { 8 - this._writeToLogs = []; 9 - this._writeToConsoles = []; 8 + this._consoles = []; 9 + this._logs = []; 10 10 }, 11 11 12 12 members: { 13 - _writeToConsoles: null, 14 - _writeToLogs: null, 13 + _consoles: null, 14 + _logs: null, 15 15 16 - addLogfile: function(path) { 17 - var options = { 16 + addConsole: function(console) { 17 + this._consoles.push(console); 18 + return this; 19 + }, 20 + 21 + addLog: function(path) { 22 + this._logs.push(fs.createWriteStream(path, { 18 23 flags: 'a', 19 24 encoding: 'utf8', 20 25 mode: 0664, 21 - }; 22 - 23 - var logfile = fs.createWriteStream(path, options); 24 - 25 - this._writeToLogs.push(logfile); 26 - 27 - return this; 28 - }, 29 - 30 - addConsole: function(console) { 31 - this._writeToConsoles.push(console); 26 + })); 32 27 return this; 33 28 }, 34 29 ··· 38 33 str = '[' + date + '] ' + str; 39 34 40 35 var ii; 41 - for (ii = 0; ii < this._writeToConsoles.length; ii++) { 42 - this._writeToConsoles[ii].log(str); 36 + for (ii = 0; ii < this._consoles.length; ii++) { 37 + this._consoles[ii].log(str); 43 38 } 44 39 45 - for (ii = 0; ii < this._writeToLogs.length; ii++) { 46 - this._writeToLogs[ii].write(str + '\n'); 40 + for (ii = 0; ii < this._logs.length; ii++) { 41 + this._logs[ii].write(str + '\n'); 47 42 } 48 - } 49 - 50 - } 51 - 43 + }, 44 + }, 52 45 });