2018-03-24 14:13:27 +00:00
|
|
|
export default class ClientDriver{
|
2018-03-23 17:43:59 +00:00
|
|
|
|
|
|
|
/* (0) Constants & Enums
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
static get STATE(){
|
|
|
|
|
|
|
|
return Object.freeze({
|
2018-03-24 14:13:27 +00:00
|
|
|
CLOSED: 0,
|
|
|
|
READY: 1,
|
2018-03-23 17:43:59 +00:00
|
|
|
CONNECTING: 2,
|
|
|
|
CONNECTED: 3,
|
2018-03-24 14:13:27 +00:00
|
|
|
TRANFERING: 4
|
2018-03-23 17:43:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* (1) Creates a client driver
|
|
|
|
*
|
|
|
|
* @_resource<String> Target resource (typically an URL)
|
2018-03-25 11:40:35 +00:00
|
|
|
* @_auth<mixed> Authentication data (depends on Driver implementation)
|
2018-03-23 17:43:59 +00:00
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2018-03-25 11:40:35 +00:00
|
|
|
constructor(_resource, _auth={}){
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) Initialize driver
|
|
|
|
---------------------------------------------------------*/
|
2018-03-23 17:43:59 +00:00
|
|
|
/* (1) Default attributes values */
|
2018-03-24 14:13:27 +00:00
|
|
|
this.force_close = false;
|
|
|
|
this.state = ClientDriver.STATE.READY;
|
|
|
|
this.stack = [];
|
2018-03-25 11:40:35 +00:00
|
|
|
this.error = false;
|
2018-03-24 14:13:27 +00:00
|
|
|
|
|
|
|
/* (2) Default User callbacks */
|
2018-03-23 17:43:59 +00:00
|
|
|
this.callback = {
|
2018-03-24 14:13:27 +00:00
|
|
|
onconnected: function(){},
|
|
|
|
onclose: function(){},
|
|
|
|
onreceive: function(){}
|
2018-03-23 17:43:59 +00:00
|
|
|
};
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
this.event = {
|
|
|
|
|
|
|
|
/* (3) Manage connection opened */
|
|
|
|
onconnected: function(){
|
|
|
|
|
|
|
|
// update state
|
|
|
|
this.state = ClientDriver.STATE.CONNECTED;
|
|
|
|
|
|
|
|
// call callback
|
|
|
|
this.callback.onconnected();
|
|
|
|
|
|
|
|
// if request(s) in stack -> pop & send them
|
|
|
|
while( this.stack.length > 0 )
|
|
|
|
this.send(this.stack.shift());
|
|
|
|
|
|
|
|
}.bind(this),
|
|
|
|
|
|
|
|
/* (4) Manage connection closed */
|
|
|
|
onclose: function(){
|
|
|
|
|
|
|
|
// if called close() -> CLOSED
|
|
|
|
if( this.force_close )
|
|
|
|
this.state = ClientDriver.STATE.CLOSED;
|
|
|
|
|
|
|
|
// else set state back to READY
|
|
|
|
else
|
|
|
|
this.state = ClientDriver.STATE.READY;
|
|
|
|
|
|
|
|
// call callback
|
|
|
|
this.callback.onclose();
|
|
|
|
|
|
|
|
}.bind(this),
|
|
|
|
|
|
|
|
/* (5) Manage response received */
|
|
|
|
onreceive: function(_response){
|
|
|
|
|
|
|
|
// set state from TRANSFERING to CONNECTED
|
|
|
|
this.state = ClientDriver.STATE.CONNECTED;
|
|
|
|
|
|
|
|
// call callback
|
|
|
|
this.callback.onreceive(_response);
|
|
|
|
|
|
|
|
}.bind(this)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/* (2) Manage errors
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
/* (1) Fail: invalid _resource */
|
2018-03-23 17:43:59 +00:00
|
|
|
if( typeof _resource !== 'string' )
|
|
|
|
return ( this.error = true );
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) Set explicit attributes */
|
2018-03-23 17:43:59 +00:00
|
|
|
this.resource = _resource;
|
2018-03-25 11:40:35 +00:00
|
|
|
this.auth = _auth;
|
2018-03-23 17:43:59 +00:00
|
|
|
|
|
|
|
return;
|
2018-03-24 14:13:27 +00:00
|
|
|
|
2018-03-23 17:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
|
2018-03-23 17:43:59 +00:00
|
|
|
/* (2) Binds the client to the resource
|
|
|
|
*
|
|
|
|
* @return bound<boolean> Whether the binding has been successful
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
bind(){
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) force_close -> fail */
|
|
|
|
if( this.force_close )
|
2018-03-23 17:43:59 +00:00
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) Fail: not READY */
|
|
|
|
if( this.state !== ClientDriver.STATE.READY )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* (3) Update state */
|
|
|
|
this.state = ClientDriver.STATE.CONNECTING;
|
|
|
|
|
|
|
|
/* (4) Child dispatch */
|
2018-03-23 17:43:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (3) Closes the connection
|
|
|
|
*
|
|
|
|
* @return closed<boolean> Whether the connection has been closed
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
close(){
|
|
|
|
|
|
|
|
/* (1) set force_close */
|
|
|
|
this.force_close = true;
|
|
|
|
|
|
|
|
/* (2) Update state */
|
|
|
|
this.state = ClientDriver.STATE.CLOSED;
|
|
|
|
|
|
|
|
/* (4) Child dispatch */
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* (4) Send request
|
2018-03-23 17:43:59 +00:00
|
|
|
*
|
|
|
|
* @_request<Object> Request data
|
|
|
|
*
|
|
|
|
* @return sent<boolean> Whether the request has been successful
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
send(_request){
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) force_close -> fail */
|
|
|
|
if( this.force_close )
|
2018-03-23 17:43:59 +00:00
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) bufferise 'state' */
|
|
|
|
let state = this.state;
|
|
|
|
|
|
|
|
/* (3) Fail: invalid _request */
|
2018-03-23 17:43:59 +00:00
|
|
|
if( !(_request instanceof Object) )
|
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (4) CLOSED -> abort */
|
|
|
|
if( state === ClientDriver.STATE.CLOSED )
|
2018-03-23 17:43:59 +00:00
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (5) READY -> stack message + bind() [in case connection failed)] */
|
2018-04-03 13:37:18 +00:00
|
|
|
if( state === ClientDriver.STATE.READY ){
|
|
|
|
this.stack.push(_request);
|
|
|
|
this.bind();
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-24 14:13:27 +00:00
|
|
|
|
|
|
|
/* (6) CONNECTING -> stack message */
|
|
|
|
if( state === ClientDriver.STATE.CONNECTING )
|
2018-04-03 13:37:18 +00:00
|
|
|
return ( this.stack.push(_request) < -1 );
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (7) update state */
|
|
|
|
this.state = ClientDriver.STATE.TRANFERING;
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (8) Child dispatch */
|
2018-03-23 17:43:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (5) Bind event to connection successfully opened
|
2018-03-23 17:43:59 +00:00
|
|
|
*
|
|
|
|
* @_callback<Function> Callback launched when connection is opened
|
|
|
|
*
|
|
|
|
* @return bound<boolean> Whether the callback has successfully been bound
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2018-03-24 14:13:27 +00:00
|
|
|
set onconnected(_callback){
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) Fail: invalid _callback */
|
2018-03-23 17:43:59 +00:00
|
|
|
if( !(_callback instanceof Function) )
|
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) Register _callback */
|
|
|
|
this.callback.onconnected = _callback;
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (3) By default return success */
|
2018-03-23 17:43:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (6) Bind event to connection closed
|
2018-03-23 17:43:59 +00:00
|
|
|
*
|
|
|
|
* @_callback<Function> Callback launched when connection is closed
|
|
|
|
*
|
|
|
|
* @return bound<boolean> Whether the callback has successfully been bound
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2018-03-24 14:13:27 +00:00
|
|
|
set onclose(_callback){
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) Fail: invalid _callback */
|
2018-03-23 17:43:59 +00:00
|
|
|
if( !(_callback instanceof Function) )
|
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) Register _callback */
|
2018-03-23 17:43:59 +00:00
|
|
|
this.callback.onclose = _callback;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (3) By default return success */
|
2018-03-23 17:43:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (7) Bind event to message reception
|
2018-03-23 17:43:59 +00:00
|
|
|
*
|
|
|
|
* @_callback<Function> Callback launched when a message is received
|
|
|
|
*
|
|
|
|
* @return bound<boolean> Whether the callback has successfully been bound
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2018-03-24 14:13:27 +00:00
|
|
|
set onreceive(_callback){
|
2018-03-23 17:43:59 +00:00
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (1) Fail: invalid _callback */
|
2018-03-23 17:43:59 +00:00
|
|
|
if( !(_callback instanceof Function) )
|
|
|
|
return false;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (2) Register _callback */
|
2018-03-23 17:43:59 +00:00
|
|
|
this.callback.onreceive = _callback;
|
|
|
|
|
2018-03-24 14:13:27 +00:00
|
|
|
/* (3) By default return success */
|
2018-03-23 17:43:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|