Skip to content

Instantly share code, notes, and snippets.

@quinkennedy
Forked from robotconscience/gist:2226632
Created May 12, 2012 19:49
Show Gist options
  • Save quinkennedy/2668550 to your computer and use it in GitHub Desktop.
Save quinkennedy/2668550 to your computer and use it in GitHub Desktop.
ecs.js
// BIND FIX FOR OLDER BROWSERS
if( Function.prototype.bind ) {
} else {
/** safari, why you no bind!? */
Function.prototype.bind = function (bind) {
var self = this;
return function () {
var args = Array.prototype.slice.call(arguments);
return self.apply(bind || null, args);
};
};
}
/*!
* \namespace ECSjs
* \brief An javascript library to connect to ECS installation.
* <br />Copyright (C) 2012 LAB at Rockwell Group http://lab.rockwellgroup.com
*
* @author The Lab
* @modified 05/11/2012
* @version 0.0.3
*/
var ECSjs = {}
/*! \class ECSjs::Connection
\brief Creates a new ECS connection with host
*/
ECSjs.Connection = function( framework ){
this.bConnected = false
this.framework = framework || ECSjs.ECS;
this.onConnectHooks = [];
this.onDisconnectHooks = [];
this.onMessageHooks = [];
this.onStartHooks = [];
this.onStopHooks = [];
this.onFileHooks = [];
this.onStartupHooks = [];
this.onActivateHooks = [];
this.onDeactivateHooks = [];
this.onShutdownHooks = [];
};
/*! \fn ECSjs::Connection::connect
* \brief Setup ECS connection
* \memberof ECSjs::Connection
* \param host (optional) The host of the ecsc that this application should connect to. Defaults to 127.0.0.1. You must specify a host if you are connecting to a remote ECS server.
* \param port (optional) The port on the host of the ecsc that this application should connect to. Defaults to 7847 (ECS default). You must specify a port if you change the port your local or remote ECS server is running on.
* \param channel (optional) The websocket channel that this application should use to connect to the host. Defalut to "/"
* \param role (optional) The ECS role that this application is fulfilling
*
*/
ECSjs.Connection.prototype.connect = function( host, port, channel, role ) {
this.role = role || "";
this.host = host || "127.0.0.1";
this.port = port || 7847;
this.channel = channel || "/";
this.socket = new WebSocket("ws://"+this.host+":"+this.port+this.channel);
this.socket._parent = this;
this.socket.onmessage = this.onWSMessage.bind(this);
this.socket.onopen = this.onConnectionOpened.bind(this);
this.socket.onclose = this.onConnectionClosed.bind(this);
};
/*!
* \fn ECSjs::Connection::sendMessage
* \brief Send an ECS message
* \memberof ECSjs::Connection
* \param key The name of the route you are sending.
* \param value the value you are sending
*/
ECSjs.Connection.prototype.sendMessage = function( key, value ) {
if (!this.bConnected){
if (console) console.warn("Not connected!");
return;
}
if( this.framework == ECSjs.ECS ) {
this.socket.send( "<route_update><configs><config><name>"+key+"</name><value>"+value+"</value></config></configs></route_update>" );
} else {
value['route'] = key;
this.socket.send( JSON.stringify(value) );
}
};
/*!
* \fn ECSjs::Connection::onMessage
* \brief Pass in a function to receive messages from ECS
* \memberof ECSjs::Connection
* \param fun function you would like to be called; must catch (key, value)
*/
ECSjs.Connection.prototype.onMessage = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onMessage is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onMessageHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onConnect
* \brief Pass in a function in your add a listener to "connect" events from ECS.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onConnect = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onConnect is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onConnectHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onDisconnect
* \brief Pass in a function in your add a listener to "disconnect" events
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onDisconnect = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onDisconnect is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onDisconnectHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onStart
* \brief Pass in a function in your add a listener to "start" events from ECS.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onStart = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onStart is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onStartHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onStop
* \brief Pass in a function in your add a listener to "stop" events from ECS.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onStop = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onStop is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onStopHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onStartup
* \brief Pass in a function in your add a listener to "startup" events from Interactive Spaces.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onStartup = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onStartup is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onStartupHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onActivate
* \brief Pass in a function in your add a listener to "activate" events from Interactive Spaces.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onActivate = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onActivate is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onActivateHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onDeactivate
* \brief Pass in a function in your add a listener to "deactivate" events from Interactive Spaces.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onDeactivate = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onDeactivate is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onDeactivateHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onShutdown
* \brief Pass in a function in your add a listener to "shutdown" events from Interactive Spaces.
* \memberof ECSjs::Connection
* \param fun function you would like to be called
*/
ECSjs.Connection.prototype.onShutdown = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onShutdown is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onShutdownHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onFile
* \brief Pass in a function to receive files from ECS
* \memberof ECSjs::Connection
* \param fun function you would like to be called; must catch (filepath)
*/
ECSjs.Connection.prototype.onFile = function( fun ) {
if ( typeof fun !== "function" ){
console.warn( "method passed to ECSjs.Connection.onFile is not a function");
} else {
// DEV NOTE: SHOULD WE CHECK FOR DUPLICATES?
this.onFileHooks.push( fun );
}
};
/*!
* \fn ECSjs::Connection::onConnectionOpened
* \memberof ECSjs::Connection
* \private
*/
ECSjs.Connection.prototype.onConnectionOpened = function() {
this.bConnected = true;
if (console) console.log("ECS connected");
if( this.framework == ECSjs.ECS ) {
this.socket.send("<application_message><role>"+this.role+"</role></application_message>");
}
this.callAllFuncInArray(this.onConnectHooks);
};
/*!
* \fn ECSjs::Connection::onConnectionClosed
* \memberof ECSjs::Connection
* \private
*/
ECSjs.Connection.prototype.onConnectionClosed = function() {
this.bConnected = false;
this.callAllFuncInArray(this.onDisconnectHooks);
};
/*!
* \fn ECSjs::Connection::callAllFuncInArray
* \brief A utility function to call every function in an array of functions without any arguments
* \memberof ECSjs::Connection
* \private
*/
ECSjs.Connection.prototype.callAllFuncInArray = function(array){
for(var i in array){
array[i]();
};
};
/*!
* \fn ECSjs::Connection::onWSMessage
* \memberof ECSjs::Connection
* \private
*/
ECSjs.Connection.prototype.onWSMessage = function( evt ) {
if( this.framework == ECSjs.ECS ) {
var xml;
if (window.DOMParser){
var parser=new DOMParser();
xml = parser.parseFromString(evt.data, "text/xml");
} else {
// Internet Explorer
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async=false;
xml.loadXML(evt.data);
}
if (evt.data.indexOf("route_update") >= 0) {
var configs = xml.getElementsByTagName("configs")[0].childNodes;
for (var i=0; i < configs.length; i++) {
var name = null;
var value = null;
var curConfig = configs[i];
// Config name
var n = curConfig.getElementsByTagName("name")[0];
name = n.childNodes[0].nodeValue;
// Config value
var val = curConfig.getElementsByTagName("value")[0];
value = val.childNodes[0].nodeValue;
// Invoke route update method if we have a complete name/value pair
if (name != null && value != null) {
for (var i=0; i<this.onMessageHooks.length; i++){
this.onMessageHooks[i](name, value);
};
}
}
} else if (evt.data.indexOf("application_message") >= 0) {
var action = xml.getElementsByTagName("action")[0];
var a = action.childNodes[0].nodeValue;
if (a == "start"){
this.callAllFuncInArray(this.onStartHooks);
} else if (a == "stop"){
this.callAllFuncInArray(this.onStopHooks);
}
} else if (evt.data.indexOf("file_transfer") >= 0) {
var action = xml.getElementsByTagName("filepath")[0];
var fp = action.childNodes[0].nodeValue;
// Invoke the file transfer method with the file path
if (fp != null && !fp.equals("")) {
for (var i=0; i<this.onFileHooks.length; i++){
this.onFileHooks[i](fp);
}
}
}
} else if (this.framework == ECSjs.INTERACTIVE_SPACES){
var dataObj = JSON.parse( evt.data );
if (dataObj.route == "state"){
switch (dataObj.data.state){
case "startup":
this.callAllFuncInArray(this.onStartupHooks);
break;
case "activate":
this.callAllFuncInArray(this.onActivateHooks);
break;
case "deactivate":
this.callAllFuncInArray(this.onDeactivateHooks);
break;
case "shutdown":
this.callAllFuncInArray(this.onShutdownHooks);
break;
default:
console.warn( "state passed via websocket is unexpected:");
console.warn(dataObj);
break;
}
} else {
this.defaultMessageHandling(evt);
}
} else {
this.defaultMessageHandling(evt);
}
};
/*!
* \fn ECSjs::Connection::defaultMessageHandling
* \brief Handles the default functionality for onWSMessage
* \memberof ECSjs::Connection
* \private
*/
ECSjs.Connection.prototype.defaultMessageHandling = function(evt){
var dataObj = JSON.parse( evt.data );
if ( dataObj.route ) {
for (var i=0; i<this.onMessageHooks.length; i++){
this.onMessageHooks[i](dataObj.route, dataObj.data);
};
} else {
for (var i=0; i<this.onMessageHooks.length; i++){
this.onMessageHooks[i]( "route", dataObj );
};
}
}
/** @constant */
ECSjs.ECS = "ecs";
/** @constant */
ECSjs.INTERACTIVE_SPACES = "interactiveSpaces";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment