253 lines
6.5 KiB
JavaScript
253 lines
6.5 KiB
JavaScript
import { ServerAuth } from "/js/connect/auth.js";
|
|
|
|
function randint(min, max) {
|
|
return Math.ceil((Math.random() * (max - min)) + min);
|
|
}
|
|
|
|
function getTraceId() {
|
|
const dict = "1234567890abcdefABCDEF";
|
|
return [...new Array(16)]
|
|
.map(() => dict[randint(0, dict.length - 1)])
|
|
.join("");
|
|
}
|
|
|
|
const curUrl = new URL(location.href);
|
|
const [address, port] = curUrl.searchParams.get("server").split(/:/);
|
|
const isTLSmode = curUrl.searchParams.get("encrypted") === "true";
|
|
|
|
const apiMethodsProtected = new WeakMap();
|
|
class ProtoApiMethods {
|
|
constructor (api) {
|
|
//this.api = api;
|
|
if (!(api instanceof ApiSocket))
|
|
throw new Error("api must be instance of ApiSocket class");
|
|
apiMethodsProtected.set(this, api);
|
|
}
|
|
|
|
set api (_) {
|
|
throw new Error("api is not writeable");
|
|
}
|
|
|
|
get api () {
|
|
return apiMethodsProtected.get(this);
|
|
}
|
|
|
|
async _protoMethod (rqdata, threadcb = null) {
|
|
if (!(this instanceof ProtoApiMethods)) {
|
|
throw new Error("_protoMethod allowed only into original abstract class");
|
|
}
|
|
|
|
const socket = this.api.socket;
|
|
const trace_id = getTraceId()
|
|
|
|
const promise = new Promise((rs, rj) => {
|
|
socket.onmessage = (ev) => {
|
|
ev = JSON.parse(ev.data);
|
|
const data = ev.result;
|
|
console.debug("Method sended:", ev);
|
|
if (ev.trace_id === trace_id)
|
|
if (ev.warning)
|
|
console.warn("Method warning:", ev.warning, "\ndetails:", ev);
|
|
if (!!ev.ended)
|
|
return rs(data);
|
|
if (typeof threadcb === 'function')
|
|
threadcb(data);
|
|
};
|
|
socket.onerror = (err) => rj(err);
|
|
});
|
|
console.debug("Client send:", { trace_id, ...rqdata });
|
|
socket.send(
|
|
JSON.stringify({ trace_id, ...rqdata }),
|
|
);
|
|
return await promise;
|
|
}
|
|
}
|
|
|
|
class ApiMethods extends ProtoApiMethods {
|
|
/*async _protoMethod (rqdata) {
|
|
throw new Error("_protoMethod allowed only into abstract class");
|
|
}*/
|
|
|
|
constructor (api) {
|
|
super(api);
|
|
}
|
|
|
|
async info (fields = null, fieldsExtSource = null) {
|
|
return await super._protoMethod({
|
|
method: "info",
|
|
fields: fields?.join(",") ?? "*",
|
|
fieldsExtSource: fieldsExtSource?.join(",") ?? "*",
|
|
});
|
|
}
|
|
|
|
async authed () {
|
|
return await super._protoMethod({
|
|
method: "authed",
|
|
});
|
|
}
|
|
|
|
async token (token) {
|
|
return await super._protoMethod({
|
|
method: "token", token
|
|
});
|
|
}
|
|
|
|
async login (username, password, gtf = false) {
|
|
return await super._protoMethod({
|
|
method: "login",
|
|
username, password,
|
|
gtf
|
|
});
|
|
}
|
|
|
|
async characters (fields = "*") {
|
|
return await super._protoMethod({
|
|
method: "characters", fields
|
|
});
|
|
}
|
|
}
|
|
|
|
const apiHTMLProtected = new WeakMap();
|
|
class ApiHTML {
|
|
constructor (api) {
|
|
//this.api = api;
|
|
if (!(api instanceof ApiSocket))
|
|
throw new Error("api must be instance of ApiSocket class");
|
|
apiHTMLProtected.set(this, api);
|
|
}
|
|
|
|
set api (_) {
|
|
throw new Error("api is not writeable");
|
|
}
|
|
|
|
get api () {
|
|
return apiHTMLProtected.get(this);
|
|
}
|
|
|
|
async renderMainMenu (user, bgUrl = null, favicon = null) {
|
|
bgUrl = bgUrl ?? "assets/hello/1.png";
|
|
favicon = favicon ?? "favicon.png";
|
|
|
|
document.body.style.backgroundImage = `url(${
|
|
JSON.stringify(bgUrl)
|
|
})`;
|
|
document.body.style.backgroundSize = `${screen.width}px ${screen.height}px`;
|
|
$.find('link[rel="icon"]')[0].href = favicon;
|
|
|
|
document.getElementById("server.area").innerHTML = '';
|
|
$(document.getElementById("server.area")).append(ServerAuth.mainMenuForm);
|
|
// JS-Events
|
|
this.api.methods.characters("*")
|
|
.then(characters => {
|
|
const addCharBtn = document.createElement("button");
|
|
addCharBtn.setAttribute("type", "button");
|
|
["btn", "btn-success", "btn-outline-light"].forEach(c =>
|
|
addCharBtn.classList.add(c));
|
|
addCharBtn.innerText = "Add character";
|
|
|
|
const charlist = $.find("#user-charlist")[0];
|
|
for (let character of characters) {
|
|
// TODO: Create add chars to charlist
|
|
}
|
|
charlist.append(addCharBtn);
|
|
|
|
// Display
|
|
$.find("#mainmenu-load")[0].hidden = true;
|
|
$.find("#main-panel")[0].hidden = false;
|
|
}).catch(err => {
|
|
// Logging error
|
|
console.error(err.stack);
|
|
// Display
|
|
$.find("#mainmenu-load")[0].hidden = true;
|
|
$.find("#mainmenu-error")[0].hidden = false;
|
|
});
|
|
}
|
|
|
|
async renderAuth (authMode, bgUrl = null, favicon = null) {
|
|
bgUrl = bgUrl ?? "assets/hello/1.png";
|
|
favicon = favicon ?? "favicon.png";
|
|
|
|
document.body.style.backgroundImage = `url(${
|
|
JSON.stringify(bgUrl)
|
|
})`;
|
|
document.body.style.backgroundSize = `${screen.width}px ${screen.height}px`;
|
|
$.find('link[rel="icon"]')[0].href = favicon;
|
|
|
|
document.getElementById("server.area").innerHTML = '';
|
|
$(document.getElementById("server.area")).append(ServerAuth.authForm);
|
|
|
|
$.find("#server-code-form")[0].hidden = authMode !== "password";
|
|
|
|
[...$.find(".auth-act-item")].forEach(authEl => {
|
|
const authElJQ = $(authEl);
|
|
const isHidden = authEl.hidden;
|
|
authEl.hidden = false;
|
|
const buttonBlock = authElJQ.find(".btn-auth-block")[0];
|
|
const paramsBlock = authElJQ.find(".params-auth")[0];
|
|
|
|
buttonBlock.style.marginTop = `calc(100% - ${paramsBlock.offsetHeight}px)`;
|
|
authEl.hidden = isHidden;
|
|
});
|
|
|
|
$.find("#menu-log-in")[0].onclick = function () {
|
|
$.find("#log-in")[0].hidden = false;
|
|
$.find("#register")[0].hidden = true;
|
|
}
|
|
|
|
$.find("#menu-register")[0].onclick = function () {
|
|
$.find("#log-in")[0].hidden = true;
|
|
$.find("#register")[0].hidden = false;
|
|
}
|
|
|
|
$.find("#auth-btn")[0].onclick = () => {
|
|
this.api.methods.login(
|
|
$.find("#username")[0].value,
|
|
$.find("#password")[0].value,
|
|
true
|
|
)
|
|
.then(user => {
|
|
const { token } = user;
|
|
localStorage.setItem(`my-token>${!isTLSmode ? "ws" : "wss"}://${address}:${port}`, token);
|
|
this.renderMainMenu(user, bgUrl, favicon);
|
|
});
|
|
}
|
|
$.find("#reg-btn")[0].onclick = () => { }
|
|
}
|
|
}
|
|
|
|
const apiSocketsProtected = new WeakMap();
|
|
export class ApiSocket {
|
|
constructor ({
|
|
isTLSmode, address, port
|
|
}) {
|
|
this.tlsMode = isTLSmode;
|
|
this.address = address;
|
|
this.port = port;
|
|
|
|
//this.socket = new WebSocket(`${!isTLSmode ? "ws" : "wss"}://${address}:${port}`);
|
|
const socket = new WebSocket(`${!isTLSmode ? "ws" : "wss"}://${address}:${port}`);
|
|
apiSocketsProtected.set(this, socket);
|
|
this.methods = new ApiMethods(this);
|
|
this.user = null;
|
|
|
|
this.html = new ApiHTML(this);
|
|
}
|
|
|
|
set socket (_) {
|
|
throw new Error("api is not writeable");
|
|
}
|
|
|
|
get socket () {
|
|
return apiSocketsProtected.get(this);
|
|
}
|
|
|
|
async run () {
|
|
const socket = this.socket;
|
|
const promise = new Promise((rs, rj) => {
|
|
socket.onopen = () => this.methods.info().then(data => rs(data));
|
|
socket.onerror = (err) => rj(err);
|
|
});
|
|
return await promise;
|
|
}
|
|
}
|