Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14475240
D9327.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D9327.id.diff
View Options
diff --git a/support/aphlict/client/build_aphlict_client.sh b/support/aphlict/client/build_aphlict_client.sh
--- a/support/aphlict/client/build_aphlict_client.sh
+++ b/support/aphlict/client/build_aphlict_client.sh
@@ -9,20 +9,13 @@
fi;
set -e
-set -x
-# cp -R $ROOT/externals/vegas/src $BASEDIR/src/vegas
-
-(cd $BASEDIR && $MXMLC \
- -output aphlict.swf \
+$MXMLC \
+ -output=$ROOT/webroot/rsrc/swf/aphlict.swf \
-default-background-color=0x444444 \
-default-size=500,500 \
-warnings=true \
-debug=true \
-source-path=$ROOT/externals/vegas/src \
-static-link-runtime-shared-libraries=true \
- src/Aphlict.as)
-
-mv $BASEDIR/aphlict.swf $ROOT/webroot/rsrc/swf/aphlict.swf
-
-# -target-player=10.2.0 \
+ $BASEDIR/src/AphlictClient.as
diff --git a/support/aphlict/client/src/Aphlict.as b/support/aphlict/client/src/Aphlict.as
--- a/support/aphlict/client/src/Aphlict.as
+++ b/support/aphlict/client/src/Aphlict.as
@@ -1,117 +1,38 @@
package {
- import flash.net.*;
- import flash.utils.*;
- import flash.media.*;
- import flash.display.*;
- import flash.events.*;
+ import flash.display.Sprite;
import flash.external.ExternalInterface;
+ import flash.net.LocalConnection;
- import vegas.strings.JSON;
public class Aphlict extends Sprite {
- private var client:String;
+ /**
+ * A transport channel used to receive data.
+ */
+ protected var recv:LocalConnection;
- private var socket:Socket;
- private var readBuffer:ByteArray;
+ /**
+ * A transport channel used to send data.
+ */
+ protected var send:LocalConnection;
- private var remoteServer:String;
- private var remotePort:Number;
public function Aphlict() {
super();
- ExternalInterface.addCallback('connect', this.externalConnect);
- ExternalInterface.call(
- 'JX.Stratcom.invoke',
- 'aphlict-component-ready',
- null,
- {});
- }
-
- public function externalConnect(server:String, port:Number):void {
- this.externalInvoke('connect');
-
- this.remoteServer = server;
- this.remotePort = port;
-
- this.connectToServer();
- }
-
-
- public function connectToServer():void {
- 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 {
- this.externalInvoke('connected');
- }
-
- 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 {
- this.externalInvoke('error', event.text);
- }
-
- private function didReceiveSocket(event:Event):void {
- var b:ByteArray = this.readBuffer;
- this.socket.readBytes(b, b.length);
-
- do {
- b = this.readBuffer;
- b.position = 0;
-
- if (b.length <= 8) {
- break;
- }
-
- 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;
-
- this.receiveMessage(data);
- } else {
- break;
- }
- } while (true);
-
- }
+ this.recv = new LocalConnection();
+ this.recv.client = this;
- public function receiveMessage(msg:Object):void {
- this.externalInvoke('receive', msg);
+ this.send = new LocalConnection();
}
- public function externalInvoke(type:String, object:Object = null):void {
+ protected function externalInvoke(type:String, object:Object = null):void {
ExternalInterface.call('JX.Aphlict.didReceiveEvent', type, object);
}
- public function log(message:String):void {
- ExternalInterface.call('console.log', message);
+ protected function log(message:String):void {
+ this.externalInvoke('log', message);
}
}
diff --git a/support/aphlict/client/src/AphlictClient.as b/support/aphlict/client/src/AphlictClient.as
new file mode 100644
--- /dev/null
+++ b/support/aphlict/client/src/AphlictClient.as
@@ -0,0 +1,129 @@
+package {
+
+ import flash.events.TimerEvent;
+ import flash.external.ExternalInterface;
+ import flash.utils.Timer;
+
+
+ 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;
+
+
+ public function AphlictClient() {
+ super();
+
+ ExternalInterface.addCallback('connect', this.externalConnect);
+ ExternalInterface.call(
+ 'JX.Stratcom.invoke',
+ 'aphlict-component-ready',
+ null,
+ {});
+ }
+
+ public function externalConnect(server:String, port:Number):void {
+ this.externalInvoke('connect');
+
+ this.remoteServer = server;
+ this.remotePort = port;
+
+ 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 (x:Error) {
+ // Couldn't become the master
+ this.log('Cannot become the master... probably one already exists');
+ }
+
+ this.send.send('aphlict_master', 'register', this.client);
+ this.expiry = new Date().getTime() + (5 * AphlictClient.INTERVAL);
+ this.log('Registered client ' + this.client);
+
+ this.timer.start();
+ }
+
+ /**
+ * 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);
+ }
+
+ }
+
+}
diff --git a/support/aphlict/client/src/AphlictMaster.as b/support/aphlict/client/src/AphlictMaster.as
new file mode 100644
--- /dev/null
+++ b/support/aphlict/client/src/AphlictMaster.as
@@ -0,0 +1,166 @@
+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;
+
+
+ public class AphlictMaster extends Aphlict {
+
+ /**
+ * 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;
+
+ private var socket:Socket;
+ private var readBuffer:ByteArray;
+
+
+ public function AphlictMaster(server:String, port:Number) {
+ super();
+
+ this.remoteServer = server;
+ this.remotePort = port;
+
+ // Connect to the Aphlict Server.
+ this.recv.connect('aphlict_master');
+ this.connectToServer();
+
+ this.clients = new Dictionary();
+
+ // 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();
+ }
+ }
+
+ /**
+ * 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];
+ }
+ }
+ }
+
+ /**
+ * 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 {
+ 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 {
+ this.externalInvoke('connected');
+ }
+
+ 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 {
+ this.externalInvoke('error', event.text);
+ }
+
+ private function didReceiveSocket(event:Event):void {
+ var b:ByteArray = this.readBuffer;
+ this.socket.readBytes(b, b.length);
+
+ do {
+ b = this.readBuffer;
+ b.position = 0;
+
+ if (b.length <= 8) {
+ break;
+ }
+
+ 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) {
+ this.log('Sending message to client: ' + client);
+ this.send.send(client, 'receiveMessage', data);
+ }
+ } else {
+ break;
+ }
+ } while (true);
+ }
+
+ }
+
+}
diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 28, 6:16 PM (1 h, 22 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6940687
Default Alt Text
D9327.id.diff (13 KB)
Attached To
Mode
D9327: Modify the Aphlict client to use `LocalConnection`.
Attached
Detach File
Event Timeline
Log In to Comment