1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 11:30:55 +01:00

Break some of Aphlict into reasonable classes with sensible responsibilities

Summary:
Ref T4324.

  - Create `Listener` to represent listening clients.
  - Create `ListenerList` to represent the current list of clients.
  - Create `Logfile` to handle logging.

Test Plan: Clicked "Send Test Notification", verified logs, status and notifications all work correctly.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T4324

Differential Revision: https://secure.phabricator.com/D8256
This commit is contained in:
epriestley 2014-02-17 16:00:51 -08:00
parent 18f856ac6f
commit 28fe44da0a
7 changed files with 204 additions and 80 deletions

View file

@ -170,7 +170,7 @@ return array(
'rsrc/externals/javelin/core/__tests__/stratcom.js' => 'da194d4b',
'rsrc/externals/javelin/core/__tests__/util.js' => 'd3b157a9',
'rsrc/externals/javelin/core/init.js' => 'b88ab49e',
'rsrc/externals/javelin/core/init_node.js' => '9fe4895f',
'rsrc/externals/javelin/core/init_node.js' => 'd7dde471',
'rsrc/externals/javelin/core/install.js' => '52a92793',
'rsrc/externals/javelin/core/util.js' => '7501647b',
'rsrc/externals/javelin/docs/Base.js' => '3b9ca7eb',

View file

@ -7,12 +7,21 @@
*/
var JX = require('./lib/javelin').JX;
JX.require('lib/AphlictIDGenerator', __dirname);
var id_generator = new JX.AphlictIDGenerator();
JX.require('lib/AphlictListenerList', __dirname);
JX.require('lib/AphlictLog', __dirname);
var debug = new JX.AphlictLog()
.addConsole(console);
var clients = new JX.AphlictListenerList();
var config = parse_command_line_arguments(process.argv);
if (config.logfile) {
debug.addLogfile(config.logfile);
}
function parse_command_line_arguments(argv) {
var config = {
port : 22280,
@ -54,29 +63,13 @@ var net = require('net');
var http = require('http');
var url = require('url');
var querystring = require('querystring');
var fs = require('fs');
// set up log file
var logfile = fs.createWriteStream(
config.log,
{
flags: 'a',
encoding: null,
mode: 0666
});
function log(str) {
console.log(str);
logfile.write(str + '\n');
}
process.on('uncaughtException', function (err) {
log("\n<<< UNCAUGHT EXCEPTION! >>>\n\n" + err);
process.exit(1);
});
log('----- ' + (new Date()).toLocaleString() + ' -----\n');
function getFlashPolicy() {
return [
'<?xml version="1.0"?>',
@ -92,56 +85,38 @@ net.createServer(function(socket) {
socket.write(getFlashPolicy() + '\0');
socket.end();
log('[' + socket.remoteAddress + '] Sent Flash Policy');
debug.log('[' + socket.remoteAddress + '] Sent Flash Policy');
socket.on('error', function (e) {
log('Error in policy server: ' + e);
debug.log('Error in policy server: ' + e);
});
}).listen(843);
function write_json(socket, data) {
var serial = JSON.stringify(data);
var length = Buffer.byteLength(serial, 'utf8');
length = length.toString();
while (length.length < 8) {
length = '0' + length;
}
socket.write(length + serial);
}
var clients = {};
var current_connections = 0;
var send_server = net.createServer(function(socket) {
var client_id = id_generator.generateNext();
var client_name = '[' + socket.remoteAddress + '] [#' + client_id + '] ';
var listener = clients.addListener(socket);
clients[client_id] = socket;
current_connections++;
log(client_name + 'connected\t\t(' +
current_connections + ' current connections)');
debug.log('<%s> Connected from %s',
listener.getDescription(),
socket.remoteAddress);
socket.on('close', function() {
delete clients[client_id];
current_connections--;
log(client_name + 'closed\t\t(' +
current_connections + ' current connections)');
clients.removeListener(listener);
debug.log('<%s> Disconnected', listener.getDescription());
});
socket.on('timeout', function() {
log(client_name + 'timed out!');
debug.log('<%s> Timed Out', listener.getDescription());
});
socket.on('end', function() {
log(client_name + 'ended the connection');
// node automatically closes half-open connections
debug.log('<%s> Ended Connection', listener.getDescription());
});
socket.on('error', function (e) {
log(client_name + 'Uncaught error in send server: ' + e);
debug.log('<%s> Error: %s', listener.getDescription(), e);
});
}).listen(config.port);
@ -164,7 +139,7 @@ var receive_server = http.createServer(function(request, response) {
++messages_in;
var data = querystring.parse(body);
log('notification: ' + JSON.stringify(data));
debug.log('notification: ' + JSON.stringify(data));
broadcast(data);
response.end();
});
@ -177,8 +152,8 @@ var receive_server = http.createServer(function(request, response) {
request.on('end', function() {
var status = {
'uptime': (new Date().getTime() - start_time),
'clients.active': current_connections,
'clients.total': id_generator.getTotalCount(),
'clients.active': clients.getActiveListenerCount(),
'clients.total': clients.getTotalListenerCount(),
'messages.in': messages_in,
'messages.out': messages_out,
'log': config.log,
@ -197,15 +172,17 @@ var receive_server = http.createServer(function(request, response) {
}).listen(config.admin, config.host);
function broadcast(data) {
for (var client_id in clients) {
var listeners = clients.getListeners();
for (var id in listeners) {
var listener = listeners[id];
try {
write_json(clients[client_id], data);
listener.writeMessage(data);
++messages_out;
log('wrote to client ' + client_id);
debug.log('<%s> Wrote Message', listener.getDescription());
} catch (error) {
delete clients[client_id];
current_connections--;
log('ERROR: could not write to client ' + client_id);
clients.removeListener(listener);
debug.log('<%s> Write Error: %s', error);
}
}
}
@ -216,3 +193,4 @@ if (config.user) {
process.setuid(config.user);
}
debug.log('Started Server (PID %d)', process.pid);

View file

@ -1,18 +0,0 @@
var JX = require('javelin').JX;
JX.install('AphlictIDGenerator', {
members : {
_next : 0,
generateNext : function() {
this._next = ((this._next + 1) % 1000000000000);
return this._next;
},
getTotalCount : function() {
return this._next;
}
}
});

View file

@ -0,0 +1,39 @@
var JX = require('javelin').JX;
JX.install('AphlictListener', {
construct : function(id, socket) {
this._id = id;
this._socket = socket;
},
members : {
_id : null,
_socket : null,
getID : function() {
return this._id;
},
getSocket : function() {
return this._socket;
},
getDescription : function() {
return 'Listener/' + this.getID();
},
writeMessage : function(message) {
var serial = JSON.stringify(message);
var length = Buffer.byteLength(serial, 'utf8');
length = length.toString();
while (length.length < 8) {
length = '0' + length;
}
this._socket.write(length + serial);
}
}
});

View file

@ -0,0 +1,57 @@
var JX = require('javelin').JX;
JX.require('AphlictListener', __dirname);
JX.install('AphlictListenerList', {
construct : function() {
this._listeners = {};
},
members : {
_listeners : null,
_nextID : 0,
_activeListenerCount : 0,
_totalListenerCount : 0,
addListener : function(socket) {
var listener = new JX.AphlictListener(
this._generateNextID(),
socket);
this._listeners[listener.getID()] = listener;
this._activeListenerCount++;
this._totalListenerCount++;
return listener;
},
removeListener : function(listener) {
var id = listener.getID();
if (id in this._listeners) {
delete this._listeners[id];
this._activeListenerCount--;
}
},
getListeners : function() {
return this._listeners;
},
getActiveListenerCount : function() {
return this._activeListenerCount;
},
getTotalListenerCount : function() {
return this._totalListenerCount;
},
_generateNextID : function() {
do {
this._nextID = ((this._nextID + 1) % 1000000000000);
} while (this._nextID in this._listeners);
return this._nextID;
}
}
});

View file

@ -0,0 +1,52 @@
var JX = require('javelin').JX;
var fs = require('fs');
var util = require('util');
JX.install('AphlictLog', {
construct : function() {
this._writeToLogs = [];
this._writeToConsoles = [];
},
members : {
_writeToConsoles : null,
_writeToLogs : null,
addLogfile : function(path) {
var options = {
flags: 'a',
encoding: 'utf8',
mode: 066
};
var logfile = fs.createWriteSteam(path, options);
this._writeToLogs.push(logfile);
return this;
},
addConsole : function(console) {
this._writeToConsoles.push(console);
return this;
},
log : function(pattern) {
var str = util.format.apply(null, arguments);
var date = new Date().toLocaleString();
str = '[' + date + '] ' + str;
var ii;
for (ii = 0; ii < this._writeToConsoles.length; ii++) {
this._writeToConsoles[ii].log(str);
}
for (ii = 0; ii < this._writeToLogs.length; ii++) {
this._writeToLogs[ii].write(str + "\n");
}
}
}
});

View file

@ -27,17 +27,33 @@ JX.require = function(thing, relative) {
relative = relative || __dirname + '/..';
var path = relative + '/' + thing + '.js';
var content = fs.readFileSync(path);
var dir = pathModule.dirname(path);
var sandbox = {
var k;
var sandbox = {};
for (k in global) {
sandbox[k] = global[k];
}
var extra = {
JX : this,
__DEV__ : 0,
console : console,
window : {},
require : function (thing) {
return require(pathModule.dirname(path) + '/' + thing);
__dirname : dir,
require : function(thing) {
if (thing == 'javelin') {
return require(dir + '/' + thing);
} else {
return require(thing);
}
}
};
for (k in extra) {
sandbox[k] = extra[k];
}
vm.createScript(content, path)
.runInNewContext(sandbox, path);
};