File: lib/marionette/drivers/abstract.js
(function(module, ns) {
/**
*
* Abstract driver that will handle
* all common tasks between implementations.
* Such as error handling, request/response queuing
* and timeouts.
*
* @constructor
* @class Marionette.Drivers.Abstract
* @param {Object} options set options on prototype.
*/
function Abstract(options) {
this._sendQueue = [];
this._responseQueue = [];
}
Abstract.prototype = {
/**
* Timeout for commands
*
* @property timeout
* @type Numeric
*/
timeout: 10000,
/**
* Waiting for a command to finish?
*
* @private
* @property _waiting
* @type Boolean
*/
_waiting: true,
/**
* Is system ready for commands?
*
* @property ready
* @type Boolean
*/
ready: false,
/**
* Connection id for the server.
*
* @property connectionId
* @type Numeric
*/
connectionId: null,
/**
* We just set the script timeout.
* If you need to do something in the driver.
*
* @method setScriptTiemout
* @param {Integer} the timeout value.
*/
setScriptTimeout: function setScriptTimeout(timeout) {
},
/**
* Sends remote command to server.
* Each command will be queued while waiting for
* any pending commands. This ensures order of
* response is correct.
*
*
* @method send
* @param {Object} command remote command to send to marionette.
* @param {Function} callback executed when response comes back.
*/
send: function send(cmd, callback) {
if (!this.ready) {
throw new Error('connection is not ready');
}
if (typeof(callback) === 'undefined') {
throw new Error('callback is required');
}
this._responseQueue.push(callback);
this._sendQueue.push(cmd);
this._nextCommand();
return this;
},
/**
* Connects to a remote server.
* Requires a _connect function to be defined.
*
* MyClass.prototype._connect = function _connect(){
* //open a socket to marrionete accept response
* //you *must* call _onDeviceResponse with the first
* //response from marionette it looks like this:
* //{ from: 'root', applicationType: 'gecko', traits: [] }
* this.connectionId = result.id;
* }
*
* @method connect
* @param {Function} callback executes
* after successfully connecting to the server.
*/
connect: function connect(callback) {
this.ready = true;
this._responseQueue.push(function(data) {
this.applicationType = data.applicationType;
this.traits = data.traits;
callback();
}.bind(this));
this._connect();
},
/**
* Destroys connection to server
*
* Will immediately close connection to server
* closing any pending responses.
*
* @method close
*/
close: function() {
this.ready = false;
this._responseQueue.length = 0;
if (this._close) {
this._close();
}
},
/**
* Checks queue if not waiting for a response
* Sends command to websocket server
*
* @private
* @method _nextCommand
*/
_nextCommand: function _nextCommand() {
var nextCmd;
if (!this._waiting && this._sendQueue.length) {
this._waiting = true;
nextCmd = this._sendQueue.shift();
this._sendCommand(nextCmd);
}
},
/**
* Handles responses from devices.
* Will only respond to the event if the connectionId
* is equal to the event id and the client is ready.
*
* @param {Object} data response from server.
* @private
* @method _onDeviceResponse
*/
_onDeviceResponse: function _onDeviceResponse(data) {
var cb;
if (this.ready && data.id === this.connectionId) {
this._waiting = false;
cb = this._responseQueue.shift();
cb(data.response);
this._nextCommand();
}
}
};
module.exports = Abstract;
}.apply(
this,
(this.Marionette) ?
[Marionette('drivers/abstract'), Marionette] :
[module, require('../marionette')]
));