[lib.client.client-driver][lib.client.xhr][lib.client.ws] made more generic with trying to re-configure connection (bind) if connection lost and trying to send() a request
This commit is contained in:
parent
1cedd6284a
commit
a1a5610f2c
|
@ -1,3 +1,4 @@
|
||||||
|
import {APIClient} from './lib/api-client'
|
||||||
import {GlobalStore} from './lib/gstore'
|
import {GlobalStore} from './lib/gstore'
|
||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import routes from './routes'
|
import routes from './routes'
|
||||||
|
@ -6,8 +7,14 @@ import {ContentController} from './lib/content-controller'
|
||||||
import {RoomController} from './lib/room-controller'
|
import {RoomController} from './lib/room-controller'
|
||||||
import {ChannelController} from './lib/channel-controller'
|
import {ChannelController} from './lib/channel-controller'
|
||||||
|
|
||||||
|
import XHRClientDriver from './lib/client/xhr.js'
|
||||||
|
import WebSocketClientDriver from './lib/client/ws.js'
|
||||||
|
|
||||||
|
|
||||||
window.gs = new GlobalStore();
|
window.gs = new GlobalStore();
|
||||||
|
window.api = new APIClient('localhost', null, false);
|
||||||
|
window.xhrcd = XHRClientDriver;
|
||||||
|
window.wscd = WebSocketClientDriver;
|
||||||
|
|
||||||
/* (1) Global data
|
/* (1) Global data
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
|
|
|
@ -1,81 +1,142 @@
|
||||||
/* classe API */
|
/* classe API */
|
||||||
export class APIClient{
|
export class APIClient{
|
||||||
|
|
||||||
constructor(target){
|
|
||||||
|
|
||||||
this.target = target;
|
|
||||||
|
|
||||||
this.xhr = []; // tableau d'objets pour les requêtes ajax
|
/* (1) Constructs an API client manager
|
||||||
this.buffer = null; // Contiendra le buffer pour debugger si erreur de parsage
|
*
|
||||||
this.error = { // error constants
|
* @_hostname<String> Server hostname (without http, port number, etc)
|
||||||
'-1': 'Invalid target format: "METHOD module/method"',
|
* @_baseuri<String> Server base URI
|
||||||
'-2': 'XHR error',
|
* @_ssl<bool> [OPT] Whether SSL is activated (http vs https) (default: https)
|
||||||
'-3': 'Invalid JSON response',
|
* @_port<int> [OPT] optional HTTP port (default: none)
|
||||||
|
*
|
||||||
|
* @return http_url<String> Built http_url
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
constructor(_hostname, _baseuri, _ssl=true, _port=null){
|
||||||
|
|
||||||
|
/* (1) Build URL parts */
|
||||||
|
this.http_parts = {
|
||||||
|
|
||||||
|
ssl: _ssl === true,
|
||||||
|
hostname: _hostname,
|
||||||
|
baseuri: this.fix_uri(_baseuri),
|
||||||
|
port: !isNaN(_port) ? _port: null
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.xhr_stack = []; // Ajax request stack
|
||||||
|
this.buffer = null; // Last request buffer
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fix_uri(_uri){
|
||||||
|
|
||||||
|
if( typeof _uri !== 'string' )
|
||||||
|
return '';
|
||||||
|
|
||||||
|
return _uri.split('/').filter((r) => r.trim().length).join('/')
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) HTTP url dynamic getter
|
||||||
|
*
|
||||||
|
* @_uri<String> [OPT] optional URI string
|
||||||
|
* @_token<String> [OPT] optional HTTP token
|
||||||
|
*
|
||||||
|
* @return http_url<String> Built http_url
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
build_url(_uri, _token=null){
|
||||||
|
|
||||||
|
/* (1) Initialize URL buffer */
|
||||||
|
let bufurl = 'http';
|
||||||
|
|
||||||
|
/* (2) Manage @ssl */
|
||||||
|
this.http_parts.ssl && ( bufurl = bufurl.concat('s') );
|
||||||
|
bufurl = bufurl.concat('://');
|
||||||
|
|
||||||
|
/* (3) Manage token */
|
||||||
|
( typeof _token === 'string' ) && ( bufurl = bufurl.concat(`${_token}@`) );
|
||||||
|
|
||||||
|
/* (4) Manage hostname */
|
||||||
|
bufurl = bufurl.concat(this.http_parts.hostname);
|
||||||
|
|
||||||
|
/* (5) Manage port */
|
||||||
|
( this.http_parts.port !== null ) && ( bufurl = bufurl.concat(`:${this.http_parts.port}`) );
|
||||||
|
|
||||||
|
/* (6) Base uri */
|
||||||
|
bufurl = bufurl.concat(`/${this.http_parts.baseuri}/`);
|
||||||
|
|
||||||
|
/* (7) Manage URI */
|
||||||
|
bufurl = bufurl.concat( this.fix_uri(_uri) );
|
||||||
|
|
||||||
|
return bufurl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* transaction avec le serveur (http://{host}/api/)
|
/* Server Transaction
|
||||||
*
|
*
|
||||||
* @param pTarget<String> URI cible, format "HTTP_METHOD uri/uri/uri"
|
* @param _path<String> target path (format "HTTP_METHOD uri/uri/uri")
|
||||||
* @param pArgs<Object> Le tableu d'arguments passé en POST (attribut<->postfield) à http://{host}/api/
|
* @param _args<Object> formdata object (as raw object)
|
||||||
* @param pHandler<Function> Fonction qui s'éxécutera lors de la réponse (1 argument -> réponse<Object>)
|
* @param _callback<Function> Response callback
|
||||||
* @param pToken<String> Optionnel, token d'auth pour l'api
|
* @param _token<String> [OPT] http token
|
||||||
*
|
*
|
||||||
***************************************************************************************************
|
***************************************************************************************************
|
||||||
*
|
*
|
||||||
* @usecase
|
* @usecase
|
||||||
* 1. api.call(
|
* 1. api.call(
|
||||||
* 2. "PUT newspaper/article/4"
|
* 2. 'PUT newspaper/article/4'
|
||||||
* 2. { content: "New article content" },
|
* 3. { content: "new content" },
|
||||||
* 3. function(resp){
|
* 4. (r) => alert(r.error),
|
||||||
* 4. alert(resp.error);
|
* 5. 'sometoken'
|
||||||
* 5. }
|
|
||||||
* 6. );
|
* 6. );
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
call(pTarget, pArgs, pHandler, pToken=null){
|
call(_path, _args, _callback, _token=null){
|
||||||
|
|
||||||
|
|
||||||
/* (1) Check @pHandler (for dispatching errors)
|
/* (1) Argument management
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Check if is a Function */
|
/* (1) Set default callback if @callback not callable */
|
||||||
if( !(pHandler instanceof Function) )
|
if( !(_callback instanceof Function) )
|
||||||
throw new Error("3rd argument must be a function, but is of type '"+typeof(pHandler)+"' !");
|
_callback = function(r){ console.warn('The API callback function is missing, default callback set.', 'Response', r); };
|
||||||
|
|
||||||
|
/* (2) Check @path format */
|
||||||
|
if( !/^([A-Z]+) (.+)/i.test(_path) ){
|
||||||
/* (2) Check @pTarget
|
_callback({ error: -1 });
|
||||||
---------------------------------------------------------*/
|
|
||||||
/* (1) Check format */
|
|
||||||
if( !/^([A-Z]+) (.+)/i.test(pTarget) ){
|
|
||||||
pHandler({ error: -1, ErrorDescription: this.error['-1'] });
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (2) Store locally data */
|
var http_method = RegExp.$1;
|
||||||
var lHttpMethod = RegExp.$1;
|
var http_uri = RegExp.$2;
|
||||||
var lUri = RegExp.$2;
|
|
||||||
|
/* (3) Default @_token */
|
||||||
|
if( typeof _token !== 'string' )
|
||||||
|
_token = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (3) Create form data
|
/* (3) Create form data
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Create virtual form */
|
/* (1) Create virtual form */
|
||||||
var lForm = new FormData();
|
var form_data = new FormData();
|
||||||
|
|
||||||
/* (2) Add attributes */
|
/* (2) Add attributes */
|
||||||
for( var key in pArgs ){
|
for( var key in _args ){
|
||||||
|
|
||||||
// {2.1} If a file -> send as it //
|
// {2.1} If a file -> send as it //
|
||||||
if( pArgs[key] instanceof File )
|
if( _args[key] instanceof File )
|
||||||
lForm.append(key, pArgs[key]);
|
form_data.append(key, _args[key]);
|
||||||
|
|
||||||
// {2.2} Else -> JSON stringify //
|
// {2.2} Else -> JSON stringify //
|
||||||
else
|
else
|
||||||
lForm.append(key, JSON.stringify(pArgs[key]));
|
form_data.append(key, JSON.stringify(_args[key]));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,74 +145,69 @@ export class APIClient{
|
||||||
/* (4) Create XHR request
|
/* (4) Create XHR request
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Clean ended requests */
|
/* (1) Clean ended requests */
|
||||||
for( var i = this.xhr.length-1 ; i >= 0 ; i-- ){
|
for( var i = this.xhr_stack.length-1 ; i >= 0 ; i-- ){
|
||||||
|
|
||||||
if( this.xhr[i] != null )
|
if( this.xhr_stack[i] != null )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
this.xhr.pop();
|
this.xhr_stack.pop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (2) Push a new entry -> fetch its index */
|
/* (2) Push a new entry -> fetch its index */
|
||||||
i = this.xhr.push(null) - 1;
|
i = this.xhr_stack.push(null) - 1;
|
||||||
|
|
||||||
/* (3) Create XHR object */
|
/* (3) Create XHR object */
|
||||||
this.xhr[i] = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttpRequest');
|
this.xhr_stack[i] = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttpRequest');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (5) Bind response event
|
/* (5) Bind response event
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
var self = this; // to access the buffer
|
this.xhr_stack[i].onreadystatechange = function(i, parent){
|
||||||
|
|
||||||
this.xhr[i].onreadystatechange = function(i){
|
|
||||||
|
|
||||||
/* (1) If request over */
|
/* (1) If request over */
|
||||||
if( this.xhr[i].readyState == 4 ){
|
if( this[i].readyState === 4 ){
|
||||||
|
|
||||||
/* (2) Update buffer (for debug) */
|
/* (2) Update buffer (for debug) */
|
||||||
self.buffer = this.xhr[i].responseText;
|
parent.buffer = this[i].responseText;
|
||||||
|
|
||||||
/* (3) If request success */
|
/* (3) If request success */
|
||||||
if( [0, 200, 417].indexOf(this.xhr[i].status) > -1 ){
|
if( [0, 200].indexOf(this[i].status) > -1 ){
|
||||||
|
|
||||||
|
|
||||||
/* (3.1) Create default response (if JSON error) */
|
/* (3.1) Create default response (if JSON error) */
|
||||||
var response = {error:-3, ErrorDescription: self.error['-3']};
|
var response = { error: -2 };
|
||||||
|
|
||||||
/* (3.2) Try to parse JSON */
|
/* (3.2) Try to parse JSON */
|
||||||
try{ response = JSON.parse(this.xhr[i].responseText); }catch(e){}
|
try{ response = JSON.parse(this[i].responseText); }catch(e){}
|
||||||
|
|
||||||
/* (3.3) Launch @pHandler with response */
|
/* (3.3) Launch @_callback with response */
|
||||||
pHandler(response);
|
_callback(response);
|
||||||
|
|
||||||
/* (4) If request error */
|
/* (4) If request error */
|
||||||
}else
|
}else
|
||||||
pHandler({ error:-2, ErrorDescription: self.error['-2'] });
|
_callback({ error: -3 });
|
||||||
|
|
||||||
/* (5) Notify current xhr instance is done */
|
/* (5) Notify current xhr instance is done */
|
||||||
this.xhr[i] = null;
|
this[i] = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}.bind(this, i);
|
}.bind(this.xhr_stack, i, this);
|
||||||
|
|
||||||
|
|
||||||
/* (6) Finish & send request
|
/* (6) Finish & send request
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Open the XHR */
|
/* (1) Open the XHR */
|
||||||
this.xhr[i].open(lHttpMethod, this.target+lUri, true);
|
console.log(http_method, this.build_url(http_uri, _token));
|
||||||
|
this.xhr_stack[i].open(http_method, this.build_url(http_uri, _token), true);
|
||||||
|
|
||||||
/* (2) Manage optional token */
|
/* (2) Custom header to notify we're using Ajax */
|
||||||
if( pToken != null )
|
this.xhr_stack[i].setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||||
this.xhr[i].setRequestHeader('Authorization', 'Digest '+pToken);
|
|
||||||
|
|
||||||
/* (3) Custom header to notify we're using Ajax */
|
/* (3) Make the call */
|
||||||
this.xhr[i].setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
this.xhr_stack[i].send(form_data);
|
||||||
|
|
||||||
/* (4) Make the call */
|
|
||||||
this.xhr[i].send( lForm );
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
export class ClientDriver{
|
export default class ClientDriver{
|
||||||
|
|
||||||
/* (0) Constants & Enums
|
/* (0) Constants & Enums
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
static get STATE(){
|
static get STATE(){
|
||||||
|
|
||||||
return Object.freeze({
|
return Object.freeze({
|
||||||
OPENING: 0,
|
CLOSED: 0,
|
||||||
OPENED: 1,
|
READY: 1,
|
||||||
CONNECTING: 2,
|
CONNECTING: 2,
|
||||||
CONNECTED: 3,
|
CONNECTED: 3,
|
||||||
CLOSED: 4
|
TRANFERING: 4
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,27 +22,81 @@ export class ClientDriver{
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
constructor(_resource){
|
constructor(_resource){
|
||||||
|
|
||||||
|
/* (1) Initialize driver
|
||||||
|
---------------------------------------------------------*/
|
||||||
/* (1) Default attributes values */
|
/* (1) Default attributes values */
|
||||||
this.error = false;
|
this.force_close = false;
|
||||||
this.state = ClientDriver.STATE.OPENING;
|
this.state = ClientDriver.STATE.READY;
|
||||||
this.stack = [];
|
this.stack = [];
|
||||||
|
|
||||||
|
/* (2) Default User callbacks */
|
||||||
this.callback = {
|
this.callback = {
|
||||||
onready: function(){},
|
onconnected: function(){},
|
||||||
onclose: function(){},
|
onclose: function(){},
|
||||||
onreceive: function(){}
|
onreceive: function(){}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* (2) Fail: invalid _resource */
|
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 */
|
||||||
if( typeof _resource !== 'string' )
|
if( typeof _resource !== 'string' )
|
||||||
return ( this.error = true );
|
return ( this.error = true );
|
||||||
|
|
||||||
/* (3) Set explicit attributes */
|
/* (2) Set explicit attributes */
|
||||||
this.resource = _resource;
|
this.resource = _resource;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (2) Binds the client to the resource
|
/* (2) Binds the client to the resource
|
||||||
*
|
*
|
||||||
* @return bound<boolean> Whether the binding has been successful
|
* @return bound<boolean> Whether the binding has been successful
|
||||||
|
@ -50,17 +104,43 @@ export class ClientDriver{
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
bind(){
|
bind(){
|
||||||
|
|
||||||
/* (1) Fail: not OPENING OR error */
|
/* (1) force_close -> fail */
|
||||||
if( this.error || this.state !== ClientDriver.STATE.OPENING )
|
if( this.force_close )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (2) By default return success */
|
/* (2) Fail: not READY */
|
||||||
|
if( this.state !== ClientDriver.STATE.READY )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (3) Update state */
|
||||||
|
this.state = ClientDriver.STATE.CONNECTING;
|
||||||
|
|
||||||
|
/* (4) Child dispatch */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (3) Send request
|
/* (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
|
||||||
*
|
*
|
||||||
* @_request<Object> Request data
|
* @_request<Object> Request data
|
||||||
*
|
*
|
||||||
|
@ -69,111 +149,99 @@ export class ClientDriver{
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
send(_request){
|
send(_request){
|
||||||
|
|
||||||
/* (1) Fail: if error */
|
/* (1) force_close -> fail */
|
||||||
if( this.error )
|
if( this.force_close )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (2) Fail: invalid _request */
|
/* (2) bufferise 'state' */
|
||||||
|
let state = this.state;
|
||||||
|
|
||||||
|
/* (3) Fail: invalid _request */
|
||||||
if( !(_request instanceof Object) )
|
if( !(_request instanceof Object) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) If not already connected -> stack request */
|
/* (4) CLOSED -> abort */
|
||||||
if( this.state < ClientDriver.STATE.CONNECTED ){
|
if( state === ClientDriver.STATE.CLOSED )
|
||||||
|
|
||||||
this.stack.push(_request);
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
/* (5) READY -> stack message + bind() [in case connection failed)] */
|
||||||
|
if( state === ClientDriver.STATE.READY )
|
||||||
|
return ( this.stack.push(_request) > -1 ) && this.bind();
|
||||||
|
|
||||||
|
/* (6) CONNECTING -> stack message */
|
||||||
|
if( state === ClientDriver.STATE.CONNECTING )
|
||||||
|
return ( this.stack.push(_request) > -1 );
|
||||||
|
|
||||||
/* (4) By default return success */
|
/* (7) update state */
|
||||||
|
this.state = ClientDriver.STATE.TRANFERING;
|
||||||
|
|
||||||
|
/* (8) Child dispatch */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (4) Bind event to connection opened
|
/* (5) Bind event to connection successfully opened
|
||||||
*
|
*
|
||||||
* @_callback<Function> Callback launched when connection is opened
|
* @_callback<Function> Callback launched when connection is opened
|
||||||
*
|
*
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
* @return bound<boolean> Whether the callback has successfully been bound
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
onready(_callback){
|
set onconnected(_callback){
|
||||||
|
|
||||||
/* (1) Fail: already CONNECTED OR error */
|
/* (1) Fail: invalid _callback */
|
||||||
if( this.error || this.state >= ClientDriver.STATE.CONNECTED )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (2) Fail: invalid _callback */
|
|
||||||
if( !(_callback instanceof Function) )
|
if( !(_callback instanceof Function) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) Register _callback */
|
/* (2) Register _callback */
|
||||||
this.callback.onready = function(cback){
|
this.callback.onconnected = _callback;
|
||||||
|
|
||||||
// call callback
|
/* (3) By default return success */
|
||||||
cback();
|
|
||||||
|
|
||||||
// if request(s) in stack -> pop & send them
|
|
||||||
while( this.stack.length > 0 )
|
|
||||||
this.send(this.stack.shift());
|
|
||||||
|
|
||||||
}.bind(this, _callback);
|
|
||||||
|
|
||||||
/* (5) By default return success */
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (5) Bind event to connection closed
|
/* (6) Bind event to connection closed
|
||||||
*
|
*
|
||||||
* @_callback<Function> Callback launched when connection is closed
|
* @_callback<Function> Callback launched when connection is closed
|
||||||
*
|
*
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
* @return bound<boolean> Whether the callback has successfully been bound
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
onclose(_callback){
|
set onclose(_callback){
|
||||||
|
|
||||||
/* (1) Fail: already CLOSED OR error */
|
/* (1) Fail: invalid _callback */
|
||||||
if( this.error || this.state === ClientDriver.STATE.CLOSED )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (2) Fail: invalid _callback */
|
|
||||||
if( !(_callback instanceof Function) )
|
if( !(_callback instanceof Function) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) Register _callback */
|
/* (2) Register _callback */
|
||||||
this.callback.onclose = _callback;
|
this.callback.onclose = _callback;
|
||||||
|
|
||||||
/* (4) By default return success */
|
/* (3) By default return success */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (6) Bind event to message reception
|
/* (7) Bind event to message reception
|
||||||
*
|
*
|
||||||
* @_callback<Function> Callback launched when a message is received
|
* @_callback<Function> Callback launched when a message is received
|
||||||
*
|
*
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
* @return bound<boolean> Whether the callback has successfully been bound
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
onreceive(_callback){
|
set onreceive(_callback){
|
||||||
|
|
||||||
/* (1) Fail: already CONNECTED OR error */
|
/* (1) Fail: invalid _callback */
|
||||||
if( this.error || this.state >= ClientDriver.STATE.CONNECTED )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (2) Fail: invalid _callback */
|
|
||||||
if( !(_callback instanceof Function) )
|
if( !(_callback instanceof Function) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) Register _callback */
|
/* (2) Register _callback */
|
||||||
this.callback.onreceive = _callback;
|
this.callback.onreceive = _callback;
|
||||||
|
|
||||||
/* (4) By default return success */
|
/* (3) By default return success */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {ClientDriver} from './client-driver.js'
|
import ClientDriver from './client-driver.js'
|
||||||
|
|
||||||
export class WebSocketClientDriver extends ClientDriver{
|
export default class WebSocketClientDriver extends ClientDriver{
|
||||||
|
|
||||||
|
|
||||||
/* (1) Creates a client driver
|
/* (1) Creates a client driver
|
||||||
|
@ -21,9 +21,6 @@ export class WebSocketClientDriver extends ClientDriver{
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.buffer = null; // useful when waiting for WebSocket to open
|
this.buffer = null; // useful when waiting for WebSocket to open
|
||||||
|
|
||||||
/* (N) Set all is ok */
|
|
||||||
this.error = false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,28 +39,16 @@ export class WebSocketClientDriver extends ClientDriver{
|
||||||
this.ws = new WebSocket(this.resource);
|
this.ws = new WebSocket(this.resource);
|
||||||
|
|
||||||
/* (2) Bind callback.onready */
|
/* (2) Bind callback.onready */
|
||||||
this.ws.onopen = function(){
|
this.ws.onopen = this.event.onconnected;
|
||||||
this.state = ClientDriver.STATE.CONNECTED;
|
|
||||||
this.callback.onready();
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
/* (3) Bind callback.onclose */
|
/* (3) Bind callback.onclose */
|
||||||
this.ws.onclose = function(){
|
this.ws.onclose = this.event.onclose;
|
||||||
this.state = ClientDriver.STATE.CLOSED;
|
|
||||||
this.callback.onclose();
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
/* (4) Bind callback.onerror */
|
/* (4) Bind callback.onerror */
|
||||||
this.ws.onerror = function(){
|
this.ws.onerror = this.event.onclose;
|
||||||
this.state = ClientDriver.STATE.CLOSED;
|
|
||||||
this.callback.onclose();
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
/* (5) Bind callback.onreceive */
|
/* (5) Bind callback.onreceive */
|
||||||
this.ws.onmessage = function(response){
|
this.ws.onmessage = (_message_event) => this.event.onreceive(_message_event.data);
|
||||||
this.state = ClientDriver.STATE.CONNECTED;
|
|
||||||
this.callback.onreceive(response);
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
/* (6) Return success */
|
/* (6) Return success */
|
||||||
return true;
|
return true;
|
||||||
|
@ -85,11 +70,12 @@ export class WebSocketClientDriver extends ClientDriver{
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (1) Error: invalid _request.buffer */
|
/* (1) Error: invalid _request.buffer */
|
||||||
if( typeof _request.buffer !== 'string' )
|
if( typeof _request.buffer !== 'string' ){
|
||||||
|
this.state = ClientDriver.STATE.CONNECTED;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* (2) Send message */
|
/* (2) Send message */
|
||||||
console.log('sent', _request.buffer);
|
|
||||||
this.ws.send(_request.buffer);
|
this.ws.send(_request.buffer);
|
||||||
|
|
||||||
/* (3) Return success */
|
/* (3) Return success */
|
||||||
|
@ -98,50 +84,22 @@ export class WebSocketClientDriver extends ClientDriver{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (4) Bind event to connection opened
|
/* (3) Closes the connection
|
||||||
*
|
*
|
||||||
* @_callback<Function> Callback launched when connection is opened
|
* @return closed<boolean> Whether the connection has been closed
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
onready(_callback){
|
close(){
|
||||||
|
|
||||||
/* (0) Parent check */
|
/* (0) Parent check */
|
||||||
if( !super.onready(_callback) )
|
if( !super.close() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
/* (1) Close websocket */
|
||||||
|
this.ws.close();
|
||||||
|
|
||||||
|
/* (2) Return success */
|
||||||
/* (5) Bind event to connection closed
|
return true;
|
||||||
*
|
|
||||||
* @_callback<Function> Callback launched when connection is closed
|
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
onclose(_callback){
|
|
||||||
|
|
||||||
/* (0) Parent check */
|
|
||||||
if( !super.onclose(_callback) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (6) Bind event to message reception
|
|
||||||
*
|
|
||||||
* @_callback<Function> Callback launched when a message is received
|
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
onreceive(_callback){
|
|
||||||
|
|
||||||
/* (0) Parent check */
|
|
||||||
if( !super.onreceive(_callback) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {ClientDriver} from './client-driver.js'
|
import ClientDriver from './client-driver.js'
|
||||||
|
|
||||||
export class XHRClientDriver extends ClientDriver{
|
export default class XHRClientDriver extends ClientDriver{
|
||||||
|
|
||||||
|
|
||||||
/* (1) Creates a client driver
|
/* (1) Creates a client driver
|
||||||
|
@ -20,9 +20,6 @@ export class XHRClientDriver extends ClientDriver{
|
||||||
/* (2) Create useful attributes */
|
/* (2) Create useful attributes */
|
||||||
this.xhr = null;
|
this.xhr = null;
|
||||||
|
|
||||||
/* (N) Set all is ok */
|
|
||||||
this.error = false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,17 +48,13 @@ export class XHRClientDriver extends ClientDriver{
|
||||||
// Got response
|
// Got response
|
||||||
if( this.xhr.status === 200 ){
|
if( this.xhr.status === 200 ){
|
||||||
|
|
||||||
this.callback.onreceive(this.xhr.responseText);
|
this.event.onreceive(this.xhr.responseText);
|
||||||
this.state = ClientDriver.STATE.CLOSED;
|
this.event.onclose();
|
||||||
this.callback.onclose();
|
|
||||||
|
|
||||||
// Request error
|
// Request error
|
||||||
}else{
|
}else
|
||||||
|
this.event.onclose();
|
||||||
|
|
||||||
this.state = ClientDriver.STATE.CLOSED;
|
|
||||||
this.callback.onclose();
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,11 +62,11 @@ export class XHRClientDriver extends ClientDriver{
|
||||||
|
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
/* (3) State is now CONNECTED (wrong but ..) */
|
/* (3) State is now CONNECTED (ready to send) */
|
||||||
this.state = ClientDriver.STATE.CONNECTED;
|
this.state = ClientDriver.STATE.CONNECTED;
|
||||||
|
|
||||||
/* (4) Bind to callback onready() */
|
/* (4) Bind to callback onconnected() */
|
||||||
this.callback.onready();
|
this.event.onconnected();
|
||||||
|
|
||||||
/* (5) Return success */
|
/* (5) Return success */
|
||||||
return true;
|
return true;
|
||||||
|
@ -97,14 +90,18 @@ export class XHRClientDriver extends ClientDriver{
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (2) Error: invalid _request.path */
|
/* (2) Error: invalid _request.path */
|
||||||
if( typeof _request.path !== 'string' )
|
if( typeof _request.path !== 'string' ){
|
||||||
|
this.state = ClientDriver.STATE.CONNECTED;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* (2) Manage _request.path argument
|
/* (2) Manage _request.path argument
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Error: invalid path format */
|
/* (1) Error: invalid path format */
|
||||||
if( !/^([A-Z]+) (.+)/i.test(_request.path) )
|
if( !/^([A-Z]+) (.+)/i.test(_request.path) ){
|
||||||
|
this.state = ClientDriver.STATE.CONNECTED;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (2) Extract path data */
|
/* (2) Extract path data */
|
||||||
|
@ -145,54 +142,4 @@ export class XHRClientDriver extends ClientDriver{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (4) Bind event to connection opened
|
|
||||||
*
|
|
||||||
* @_callback<Function> Callback launched when connection is opened
|
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
onready(_callback){
|
|
||||||
|
|
||||||
/* (0) Parent check */
|
|
||||||
if( !super.onready(_callback) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (5) Bind event to connection closed
|
|
||||||
*
|
|
||||||
* @_callback<Function> Callback launched when connection is closed
|
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
onclose(_callback){
|
|
||||||
|
|
||||||
/* (0) Parent check */
|
|
||||||
if( !super.onclose(_callback) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (6) Bind event to message reception
|
|
||||||
*
|
|
||||||
* @_callback<Function> Callback launched when a message is received
|
|
||||||
*
|
|
||||||
* @return bound<boolean> Whether the callback has successfully been bound
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
onreceive(_callback){
|
|
||||||
|
|
||||||
/* (0) Parent check */
|
|
||||||
if( !super.onreceive(_callback) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
=== USER ===
|
||||||
|
|
||||||
|
>>> POST /user/
|
||||||
|
{
|
||||||
|
username: <String>
|
||||||
|
password: <String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> GET /user/:uid
|
||||||
|
{}
|
||||||
|
|
||||||
|
>>> PUT /user/:uid
|
||||||
|
{
|
||||||
|
username: <?String>
|
||||||
|
passowrd: <?String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> DELETE /user/:uid
|
||||||
|
{}
|
||||||
|
|
||||||
|
=== USER AUTHENTICATION ===
|
||||||
|
|
||||||
|
>>> POST /user/token
|
||||||
|
{
|
||||||
|
username: <String>
|
||||||
|
password: <String>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== CHANNEL ===
|
||||||
|
|
||||||
|
|
||||||
|
>>> POST @token:/channel/
|
||||||
|
{
|
||||||
|
link: <String>
|
||||||
|
name: <String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> GET @token:/channel/:cid --> channel specific data
|
||||||
|
>>> GET @token:/channel/ --> all available channels for user
|
||||||
|
{}
|
||||||
|
|
||||||
|
>>> PUT @token:/channel/:cid
|
||||||
|
{
|
||||||
|
link: <?String>
|
||||||
|
name: <?String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> DELETE @token:/channel/:cid
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=== CHANNEL <> USER ===
|
||||||
|
|
||||||
|
|
||||||
|
>>> POST @token:/channel/:cid/subscribe
|
||||||
|
{}
|
||||||
|
|
||||||
|
>>> DELETE @token:/channel/:cid/subscribe
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
=== ROOM ===
|
||||||
|
|
||||||
|
>>> POST @token:/channel/:cid/room/:type/
|
||||||
|
{
|
||||||
|
name: <String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> GET @token:/channel/:cid/room/:type/ --> all channel's rooms of this type
|
||||||
|
|
||||||
|
>>> GET @token:/channel/:cid/room/:type/:rid --> room information of this type
|
||||||
|
|
||||||
|
>>> PUT @token:/channel/:cid/room/:type/:rid
|
||||||
|
{
|
||||||
|
name: <String>
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> DELETE @token:/channel/:cid/room/:type/:rid --> remove room
|
Loading…
Reference in New Issue