169 lines
4.0 KiB
JavaScript
169 lines
4.0 KiB
JavaScript
import ClientDriver from './client-driver.js'
|
|
|
|
export default class XHRClientDriver extends ClientDriver{
|
|
|
|
|
|
/* (1) Creates a client driver
|
|
*
|
|
* @_resource<String> Target resource
|
|
* (typically a hostname without trailing HTTP:// nor HTTPS://)
|
|
* @_auth<AuthObject> Authentication object
|
|
*
|
|
*
|
|
* [fornat::AuthObject]
|
|
* {
|
|
* ssl: <boolean>
|
|
* }
|
|
*
|
|
---------------------------------------------------------*/
|
|
constructor(_resource, _auth={ssl:true}){
|
|
|
|
/* (0) Parent check */
|
|
if( super(_resource, _auth).error ){
|
|
this.force_close = true;
|
|
return;
|
|
}
|
|
|
|
/* (1) Create useful attributes */
|
|
this.xhr = null;
|
|
|
|
/* (2) Manage _resource format (remove http://, https://) */
|
|
this.resource = _resource.replace(/^https?:\/\//, '');
|
|
|
|
/* (3) Manage @proto default values */
|
|
this.proto = typeof _auth !== 'object' && _auth['ssl'] != null && _auth.ssl === true;
|
|
this.proto = (this.proto) ? 'https://' : 'http://';
|
|
|
|
}
|
|
|
|
|
|
/* (2) Binds the client to the resource
|
|
*
|
|
* @return bound<boolean> Whether the binding has been successful
|
|
*
|
|
---------------------------------------------------------*/
|
|
bind(){
|
|
|
|
/* (0) Parent check */
|
|
if( !super.bind() )
|
|
return false;
|
|
|
|
/* (1) Create XHR instance */
|
|
this.xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttpRequest');
|
|
|
|
/* (2) Manage after request callbacks */
|
|
this.xhr.onreadystatechange = function(){
|
|
|
|
switch(this.xhr.readyState){
|
|
|
|
// Request sent
|
|
case 4:
|
|
|
|
// Got response
|
|
if( this.xhr.status === 200 ){
|
|
|
|
this.event.onreceive(this.xhr.responseText);
|
|
this.event.onclose();
|
|
|
|
// Request error
|
|
}else
|
|
this.event.onclose();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}.bind(this);
|
|
|
|
/* (3) State is now CONNECTED (ready to send) */
|
|
this.state = ClientDriver.STATE.CONNECTED;
|
|
|
|
/* (4) Bind to callback onconnected() */
|
|
this.event.onconnected();
|
|
|
|
/* (5) Return success */
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
/* (3) Send request
|
|
*
|
|
* @_request<Object> Request data
|
|
*
|
|
* @return sent<boolean> Whether the request has been successful
|
|
*
|
|
---------------------------------------------------------*/
|
|
send(_request){
|
|
|
|
/* (1) Fast argument check
|
|
---------------------------------------------------------*/
|
|
/* (1) Parent check */
|
|
if( !super.send(_request) )
|
|
return false;
|
|
|
|
/* (2) Error: invalid _request.path */
|
|
if( typeof _request.path !== 'string' ){
|
|
this.state = ClientDriver.STATE.CONNECTED;
|
|
return false;
|
|
}
|
|
|
|
/* (3) Default @http_token value */
|
|
let http_token = null;
|
|
if( typeof _request.http_token === 'string' )
|
|
http_token = _request.http_token;
|
|
|
|
|
|
/* (2) Manage _request.path argument
|
|
---------------------------------------------------------*/
|
|
/* (1) Error: invalid path format */
|
|
if( !/^([A-Z]+) (.+)/i.test(_request.path) ){
|
|
this.state = ClientDriver.STATE.CONNECTED;
|
|
return;
|
|
}
|
|
|
|
|
|
/* (2) Extract path data */
|
|
let http_method = RegExp.$1;
|
|
let http_uri = RegExp.$2;
|
|
|
|
|
|
/* (3) Manage _request.form argument
|
|
---------------------------------------------------------*/
|
|
/* (1) Helpers */
|
|
let is_object = typeof _request.form === 'object';
|
|
let is_formdata = is_object && _request.form instanceof FormData;
|
|
|
|
/* (2) Create default value for _request.form */
|
|
let form_data = new FormData();
|
|
|
|
/* (3) If already FormData object -> store as it is */
|
|
if( is_object && is_formdata )
|
|
form_data = _requset.form;
|
|
|
|
/* (4) If just a raw object -> convert to FormData */
|
|
if( is_object && !is_formdata )
|
|
Object.keys(_request.form).map( (k, v) => form_data.append(k, v) );
|
|
|
|
|
|
/* (4) Open connection
|
|
---------------------------------------------------------*/
|
|
/* (1) Build full request URI */
|
|
let request_uri = this.resource.split(/\/$/).concat(http_uri.split(/^\//)).filter((v) => v.trim().length).join('/');
|
|
|
|
/* (2) Build protocol (http, https) and http_token */
|
|
let protocol = http_token != null ? `${this.proto}${http_token}@` : this.proto;
|
|
|
|
/* (3) Open connection */
|
|
this.xhr.open(http_method, `${protocol}${request_uri}`, true);
|
|
|
|
/* (3) Send request */
|
|
this.xhr.send(form_data);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
} |