KStats/Public/ecma/KStats.ecma.js

248 lines
8.2 KiB
JavaScript
Raw Normal View History

KStats = function(input){
const self = this,
default_settings = {
autostart : true,
nulls : false,
default_vaalue : null,
ajax_timeout : 2000,
settings_overwrite : false,
kstats_url : "https://kstats.k3y.pw/api/uCDY3brWxEJrJywm2sFcKo1d8oaUdmxTTrv3VGuhpyRDpPYXyKeHWeknh/{session}/ecma/set",
frames_per_second : 1,
milliseconds_per_connection : 2000,
session_cookie_name : "kstats_session_id",
session_timeout : 60000,
data_key : "kstats_data"
},
custom = {},
threads = [];
let started = false,
thread = null,
last_connection = 0,
milliseconds_per_connection = null,
register_thread = null,
id = null,
url = null,
session = null,
data_key = null;
const default_value = this.default_value = (_default, nulls) => _default !== undefined && (_default !== null || (typeof nulls == "boolean" ? nulls : settings("nulls", null, false, false))) ? _default : settings(["default_value", "default"], null, null, true);
const settings = this.settings = (names, inputs, _default, nulls) => {
if(!names)
return default_value(_default, nulls);
const l = (names.push ? names : names = [names]).length,
m = (inputs = (inputs ? inputs.push ? inputs : [inputs] : []).concat([input, custom, default_settings])).length;
typeof nulls != "boolean" && (nulls = settings("nulls", null, false, false));
for(let j = 0; j < m; j ++)
if(typeof inputs[j] == "object")
for(let i = 0; i < l; i ++)
if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null))
return inputs[j][names[i]];
return default_value(_default, nulls);
};
const load = this.load = (url, callback) => {
let ended = false;
const ajax = new XMLHttpRequest(),
timeout = settings(["ajax_timeout", "load_timeout", "timeout"]),
date = Date.now(),
end = message => {
if(ended)
return;
ended = true;
typeof callback == "function" && callback(ajax.responseText, ajax.status, ajax.readyState, message == "OK", message);
};
ajax.open("get", url, true);
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) ? "OK" : "HTTP_ERROR");
else if(Date.now() - date > timeout)
end("FORCED_TIMEOUT");
};
ajax.send(null);
ajax.onabort = () => end("ABORTED"),
ajax.onerror = () => end("ERROR");
ajax.ontimeout = () => end("TIMEOUT");
return ajax;
};
const settings_add_i = (items, overwrite, callback, i) => {
if(i >= items.length){
typeof callback == "function" && callback();
return;
};
if(items[i]){
if(typeof items[i] == "string"){
let json;
try{
json = JSON.parse(items[i]);
}catch(exception){};
if(json)
settings_add_i(json.push ? json : [json], overwrite, end, 0);
else
load(json, response => {
try{
json = JSON.parse(response);
}catch(exception){};
if(json)
settings_add_i(json.push ? json : [json], overwrite, end, 0);
else
end();
});
return;
};
if(typeof items[i] == "object"){
if(items[i].push){
settings_add_i(items[i], overwrite, end, 0);
return;
};
for(const key in items[i])
(overwrite || custom[key] === undefined) && (custom[key] = items[i][key]);
};
};
end();
};
const settings_add = this.settings_add = (items, overwrite, callback) => settings_add_i(items ? items.push ? items : [items] : [], typeof overwrite == "boolean" ? overwrite : settings(["settings_overwrite", "overwrite"]), callback, 0);
const threads_method = () => threads.forEach(thread => thread && thread());
const threads_start = this.threads_start = () => thread === null && (thread = setInterval(threads_method, 1000 / settings(["frames_per_second", "fps"])));
this.threads_stop = () => {
if(thread === null)
return;
clearInterval(thread);
thread = null;
};
const threads_add = this.threads_add = method => {
if(typeof method != "function")
return null;
let i = 0;
const l = threads.length;
for(; i < l; i ++)
if(!threads[i])
break;
threads[i] = method;
return i;
};
const threads_remove = this.threads_remove = i => !isNaN(i) && threads[i] && (threads[i] = null);
const string_variables = this.string_variables = (string, variables, _default) => {
if(!variables)
variables = [];
else if(!variables.push)
variables = [variables];
for(let i = variables.length - 1; i >= 0; i --)
typeof variables[i] != "object" && (variables = variables.splice(i, 1));
const l = variables.length;
return string.replace(/\{([^\{\}]+)\}/g, (...arguments) => {
for(let i = 0; i < l; i ++)
if(variables[i][arguments[1]] !== undefined)
return variables[i][arguments[1]];
return _default !== undefined ? _default : arguments[0];
});
};
const update = () => load(tmp = string_variables(url || (url = settings(["kstats_url", "url"])), {
session : session
}) + (id ? "/" + id : "") + "?" + (data_key || (data_key = settings("data_key"))) + "=" + btoa(JSON.stringify({
url : window.location.href.replace(/^([^#]+)(\#.*)?$/, "$1")
})), (...arguments) => {
if(!arguments[0])
return;
const data = JSON.parse(arguments[0]),
current_session = Number(data.data.variables.current_session);
session != current_session && (document.cookie = settings("session_cookie_name") + "=" + (session = current_session) + ";expires=" + new Date(Date.now() + settings("session_timeout")).toUTCString() + ";path=/;SameSite=Lax");
if(id === null){
id = data.data.variables.id;
addEventListener("beforeunload", update);
};
});
const register_event = () => {
const date = Date.now();
if(date - last_connection > milliseconds_per_connection){
last_connection = date;
update();
};
};
this.start = () => {
if(started)
return;
started = true;
settings_add(settings("settings_files"), true, () => {
const session_pattern = new RegExp("^" + settings("session_cookie_name") + "=(.+)$");
milliseconds_per_connection = settings("milliseconds_per_connection");
!decodeURIComponent(document.cookie).split(";").some(cookie => {
const matches = cookie.trim().match(session_pattern);
if(matches){
session = Number(matches[1]);
return true;
};
}) && (session = 0);
threads_start();
register_thread = threads_add(register_event);
});
};
const construct = () => {
settings("autostart") && self.start();
};
construct();
};