310 lines
9.1 KiB
JavaScript
310 lines
9.1 KiB
JavaScript
"use strict";
|
|
|
|
import {Common} from "../Utils/Common.ecma.js";
|
|
import {Check} from "../Utils/Checks.ecma.js";
|
|
|
|
/**
|
|
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
|
*/
|
|
|
|
/**
|
|
* @class FilesDriver
|
|
* @constructor
|
|
* @param {!AnP} anp
|
|
* @param {?(Object.<string, any|null>|Array<any|null>)} [inputs = null]
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
export const FilesDriver = (function(){
|
|
|
|
/**
|
|
* @callback simple_callback
|
|
* @returns {void}
|
|
*/
|
|
|
|
/**
|
|
* @callback continue_callback
|
|
* @param {!boolean} ok
|
|
* @return {boolean}
|
|
*/
|
|
|
|
/**
|
|
* @callback ok_callback
|
|
* @param {!boolean} ok
|
|
* @return {void}
|
|
*/
|
|
|
|
/**
|
|
* @callback load_callback
|
|
* @param {?string} content
|
|
* @param {!boolean} ok
|
|
* @return {void}
|
|
*/
|
|
|
|
/**
|
|
* @callback load_json_callback
|
|
* @param {!Array.<Object.<string, any|null>|Array.<any|null>>} results
|
|
* @return {void}
|
|
*/
|
|
|
|
/**
|
|
* @constructs FilesDriver
|
|
* @param {!AnP} anp
|
|
* @param {?(Object.<string, any|null>|Array<any|null>)} [inputs = null]
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
const FilesDriver = function(anp, inputs = null){
|
|
|
|
/** @type {FilesDriver} */
|
|
const self = this;
|
|
/** @type {Array.<string>} */
|
|
let default_root_urls = [""],
|
|
/** @type {number} */
|
|
default_timeout = 2000,
|
|
/** @type {boolean} */
|
|
default_asynchronous = true,
|
|
/** @type {string} */
|
|
default_method = "get",
|
|
/** @type {boolean} */
|
|
started = false;
|
|
|
|
/**
|
|
* @returns {void}
|
|
* @access private
|
|
*/
|
|
const constructor = () => {};
|
|
|
|
/**
|
|
* @param {?continue_callback} callback
|
|
* @returns {boolean}
|
|
* @access public
|
|
*/
|
|
this.update = (callback = null) => {
|
|
|
|
default_timeout = anp.settings.get(["files_driver_timeout", "timeout"], inputs, default_timeout);
|
|
default_asynchronous = anp.settings.get(["files_driver_asynchronous", "asynchronous"], inputs, default_asynchronous);
|
|
default_method = anp.settings.get(["files_driver_method", "method"], inputs, default_method);
|
|
|
|
Common.execute(callback);
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {?continue_callback} callback
|
|
* @returns {boolean}
|
|
* @access public
|
|
*/
|
|
this.reset = (callback = null) => {
|
|
|
|
default_root_urls = [""];
|
|
default_timeout = 2000;
|
|
default_asynchronous = true;
|
|
|
|
self.update(callback);
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {?continue_callback} callback
|
|
* @returns {boolean}
|
|
* @access public
|
|
*/
|
|
this.start = (callback = null) => {
|
|
|
|
/** @type {continue_callback} */
|
|
const end = ok => Common.execute(callback, ok);
|
|
|
|
if(started){
|
|
end(false);
|
|
return false;
|
|
};
|
|
started = true;
|
|
|
|
self.update(() => end(true));
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* @param {?continue_callback} callback
|
|
* @returns {boolean}
|
|
* @access public
|
|
*/
|
|
this.close = (callback = null) => {
|
|
|
|
/** @type {continue_callback} */
|
|
const end = ok => Common.execute(callback, ok);
|
|
|
|
if(!started){
|
|
end(false);
|
|
return false;
|
|
};
|
|
started = false;
|
|
|
|
end(true);
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* @param {!string} method
|
|
* @param {!string} url
|
|
* @param {!boolean} asynchronous
|
|
* @param {!number} timeout
|
|
* @param {?load_callback} [callback = null]
|
|
* @param {!Array.<string>} root_urls
|
|
* @param {!number} [i = 0]
|
|
* @param {!Array.<string>} [root_urls_done = []]
|
|
* @return {void}
|
|
* @access public
|
|
*/
|
|
const load_url_route = (method, url, asynchronous, timeout, callback, root_urls, i = 0, root_urls_done = []) => {
|
|
|
|
if(i == root_urls.length){
|
|
Common.execute(callback, null, false);
|
|
return;
|
|
};
|
|
|
|
/** @type {simple_callback} */
|
|
const next = () => {
|
|
load_url_route(method, url, asynchronous, timeout, callback, root_urls, i + 1, root_urls_done.concat(root_urls[i]));
|
|
};
|
|
|
|
if(root_urls_done.includes(root_urls[i])){
|
|
next();
|
|
return;
|
|
};
|
|
|
|
/** @type {boolean} */
|
|
let ended = false;
|
|
/** @type {XMLHttpRequest} */
|
|
const ajax = new XMLHttpRequest(),
|
|
/** @type {ok_callback} */
|
|
end = (ok = false) => {
|
|
if(ended)
|
|
return;
|
|
ended = true;
|
|
if(ok)
|
|
Common.execute(callback, ajax.responseText, true);
|
|
else
|
|
next();
|
|
},
|
|
/** @type {number} */
|
|
date = Date.now();
|
|
|
|
ajax.open(method, root_urls[i] + url, asynchronous);
|
|
ajax.timeout = timeout;
|
|
ajax.onreadystatechange = () => {
|
|
if(ended)
|
|
return;
|
|
if(ajax.readyState == 4)
|
|
end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status));
|
|
else if(Date.now() - date >= timeout)
|
|
end(false);
|
|
};
|
|
ajax.send(null);
|
|
|
|
ajax.onload = end;
|
|
ajax.onerror = end;
|
|
ajax.ontimeout = end;
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {!string} url
|
|
* @param {?load_callback} [callback = null]
|
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
|
* @return {void}
|
|
* @access public
|
|
*/
|
|
this.load = (url, callback, inputs = null) => {
|
|
load_url_route(
|
|
Common.get_value(["files_driver_method", "method"], inputs, "get").toLowerCase(),
|
|
url,
|
|
Common.get_value(["files_driver_asynchronous", "asynchronous"], inputs, default_asynchronous),
|
|
Common.get_value(["files_driver_timeout", "timeout"], inputs, default_timeout),
|
|
callback,
|
|
Common.get_value(["files_driver_root_urls", "root_urls"], inputs, []).concat(default_root_urls)
|
|
);
|
|
};
|
|
|
|
/**
|
|
* @param {?any} data
|
|
* @param {!load_json_callback} callback
|
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
|
* @return {void}
|
|
* @access public
|
|
*/
|
|
this.load_json = (data, callback, inputs = null) => {
|
|
|
|
if(Check.is_bool(inputs))
|
|
inputs = {only_dictionaries : inputs};
|
|
|
|
/** @type {boolean} */
|
|
const only_dictionaries = Common.get_value([
|
|
"files_driver_load_json_only_dictionaries",
|
|
"load_json_only_dictionaries",
|
|
"only_dictionaries"
|
|
], Check.is_bool(inputs) ? inputs = {
|
|
only_dictionaries : inputs
|
|
} : inputs, false),
|
|
/** @type {Array.<Object.<string, any|null>|Array.<any|null>>} */
|
|
results = [],
|
|
/** @type {simple_callback} */
|
|
end = () => {
|
|
Common.execute(callback, results);
|
|
};
|
|
|
|
if(Check.is_dictionary(data)){
|
|
results.push(data);
|
|
end();
|
|
}else if(Check.is_array(data)){
|
|
if(only_dictionaries){
|
|
|
|
/** @type {number} */
|
|
const l = data.length;
|
|
/** @type {number} */
|
|
let loaded = 0;
|
|
|
|
for(let item of data)
|
|
self.load_json(item, subresults => {
|
|
results.push(...subresults);
|
|
++ loaded == l && end();
|
|
}, inputs);
|
|
|
|
}else{
|
|
results.push(data);
|
|
end();
|
|
};
|
|
}else if(Check.is_string(data)){
|
|
|
|
/** @type {Object.<string, any|null>|Array.<any|null>|null} */
|
|
let json;
|
|
|
|
if(Check.is_json(data, false) && (json = JSON.parse(data)) !== null)
|
|
self.load_json(json, subresults => {
|
|
results.push(...subresults);
|
|
end();
|
|
}, inputs);
|
|
else
|
|
self.load(data, (content, ok) => {
|
|
self.load_json(content, subresults => {
|
|
results.push(...subresults);
|
|
end();
|
|
}, inputs);
|
|
}, inputs);
|
|
|
|
}else
|
|
end();
|
|
|
|
};
|
|
|
|
constructor();
|
|
|
|
};
|
|
|
|
return FilesDriver;
|
|
})(); |