2012-06-14 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Notification server. Launch with:
|
|
|
|
*
|
|
|
|
* sudo node aphlict_server.js --user=aphlict
|
|
|
|
*
|
2012-12-20 00:19:23 +01:00
|
|
|
* You can also specify `port`, `admin`, `host` and `log`.
|
2012-06-14 15:12:54 +02:00
|
|
|
*/
|
|
|
|
|
2014-02-18 01:00:01 +01:00
|
|
|
var JX = require('./lib/javelin').JX;
|
|
|
|
|
2014-02-18 01:01:09 +01:00
|
|
|
JX.require('lib/AphlictFlashPolicyServer', __dirname);
|
2014-02-18 01:00:51 +01:00
|
|
|
JX.require('lib/AphlictListenerList', __dirname);
|
|
|
|
JX.require('lib/AphlictLog', __dirname);
|
|
|
|
|
2012-06-14 15:12:54 +02:00
|
|
|
function parse_command_line_arguments(argv) {
|
|
|
|
var config = {
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
port: 22280,
|
|
|
|
admin: 22281,
|
|
|
|
host: '127.0.0.1',
|
|
|
|
user: null,
|
2012-06-14 15:12:54 +02:00
|
|
|
log: '/var/log/aphlict.log'
|
|
|
|
};
|
|
|
|
|
|
|
|
for (var ii = 2; ii < argv.length; ii++) {
|
|
|
|
var arg = argv[ii];
|
|
|
|
var matches = arg.match(/^--([^=]+)=(.*)$/);
|
|
|
|
if (!matches) {
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
throw new Error("Unknown argument '" + arg + "'!");
|
2012-06-14 15:12:54 +02:00
|
|
|
}
|
|
|
|
if (!(matches[1] in config)) {
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
throw new Error("Unknown argument '" + matches[1] + "'!");
|
2012-06-14 15:12:54 +02:00
|
|
|
}
|
|
|
|
config[matches[1]] = matches[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
config.port = parseInt(config.port, 10);
|
|
|
|
config.admin = parseInt(config.admin, 10);
|
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2014-12-30 12:06:44 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-05-19 02:04:22 +02:00
|
|
|
if (process.getuid() !== 0) {
|
2012-06-14 15:12:54 +02:00
|
|
|
console.log(
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
"ERROR: " +
|
|
|
|
"This server must be run as root because it needs to bind to privileged " +
|
|
|
|
"port 843 to start a Flash policy server. It will downgrade to run as a " +
|
|
|
|
"less-privileged user after binding if you pass a user in the command " +
|
2012-06-14 15:12:54 +02:00
|
|
|
"line arguments with '--user=alincoln'.");
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
var net = require('net');
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
var http = require('http');
|
2012-06-12 02:49:32 +02:00
|
|
|
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
process.on('uncaughtException', function(err) {
|
2014-06-30 22:00:12 +02:00
|
|
|
debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack);
|
2014-06-11 19:40:04 +02:00
|
|
|
|
2012-06-20 22:20:47 +02:00
|
|
|
process.exit(1);
|
|
|
|
});
|
|
|
|
|
2014-12-30 12:02:58 +01:00
|
|
|
new JX.AphlictFlashPolicyServer()
|
2014-02-18 01:01:09 +01:00
|
|
|
.setDebugLog(debug)
|
|
|
|
.setAccessPort(config.port)
|
|
|
|
.start();
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
|
|
|
|
|
2014-12-30 12:02:58 +01:00
|
|
|
net.createServer(function(socket) {
|
2014-02-18 01:00:51 +01:00
|
|
|
var listener = clients.addListener(socket);
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
|
2014-02-18 01:00:51 +01:00
|
|
|
debug.log('<%s> Connected from %s',
|
|
|
|
listener.getDescription(),
|
|
|
|
socket.remoteAddress);
|
2012-06-12 02:49:32 +02:00
|
|
|
|
2014-06-11 21:17:18 +02:00
|
|
|
var buffer = new Buffer([]);
|
|
|
|
var length = 0;
|
|
|
|
|
|
|
|
socket.on('data', function(data) {
|
|
|
|
buffer = Buffer.concat([buffer, new Buffer(data)]);
|
|
|
|
|
|
|
|
while (buffer.length) {
|
|
|
|
if (!length) {
|
|
|
|
length = buffer.readUInt16BE(0);
|
|
|
|
buffer = buffer.slice(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer.length < length) {
|
|
|
|
// We need to wait for the rest of the data.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var message;
|
|
|
|
try {
|
|
|
|
message = JSON.parse(buffer.toString('utf8', 0, length));
|
|
|
|
} catch (err) {
|
|
|
|
debug.log('<%s> Received invalid data.', listener.getDescription());
|
|
|
|
continue;
|
|
|
|
} finally {
|
|
|
|
buffer = buffer.slice(length);
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug.log('<%s> Received data: %s',
|
|
|
|
listener.getDescription(),
|
|
|
|
JSON.stringify(message));
|
|
|
|
|
|
|
|
switch (message.command) {
|
|
|
|
case 'subscribe':
|
|
|
|
debug.log(
|
|
|
|
'<%s> Subscribed to: %s',
|
|
|
|
listener.getDescription(),
|
|
|
|
JSON.stringify(message.data));
|
|
|
|
listener.subscribe(message.data);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'unsubscribe':
|
|
|
|
debug.log(
|
|
|
|
'<%s> Unsubscribed from: %s',
|
|
|
|
listener.getDescription(),
|
|
|
|
JSON.stringify(message.data));
|
|
|
|
listener.unsubscribe(message.data);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
debug.log('<s> Unrecognized command.', listener.getDescription());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2012-06-12 02:49:32 +02:00
|
|
|
socket.on('close', function() {
|
2014-02-18 01:00:51 +01:00
|
|
|
clients.removeListener(listener);
|
|
|
|
debug.log('<%s> Disconnected', listener.getDescription());
|
2012-06-12 02:49:32 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
socket.on('timeout', function() {
|
2014-02-18 01:00:51 +01:00
|
|
|
debug.log('<%s> Timed Out', listener.getDescription());
|
2012-06-12 02:49:32 +02:00
|
|
|
});
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
|
2012-06-12 02:49:32 +02:00
|
|
|
socket.on('end', function() {
|
2014-02-18 01:00:51 +01:00
|
|
|
debug.log('<%s> Ended Connection', listener.getDescription());
|
2012-06-12 02:49:32 +02:00
|
|
|
});
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
socket.on('error', function(e) {
|
2014-02-18 01:00:51 +01:00
|
|
|
debug.log('<%s> Error: %s', listener.getDescription(), e);
|
Aphlict, simple notification server
Summary:
This is purely a prototype at the moment, but the basic functionality sort of
works.
I'm not sure how far I want to go with this but I think we might be able to get
somewhere without it being gross.
The idea here is to build a notification server WITHOUT using Comet, since Comet
is extremely difficult and complicated.
Instead, I use Flash on the client. LocalConnection allows flash instances to
talk to each other and connect() can be used as a locking primitive. This allows
all the instances to elect a master instance in a race-safe way. The master is
responsible for opening a single connnection to the server.
On the server, I use Node.js since PHP is pretty unsuitable for this task.
See Github Issue #3: https://github.com/facebook/phabricator/issues/3
One thing I need to figure out next is if I can reasonably do SSL/TSL over Flash
(it looks like I can, in theory, with the as3crypto library) or if the server
needs to just send down version information and trigger a separate Ajax call on
the client.
Test Plan:
Created a client pool and connected it to the server, with election and failover
apparently working correctly.
Reviewed By: aran
Reviewers: Girish, aran, jungejason, tuomaspelkonen, davidrecordon
Commenters: Girish, davidrecordon
CC: aran, epriestley, Girish, davidrecordon
Differential Revision: 284
2011-05-15 23:05:02 +02:00
|
|
|
});
|
2014-02-18 01:00:51 +01:00
|
|
|
|
2012-06-14 15:12:54 +02:00
|
|
|
}).listen(config.port);
|
2012-06-12 02:49:32 +02:00
|
|
|
|
|
|
|
|
2012-06-14 15:12:54 +02:00
|
|
|
var messages_out = 0;
|
|
|
|
var messages_in = 0;
|
|
|
|
var start_time = new Date().getTime();
|
2012-06-12 02:49:32 +02:00
|
|
|
|
2014-12-30 12:06:44 +01:00
|
|
|
function transmit(msg) {
|
|
|
|
var listeners = clients.getListeners().filter(function(client) {
|
|
|
|
return client.isSubscribedToAny(msg.subscribers);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (var i = 0; i < listeners.length; i++) {
|
|
|
|
var listener = listeners[i];
|
|
|
|
|
|
|
|
try {
|
|
|
|
listener.writeMessage(msg);
|
|
|
|
|
|
|
|
++messages_out;
|
|
|
|
debug.log('<%s> Wrote Message', listener.getDescription());
|
|
|
|
} catch (error) {
|
|
|
|
clients.removeListener(listener);
|
|
|
|
debug.log('<%s> Write Error: %s', listener.getDescription(), error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 12:02:58 +01:00
|
|
|
http.createServer(function(request, response) {
|
2012-06-14 15:12:54 +02:00
|
|
|
// Publishing a notification.
|
2014-07-18 01:01:46 +02:00
|
|
|
if (request.url == '/') {
|
|
|
|
if (request.method == 'POST') {
|
|
|
|
var body = '';
|
2012-06-12 02:49:32 +02:00
|
|
|
|
2014-07-18 01:01:46 +02:00
|
|
|
request.on('data', function(data) {
|
|
|
|
body += data;
|
|
|
|
});
|
2012-06-12 02:49:32 +02:00
|
|
|
|
2014-07-18 01:01:46 +02:00
|
|
|
request.on('end', function() {
|
|
|
|
try {
|
|
|
|
var msg = JSON.parse(body);
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
|
2014-07-18 01:01:46 +02:00
|
|
|
debug.log('notification: ' + JSON.stringify(msg));
|
|
|
|
++messages_in;
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
|
2014-07-18 01:20:00 +02:00
|
|
|
try {
|
|
|
|
transmit(msg);
|
|
|
|
response.writeHead(200, {'Content-Type': 'text/plain'});
|
|
|
|
} catch (err) {
|
|
|
|
debug.log(
|
|
|
|
'<%s> Internal Server Error! %s',
|
|
|
|
request.socket.remoteAddress,
|
|
|
|
err);
|
|
|
|
response.statusCode = 500;
|
|
|
|
response.write('500 Internal Server Error\n');
|
|
|
|
}
|
2014-07-18 01:01:46 +02:00
|
|
|
} catch (err) {
|
|
|
|
debug.log(
|
|
|
|
'<%s> Bad Request! %s',
|
|
|
|
request.socket.remoteAddress,
|
|
|
|
err);
|
|
|
|
response.statusCode = 400;
|
|
|
|
response.write('400 Bad Request\n');
|
|
|
|
} finally {
|
|
|
|
response.end();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
response.statusCode = 405;
|
|
|
|
response.write('405 Method Not Allowed\n');
|
|
|
|
response.end();
|
|
|
|
}
|
2012-06-14 15:12:54 +02:00
|
|
|
} else if (request.url == '/status/') {
|
2014-06-30 22:00:12 +02:00
|
|
|
request.on('data', function() {
|
2013-04-12 00:45:50 +02:00
|
|
|
// We just ignore the request data, but newer versions of Node don't
|
|
|
|
// get to 'end' if we don't process the data. See T2953.
|
|
|
|
});
|
|
|
|
|
2012-06-14 15:12:54 +02:00
|
|
|
request.on('end', function() {
|
|
|
|
var status = {
|
|
|
|
'uptime': (new Date().getTime() - start_time),
|
2014-02-18 01:00:51 +01:00
|
|
|
'clients.active': clients.getActiveListenerCount(),
|
|
|
|
'clients.total': clients.getTotalListenerCount(),
|
2012-06-14 15:12:54 +02:00
|
|
|
'messages.in': messages_in,
|
|
|
|
'messages.out': messages_out,
|
2014-02-18 00:59:39 +01:00
|
|
|
'log': config.log,
|
Make the Aphlict server more resilient.
Summary:
Currently, the Aphlict server will crash if invalid JSON data is `POST`ed to it. I have fixed this to, instead, return a 400. Also made some minor formatting changes.
Ref T4324. Ref T5284. Also, modify the data structure that is passed around (i.e. `POST`ed to the Aphlict server and broadcast to the Aphlict clients) to include the subscribers. Initially, I figured that we shouldn't expose this information to the clients... however, it is necessary for T4324 that the `AphlictMaster` is able to route a notification to the appropriate clients.
Test Plan:
Making the following `curl` request: `curl --data "{" http://localhost:22281/`.
**Before**
```
sudo ./bin/aphlict debug
Starting Aphlict server in foreground...
Launching server:
$ 'nodejs' '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict'
[Wed Jun 11 2014 17:07:51 GMT+0000 (UTC)] Started Server (PID 2033)
[Wed Jun 11 2014 17:07:55 GMT+0000 (UTC)]
<<< UNCAUGHT EXCEPTION! >>>
SyntaxError: Unexpected end of input
>>> Server exited!
```
**After**
(No output... the bad JSON is caught and a 400 is returned)
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324, T5284
Differential Revision: https://secure.phabricator.com/D9480
2014-06-11 19:16:31 +02:00
|
|
|
'version': 6
|
2012-06-14 15:12:54 +02:00
|
|
|
};
|
|
|
|
|
2015-01-02 23:09:48 +01:00
|
|
|
response.writeHead(200, {'Content-Type': 'application/json'});
|
2012-06-14 15:12:54 +02:00
|
|
|
response.write(JSON.stringify(status));
|
|
|
|
response.end();
|
|
|
|
});
|
|
|
|
} else {
|
2014-07-18 01:01:46 +02:00
|
|
|
response.statusCode = 404;
|
|
|
|
response.write('404 Not Found\n');
|
2012-06-14 15:12:54 +02:00
|
|
|
response.end();
|
2012-06-12 02:49:32 +02:00
|
|
|
}
|
2012-12-20 00:19:23 +01:00
|
|
|
}).listen(config.admin, config.host);
|
2012-06-12 02:49:32 +02:00
|
|
|
|
2012-06-14 15:12:54 +02:00
|
|
|
// If we're configured to drop permissions, get rid of them now that we've
|
|
|
|
// bound to the ports we need and opened logfiles.
|
|
|
|
if (config.user) {
|
|
|
|
process.setuid(config.user);
|
|
|
|
}
|
|
|
|
|
2014-02-18 01:00:51 +01:00
|
|
|
debug.log('Started Server (PID %d)', process.pid);
|