AnP/Public/ecma/Drivers/FilesDriver.ecma.js

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;
})();