mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-17 01:08:41 +01:00
Summary: Ref T10697. Currently, `aphlict` takes a ton of command line flags to configure exactly one admin server and exactly one client server. I want to replace this with a config file. Additionally, I plan to support: - arbitrary numbers of listening client ports; - arbitrary numbers of listening admin ports; - SSL on any port. For now, just transform the arguments to look like they're a config file. In the future, I'll load from a config file instead. This greater generality will allow you to do stuff like run separate HTTP and HTTPS admin ports if you really want. I don't think there's a ton of use for this, but it tends to make the code cleaner anyway and there may be some weird cross-datacneter cases for it. Certainly, we undershot with the initial design and lots of users want to terminate SSL in nginx and run only HTTP on this server. (Some sort-of-plausible use cases are running separate HTTP and HTTPS client servers, if your Phabricator install supports both, or running multiple HTTPS servers with different certificates if you have a bizarre VPN.) Test Plan: Started Aphlict, connected to it, sent myself test notifications, viewed status page, reviewed logfile. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10697 Differential Revision: https://secure.phabricator.com/D15700
179 lines
4.5 KiB
JavaScript
179 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
var JX = require('./javelin').JX;
|
|
|
|
require('./AphlictListenerList');
|
|
|
|
var http = require('http');
|
|
var url = require('url');
|
|
|
|
JX.install('AphlictAdminServer', {
|
|
|
|
construct: function(server) {
|
|
this._startTime = new Date().getTime();
|
|
this._messagesIn = 0;
|
|
this._messagesOut = 0;
|
|
|
|
server.on('request', JX.bind(this, this._onrequest));
|
|
this._server = server;
|
|
this._clientServers = [];
|
|
},
|
|
|
|
properties: {
|
|
clientServers: null,
|
|
logger: null,
|
|
},
|
|
|
|
members: {
|
|
_messagesIn: null,
|
|
_messagesOut: null,
|
|
_server: null,
|
|
_startTime: null,
|
|
|
|
getListenerLists: function(instance) {
|
|
var clients = this.getClientServers();
|
|
|
|
var lists = [];
|
|
for (var ii = 0; ii < clients.length; ii++) {
|
|
lists.push(clients[ii].getListenerList(instance));
|
|
}
|
|
return lists;
|
|
},
|
|
|
|
log: function() {
|
|
var logger = this.getLogger();
|
|
if (!logger) {
|
|
return;
|
|
}
|
|
|
|
logger.log.apply(logger, arguments);
|
|
|
|
return this;
|
|
},
|
|
|
|
listen: function() {
|
|
return this._server.listen.apply(this._server, arguments);
|
|
},
|
|
|
|
_onrequest: function(request, response) {
|
|
var self = this;
|
|
var u = url.parse(request.url, true);
|
|
var instance = u.query.instance || '/';
|
|
|
|
// Publishing a notification.
|
|
if (u.pathname == '/') {
|
|
if (request.method == 'POST') {
|
|
var body = '';
|
|
|
|
request.on('data', function(data) {
|
|
body += data;
|
|
});
|
|
|
|
request.on('end', function() {
|
|
try {
|
|
var msg = JSON.parse(body);
|
|
|
|
self.log(
|
|
'Received notification (' + instance + '): ' +
|
|
JSON.stringify(msg));
|
|
++self._messagesIn;
|
|
|
|
try {
|
|
self._transmit(instance, msg);
|
|
response.writeHead(200, {'Content-Type': 'text/plain'});
|
|
} catch (err) {
|
|
self.log(
|
|
'<%s> Internal Server Error! %s',
|
|
request.socket.remoteAddress,
|
|
err);
|
|
response.writeHead(500, 'Internal Server Error');
|
|
}
|
|
} catch (err) {
|
|
self.log(
|
|
'<%s> Bad Request! %s',
|
|
request.socket.remoteAddress,
|
|
err);
|
|
response.writeHead(400, 'Bad Request');
|
|
} finally {
|
|
response.end();
|
|
}
|
|
});
|
|
} else {
|
|
response.writeHead(405, 'Method Not Allowed');
|
|
response.end();
|
|
}
|
|
} else if (u.pathname == '/status/') {
|
|
this._handleStatusRequest(request, response, instance);
|
|
} else {
|
|
response.writeHead(404, 'Not Found');
|
|
response.end();
|
|
}
|
|
},
|
|
|
|
_handleStatusRequest: function(request, response, instance) {
|
|
var active_count = 0;
|
|
var total_count = 0;
|
|
|
|
var lists = this.getListenerLists(instance);
|
|
for (var ii = 0; ii < lists.length; ii++) {
|
|
var list = lists[ii];
|
|
active_count += list.getActiveListenerCount();
|
|
total_count += list.getTotalListenerCount();
|
|
}
|
|
|
|
var server_status = {
|
|
'instance': instance,
|
|
'uptime': (new Date().getTime() - this._startTime),
|
|
'clients.active': active_count,
|
|
'clients.total': total_count,
|
|
'messages.in': this._messagesIn,
|
|
'messages.out': this._messagesOut,
|
|
'version': 7
|
|
};
|
|
|
|
response.writeHead(200, {'Content-Type': 'application/json'});
|
|
response.write(JSON.stringify(server_status));
|
|
response.end();
|
|
},
|
|
|
|
/**
|
|
* Transmits a message to all subscribed listeners.
|
|
*/
|
|
_transmit: function(instance, message) {
|
|
var lists = this.getListenerLists(instance);
|
|
|
|
for (var ii = 0; ii < lists.length; ii++) {
|
|
var list = lists[ii];
|
|
var listeners = list.getListeners();
|
|
this._transmitToListeners(list, listeners, message);
|
|
}
|
|
},
|
|
|
|
_transmitToListeners: function(list, listeners, message) {
|
|
for (var ii = 0; ii < listeners.length; ii++) {
|
|
var listener = listeners[ii];
|
|
|
|
if (!listener.isSubscribedToAny(message.subscribers)) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
listener.writeMessage(message);
|
|
|
|
++this._messagesOut;
|
|
this.log(
|
|
'<%s> Wrote Message',
|
|
listener.getDescription());
|
|
} catch (error) {
|
|
list.removeListener(listener);
|
|
|
|
this.log(
|
|
'<%s> Write Error: %s',
|
|
listener.getDescription(),
|
|
error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
});
|