Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/application/aphlict/Aphlict.js
| /** | /** | ||||
| * @provides javelin-aphlict | * @provides javelin-aphlict | ||||
| * @requires javelin-install | * @requires javelin-install | ||||
| * javelin-util | * javelin-util | ||||
| * javelin-websocket | |||||
| * javelin-leader | |||||
| * javelin-json | |||||
| */ | */ | ||||
| /** | /** | ||||
| * Simple JS API for the Flash Aphlict client. Example usage: | * Client for the notification server. Example usage: | ||||
| * | * | ||||
| * var aphlict = new JX.Aphlict('aphlict_swf', '127.0.0.1', 22280) | * var aphlict = new JX.Aphlict('ws://localhost:22280', subscriptions) | ||||
| * .setHandler(function(type, message) { | * .setHandler(function(message) { | ||||
| * JX.log("Got " + type + " event!") | * // ... | ||||
| * }) | * }) | ||||
| * .start(); | * .start(); | ||||
| * | * | ||||
| * Your handler will receive these events: | |||||
| * | |||||
| * - `connect` The client initiated a connection to the server. | |||||
| * - `connected` The client completed a connection to the server. | |||||
| * - `close` The client disconnected from the server. | |||||
| * - `error` There was an error. | |||||
| * - `receive` Received a message from the server. | |||||
| * | |||||
| * You do not have to handle any of them in any specific way. | |||||
| */ | */ | ||||
| JX.install('Aphlict', { | JX.install('Aphlict', { | ||||
| construct: function(id, server, port, subscriptions) { | construct: function(uri, subscriptions) { | ||||
| if (__DEV__) { | if (__DEV__) { | ||||
| if (JX.Aphlict._instance) { | if (JX.Aphlict._instance) { | ||||
| JX.$E('Aphlict object is a singleton.'); | JX.$E('Aphlict object is a singleton.'); | ||||
| } | } | ||||
| } | } | ||||
| this._id = id; | this._uri = uri; | ||||
| this._server = server; | |||||
| this._port = port; | |||||
| this._subscriptions = subscriptions; | this._subscriptions = subscriptions; | ||||
| this._setStatus('setup'); | this._setStatus('setup'); | ||||
| JX.Aphlict._instance = this; | JX.Aphlict._instance = this; | ||||
| }, | }, | ||||
| events: ['didChangeStatus'], | events: ['didChangeStatus'], | ||||
| members: { | members: { | ||||
| _id: null, | |||||
| _server: null, | _server: null, | ||||
| _port: null, | _port: null, | ||||
| _subscriptions: null, | _subscriptions: null, | ||||
| _status: null, | _status: null, | ||||
| _statusCode: null, | _statusCode: null, | ||||
| start: function(node, uri) { | start: function(node, uri) { | ||||
| this._setStatus('start'); | JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead)); | ||||
| JX.Leader.listen('onReceiveBroadcast', JX.bind(this, this._receive)); | |||||
| JX.Leader.start(); | |||||
| // NOTE: This is grotesque, but seems to work everywhere. | JX.Leader.call(JX.bind(this, this._begin)); | ||||
| node.innerHTML = | |||||
| '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">' + | |||||
| '<param name="movie" value="' + uri + '" />' + | |||||
| '<param name="allowScriptAccess" value="always" />' + | |||||
| '<param name="wmode" value="opaque" />' + | |||||
| '<embed src="' + uri + '" wmode="opaque"' + | |||||
| 'width="0" height="0" id="' + this._id + '">' + | |||||
| '</embed>' + | |||||
| '</object>'; | |||||
| }, | |||||
| _didStartFlash: function() { | |||||
| var id = this._id; | |||||
| // Flash puts its "objects" into global scope in an inconsistent way, | |||||
| // because it was written in like 1816 when globals were awesome and IE4 | |||||
| // didn't support other scopes since global scope is the best anyway. | |||||
| var container = document[id] || window[id]; | |||||
| this._flashContainer = container; | |||||
| this._flashContainer.connect( | |||||
| this._server, | |||||
| this._port, | |||||
| this._subscriptions); | |||||
| }, | }, | ||||
| getStatus: function() { | getStatus: function() { | ||||
| return this._status; | return this._status; | ||||
| }, | }, | ||||
| getStatusCode: function() { | _begin: function() { | ||||
| return this._statusCode; | JX.Leader.broadcast( | ||||
| null, | |||||
| {type: 'aphlict.getstatus'}); | |||||
| JX.Leader.broadcast( | |||||
| null, | |||||
| {type: 'aphlict.subscribe', data: this._subscriptions}); | |||||
| }, | |||||
| _lead: function() { | |||||
| var socket = new JX.WebSocket(this._uri); | |||||
| socket.setOpenHandler(JX.bind(this, this._open)); | |||||
| socket.setMessageHandler(JX.bind(this, this._message)); | |||||
| socket.setCloseHandler(JX.bind(this, this._close)); | |||||
| this._socket = socket; | |||||
| socket.open(); | |||||
| }, | |||||
| _open: function() { | |||||
| this._broadcastStatus('open'); | |||||
| JX.Leader.broadcast(null, {type: 'aphlict.getsubscribers'}); | |||||
| }, | |||||
| _close: function() { | |||||
| this._broadcastStatus('closed'); | |||||
| }, | }, | ||||
| _setStatus: function(status, code) { | _broadcastStatus: function(status) { | ||||
| JX.Leader.broadcast(null, {type: 'aphlict.status', data: status}); | |||||
| }, | |||||
| _message: function(raw) { | |||||
| var message = JX.JSON.parse(raw); | |||||
| JX.Leader.broadcast(null, {type: 'aphlict.server', data: message}); | |||||
| }, | |||||
| _receive: function(message, is_leader) { | |||||
| switch (message.type) { | |||||
| case 'aphlict.status': | |||||
| this._setStatus(message.data); | |||||
| break; | |||||
| case 'aphlict.getstatus': | |||||
| if (is_leader) { | |||||
| this._broadcastStatus(this.getStatus()); | |||||
| } | |||||
| break; | |||||
| case 'aphlict.getsubscribers': | |||||
| JX.Leader.broadcast( | |||||
| null, | |||||
| {type: 'aphlict.subscribe', data: this._subscriptions}); | |||||
| break; | |||||
| case 'aphlict.subscribe': | |||||
| if (is_leader) { | |||||
| this._write({ | |||||
| command: 'subscribe', | |||||
| data: message.data | |||||
| }); | |||||
| } | |||||
| break; | |||||
| case 'aphlict.server': | |||||
| var handler = this.getHandler(); | |||||
| handler && handler(message.data); | |||||
| break; | |||||
| } | |||||
| }, | |||||
| _setStatus: function(status) { | |||||
| this._status = status; | this._status = status; | ||||
| this._statusCode = code || null; | |||||
| this.invoke('didChangeStatus'); | this.invoke('didChangeStatus'); | ||||
| }, | |||||
| _write: function(message) { | |||||
| this._socket.send(JX.JSON.stringify(message)); | |||||
| } | } | ||||
| }, | }, | ||||
| properties: { | properties: { | ||||
| handler: null | handler: null | ||||
| }, | }, | ||||
| statics: { | statics: { | ||||
| _instance: null, | _instance: null, | ||||
| getInstance: function() { | getInstance: function() { | ||||
| var self = JX.Aphlict; | var self = JX.Aphlict; | ||||
| if (!self._instance) { | if (!self._instance) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return self._instance; | return self._instance; | ||||
| }, | |||||
| didReceiveEvent: function(type, message) { | |||||
| var client = JX.Aphlict.getInstance(); | |||||
| if (!client) { | |||||
| return; | |||||
| } | } | ||||
| if (type == 'status') { | |||||
| client._setStatus(message.type, message.code); | |||||
| switch (message.type) { | |||||
| case 'ready': | |||||
| client._didStartFlash(); | |||||
| break; | |||||
| } | |||||
| } | |||||
| var handler = client.getHandler(); | |||||
| if (handler) { | |||||
| handler(type, message); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| }); | }); | ||||