mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-21 13:00:56 +01:00
76cefde0b3
Summary: Fixes T5373. Ref T5281. Several changes: - The `marshallExceptions` thing is useful if JS throws an exception when invoked from Flash, so set it. The resulting exceptions are a little odd (not escaped correctly, e.g.) but way better than nothing. - Put connection status in the notification menu. - When the connection fails, try to provide contextual help where we can. Test Plan: {F169493} Reviewers: chad, joshuaspence Reviewed By: joshuaspence Subscribers: epriestley Maniphest Tasks: T5281, T5373 Differential Revision: https://secure.phabricator.com/D9700
160 lines
4.4 KiB
ActionScript
160 lines
4.4 KiB
ActionScript
package {
|
|
|
|
import flash.events.TimerEvent;
|
|
import flash.external.ExternalInterface;
|
|
import flash.utils.Dictionary;
|
|
import flash.utils.Timer;
|
|
import flash.events.UncaughtErrorEvent;
|
|
|
|
final public class AphlictClient extends Aphlict {
|
|
|
|
/**
|
|
* The connection name for this client. This will be used for the
|
|
* @{class:LocalConnection} object.
|
|
*/
|
|
private var client:String;
|
|
|
|
/**
|
|
* The expiry timestamp for the @{class:AphlictMaster}. If this time is
|
|
* elapsed then the master will be assumed to be dead and another
|
|
* @{class:AphlictClient} will create a master.
|
|
*/
|
|
private var expiry:Number = 0;
|
|
|
|
/**
|
|
* The interval at which to ping the @{class:AphlictMaster}.
|
|
*/
|
|
public static const INTERVAL:Number = 3000;
|
|
|
|
private var master:AphlictMaster;
|
|
private var timer:Timer;
|
|
|
|
private var remoteServer:String;
|
|
private var remotePort:Number;
|
|
private var subscriptions:Array;
|
|
|
|
|
|
public function AphlictClient() {
|
|
super();
|
|
|
|
loaderInfo.uncaughtErrorEvents.addEventListener(
|
|
UncaughtErrorEvent.UNCAUGHT_ERROR,
|
|
this.uncaughtErrorHandler);
|
|
|
|
ExternalInterface.marshallExceptions = true;
|
|
ExternalInterface.addCallback('connect', this.externalConnect);
|
|
|
|
this.setStatus('ready');
|
|
}
|
|
|
|
private function uncaughtErrorHandler(event:UncaughtErrorEvent):void {
|
|
this.error(event.error.toString());
|
|
}
|
|
|
|
public function externalConnect(
|
|
server:String,
|
|
port:Number,
|
|
subscriptions:Array):void {
|
|
|
|
this.remoteServer = server;
|
|
this.remotePort = port;
|
|
this.subscriptions = subscriptions;
|
|
|
|
this.client = AphlictClient.generateClientId();
|
|
this.recv.connect(this.client);
|
|
|
|
this.timer = new Timer(AphlictClient.INTERVAL);
|
|
this.timer.addEventListener(TimerEvent.TIMER, this.keepalive);
|
|
|
|
this.connectToMaster();
|
|
}
|
|
|
|
/**
|
|
* Generate a unique identifier that will be used to communicate with the
|
|
* @{class:AphlictMaster}.
|
|
*/
|
|
private static function generateClientId():String {
|
|
return 'aphlict_client_' + Math.round(Math.random() * 100000);
|
|
}
|
|
|
|
/**
|
|
* Create a new connection to the @{class:AphlictMaster}.
|
|
*
|
|
* If there is no current @{class:AphlictMaster} instance, then a new master
|
|
* will be created.
|
|
*/
|
|
private function connectToMaster():void {
|
|
this.timer.stop();
|
|
|
|
// Try to become the master.
|
|
try {
|
|
this.log('Attempting to become the master...');
|
|
this.master = new AphlictMaster(this.remoteServer, this.remotePort);
|
|
this.log('I am the master.');
|
|
} catch (err:ArgumentError) {
|
|
this.log('Cannot become the master... probably one already exists');
|
|
} catch (err:Error) {
|
|
this.error(err);
|
|
}
|
|
|
|
this.registerWithMaster();
|
|
this.timer.start();
|
|
}
|
|
|
|
/**
|
|
* Register our client ID with the @{class:AphlictMaster} and send our
|
|
* subscriptions.
|
|
*/
|
|
private function registerWithMaster():void {
|
|
this.send.send('aphlict_master', 'register', this.client);
|
|
this.expiry = new Date().getTime() + (5 * AphlictClient.INTERVAL);
|
|
this.log('Registered client ' + this.client);
|
|
|
|
// Send subscriptions to master.
|
|
this.log('Sending subscriptions to master.');
|
|
this.send.send(
|
|
'aphlict_master',
|
|
'subscribe',
|
|
this.client,
|
|
this.subscriptions);
|
|
}
|
|
|
|
/**
|
|
* Send a keepalive signal to the @{class:AphlictMaster}.
|
|
*
|
|
* If the connection to the master has expired (because the master has not
|
|
* sent a heartbeat signal), then a new connection to master will be
|
|
* created.
|
|
*/
|
|
private function keepalive(event:TimerEvent):void {
|
|
if (new Date().getTime() > this.expiry) {
|
|
this.connectToMaster();
|
|
}
|
|
|
|
this.send.send('aphlict_master', 'ping', this.client);
|
|
}
|
|
|
|
/**
|
|
* This function is used to receive the heartbeat signal from the
|
|
* @{class:AphlictMaster}.
|
|
*/
|
|
public function pong():void {
|
|
this.expiry = new Date().getTime() + (2 * AphlictClient.INTERVAL);
|
|
}
|
|
|
|
/**
|
|
* Receive a message from the Aphlict Server, via the
|
|
* @{class:AphlictMaster}.
|
|
*/
|
|
public function receiveMessage(msg:Object):void {
|
|
this.log('Received message.');
|
|
this.externalInvoke('receive', msg);
|
|
}
|
|
|
|
public function setStatus(status:String, code:String = null):void {
|
|
this.externalInvoke('status', {type: status, code: code});
|
|
}
|
|
|
|
}
|
|
|
|
}
|