Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
package {
|
|
|
|
|
|
|
|
import flash.events.Event;
|
|
|
|
import flash.events.IOErrorEvent;
|
|
|
|
import flash.events.ProgressEvent;
|
|
|
|
import flash.events.SecurityErrorEvent;
|
|
|
|
import flash.events.TimerEvent;
|
|
|
|
import flash.net.Socket;
|
|
|
|
import flash.utils.ByteArray;
|
|
|
|
import flash.utils.Dictionary;
|
|
|
|
import flash.utils.Timer;
|
|
|
|
import vegas.strings.JSON;
|
|
|
|
|
|
|
|
|
2014-06-07 11:34:19 -07:00
|
|
|
final public class AphlictMaster extends Aphlict {
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The pool of connected clients.
|
|
|
|
*/
|
|
|
|
private var clients:Dictionary;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A timer used to trigger periodic events.
|
|
|
|
*/
|
|
|
|
private var timer:Timer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The interval after which clients will be considered dead and removed
|
|
|
|
* from the pool.
|
|
|
|
*/
|
|
|
|
public static const PURGE_INTERVAL:Number = 3 * AphlictClient.INTERVAL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hostname for the Aphlict Server.
|
|
|
|
*/
|
|
|
|
private var remoteServer:String;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The port number for the Aphlict Server.
|
|
|
|
*/
|
|
|
|
private var remotePort:Number;
|
|
|
|
|
2014-06-11 12:17:18 -07:00
|
|
|
/**
|
|
|
|
* A dictionary mapping PHID to subscribed clients.
|
|
|
|
*/
|
|
|
|
private var subscriptions:Dictionary;
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
private var socket:Socket;
|
|
|
|
private var readBuffer:ByteArray;
|
|
|
|
|
2014-06-23 16:26:16 -07:00
|
|
|
private var status:String;
|
|
|
|
private var statusCode:String;
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
|
|
|
|
public function AphlictMaster(server:String, port:Number) {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.remoteServer = server;
|
|
|
|
this.remotePort = port;
|
|
|
|
|
2014-06-11 12:17:18 -07:00
|
|
|
this.clients = new Dictionary();
|
|
|
|
this.subscriptions = new Dictionary();
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
// Connect to the Aphlict Server.
|
|
|
|
this.recv.connect('aphlict_master');
|
|
|
|
this.connectToServer();
|
|
|
|
|
|
|
|
// Start a timer and regularly purge dead clients.
|
|
|
|
this.timer = new Timer(AphlictMaster.PURGE_INTERVAL);
|
|
|
|
this.timer.addEventListener(TimerEvent.TIMER, this.purgeClients);
|
|
|
|
this.timer.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a @{class:AphlictClient}.
|
|
|
|
*/
|
|
|
|
public function register(client:String):void {
|
|
|
|
if (!this.clients[client]) {
|
|
|
|
this.log('Registering client: ' + client);
|
|
|
|
this.clients[client] = new Date().getTime();
|
2014-06-23 16:26:16 -07:00
|
|
|
|
|
|
|
this.send.send(client, 'setStatus', this.status, this.statusCode);
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Purge stale client connections from the client pool.
|
|
|
|
*/
|
|
|
|
private function purgeClients(event:TimerEvent):void {
|
|
|
|
for (var client:String in this.clients) {
|
|
|
|
var checkin:Number = this.clients[client];
|
|
|
|
|
|
|
|
if (new Date().getTime() - checkin > AphlictMaster.PURGE_INTERVAL) {
|
|
|
|
this.log('Purging client: ' + client);
|
|
|
|
delete this.clients[client];
|
2014-06-11 16:36:01 -07:00
|
|
|
|
|
|
|
this.log('Removing client subscriptions: ' + client);
|
|
|
|
this.unsubscribeAll(client);
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clients will regularly "ping" the master to let us know that they are
|
|
|
|
* still alive. We will "pong" them back to let the client know that the
|
|
|
|
* master is still alive.
|
|
|
|
*/
|
|
|
|
public function ping(client:String):void {
|
|
|
|
this.clients[client] = new Date().getTime();
|
|
|
|
this.send.send(client, 'pong');
|
|
|
|
}
|
|
|
|
|
|
|
|
private function connectToServer():void {
|
2014-06-23 16:26:16 -07:00
|
|
|
this.setStatusOnClients('connecting');
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
var socket:Socket = new Socket();
|
|
|
|
|
|
|
|
socket.addEventListener(Event.CONNECT, didConnectSocket);
|
|
|
|
socket.addEventListener(Event.CLOSE, didCloseSocket);
|
|
|
|
socket.addEventListener(ProgressEvent.SOCKET_DATA, didReceiveSocket);
|
|
|
|
|
|
|
|
socket.addEventListener(IOErrorEvent.IO_ERROR, didIOErrorSocket);
|
|
|
|
socket.addEventListener(
|
|
|
|
SecurityErrorEvent.SECURITY_ERROR,
|
|
|
|
didSecurityErrorSocket);
|
|
|
|
|
|
|
|
socket.connect(this.remoteServer, this.remotePort);
|
|
|
|
|
|
|
|
this.readBuffer = new ByteArray();
|
|
|
|
this.socket = socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function didConnectSocket(event:Event):void {
|
2014-06-23 16:26:16 -07:00
|
|
|
this.setStatusOnClients('connected');
|
2014-06-11 12:17:18 -07:00
|
|
|
|
|
|
|
// Send subscriptions
|
|
|
|
var phids = new Array();
|
|
|
|
for (var phid:String in this.subscriptions) {
|
|
|
|
phids.push(phid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (phids.length) {
|
|
|
|
this.sendSubscribeCommand(phids);
|
|
|
|
}
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private function didCloseSocket(event:Event):void {
|
|
|
|
this.externalInvoke('close');
|
|
|
|
}
|
|
|
|
|
|
|
|
private function didIOErrorSocket(event:IOErrorEvent):void {
|
|
|
|
this.externalInvoke('error', event.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function didSecurityErrorSocket(event:SecurityErrorEvent):void {
|
2014-06-23 16:26:16 -07:00
|
|
|
var text = event.text;
|
|
|
|
|
|
|
|
// This is really gross but there doesn't seem to be anything else
|
|
|
|
// on the object which gives us an error code.
|
|
|
|
if (text.match(/^Error #2048/)) {
|
|
|
|
this.setStatusOnClients('error', 'error.flash.xdomain');
|
|
|
|
}
|
|
|
|
|
|
|
|
this.error(text);
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
|
2014-06-11 12:17:18 -07:00
|
|
|
public function subscribe(client:String, phids:Array):void {
|
|
|
|
var newPHIDs = new Array();
|
|
|
|
|
|
|
|
for (var i:String in phids) {
|
|
|
|
var phid = phids[i];
|
|
|
|
if (!this.subscriptions[phid]) {
|
|
|
|
this.subscriptions[phid] = new Dictionary();
|
|
|
|
newPHIDs.push(phid);
|
|
|
|
}
|
|
|
|
this.subscriptions[phid][client] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newPHIDs.length) {
|
|
|
|
this.sendSubscribeCommand(newPHIDs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-11 16:36:01 -07:00
|
|
|
private function getSubscriptions(client:String):Array {
|
|
|
|
var subscriptions = new Array();
|
|
|
|
|
|
|
|
for (var phid:String in this.subscriptions) {
|
|
|
|
var clients = this.subscriptions[phid];
|
|
|
|
if (clients[client]) {
|
|
|
|
subscriptions.push(phid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return subscriptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function unsubscribeAll(client:String):void {
|
|
|
|
this.unsubscribe(client, this.getSubscriptions(client));
|
|
|
|
}
|
|
|
|
|
2014-06-11 12:17:18 -07:00
|
|
|
public function unsubscribe(client:String, phids:Array):void {
|
|
|
|
var oldPHIDs = new Array();
|
|
|
|
|
2014-06-11 16:36:01 -07:00
|
|
|
for (var i:String in phids) {
|
|
|
|
var phid = phids[i];
|
|
|
|
|
2014-06-11 12:17:18 -07:00
|
|
|
if (!this.subscriptions[phid]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete this.subscriptions[phid][client];
|
|
|
|
|
|
|
|
var empty = true;
|
|
|
|
for (var key:String in this.subscriptions[phid]) {
|
|
|
|
empty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty) {
|
|
|
|
delete this.subscriptions[phid];
|
|
|
|
oldPHIDs.push(phid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldPHIDs.length) {
|
|
|
|
this.sendUnsubscribeCommand(oldPHIDs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function sendSubscribeCommand(phids:Array):void {
|
|
|
|
var msg:Dictionary = new Dictionary();
|
|
|
|
msg['command'] = 'subscribe';
|
|
|
|
msg['data'] = phids;
|
|
|
|
|
|
|
|
this.log('Sending subscribe command to server.');
|
|
|
|
this.socket.writeUTF(vegas.strings.JSON.serialize(msg));
|
|
|
|
this.socket.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
private function sendUnsubscribeCommand(phids:Array):void {
|
|
|
|
var msg:Dictionary = new Dictionary();
|
|
|
|
msg['command'] = 'unsubscribe';
|
|
|
|
msg['data'] = phids;
|
|
|
|
|
|
|
|
this.log('Sending subscribe command to server.');
|
|
|
|
this.socket.writeUTF(vegas.strings.JSON.serialize(msg));
|
|
|
|
this.socket.flush();
|
|
|
|
}
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
private function didReceiveSocket(event:Event):void {
|
2014-06-05 09:41:46 -07:00
|
|
|
try {
|
|
|
|
var b:ByteArray = this.readBuffer;
|
|
|
|
this.socket.readBytes(b, b.length);
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
|
2014-06-05 09:41:46 -07:00
|
|
|
do {
|
|
|
|
b = this.readBuffer;
|
|
|
|
b.position = 0;
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
|
2014-06-05 09:41:46 -07:00
|
|
|
if (b.length <= 8) {
|
|
|
|
break;
|
|
|
|
}
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
|
2014-06-05 09:41:46 -07:00
|
|
|
var msg_len:Number = parseInt(b.readUTFBytes(8), 10);
|
|
|
|
if (b.length >= msg_len + 8) {
|
|
|
|
var bytes:String = b.readUTFBytes(msg_len);
|
|
|
|
var data:Object = vegas.strings.JSON.deserialize(bytes);
|
|
|
|
var t:ByteArray = new ByteArray();
|
|
|
|
t.writeBytes(b, msg_len + 8);
|
|
|
|
this.readBuffer = t;
|
|
|
|
|
|
|
|
// Send the message to all clients.
|
|
|
|
for (var client:String in this.clients) {
|
2014-06-11 12:17:18 -07:00
|
|
|
var subscribed = false;
|
|
|
|
|
|
|
|
for (var i:String in data.subscribers) {
|
|
|
|
var phid = data.subscribers[i];
|
|
|
|
|
|
|
|
if (this.subscriptions[phid] &&
|
|
|
|
this.subscriptions[phid][client]) {
|
|
|
|
subscribed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subscribed) {
|
|
|
|
this.log('Sending message to client: ' + client);
|
|
|
|
this.send.send(client, 'receiveMessage', data);
|
|
|
|
}
|
2014-06-05 09:41:46 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
2014-06-05 09:41:46 -07:00
|
|
|
} while (true);
|
|
|
|
} catch (err:Error) {
|
|
|
|
this.error(err);
|
|
|
|
}
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
|
2014-06-23 16:26:16 -07:00
|
|
|
private function setStatusOnClients(
|
|
|
|
status:String,
|
|
|
|
code:String = null):void {
|
|
|
|
|
|
|
|
this.status = status;
|
|
|
|
this.statusCode = code;
|
|
|
|
|
|
|
|
for (var client:String in this.clients) {
|
|
|
|
this.send.send(client, 'setStatus', status, code);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Modify the Aphlict client to use `LocalConnection`.
Summary:
Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server.
Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object.
Roughly this works as follows:
# The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages.
# The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool.
# Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master.
Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results.
Reviewers: #blessed_reviewers, epriestley
Reviewed By: #blessed_reviewers, epriestley
Subscribers: epriestley, Korvin
Maniphest Tasks: T4324
Differential Revision: https://secure.phabricator.com/D9327
2014-05-29 07:04:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|