From eea681d435797bcc56908ffa2a16237d1d21f9f7 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Mon, 24 May 2021 13:33:46 +0200 Subject: [PATCH] changed to async --- www/res/js/modules/locutus.js | 66 ++++++++++------- www/res/js/modules/usimp.js | 129 +++++++++++++++++++++------------- www/res/styles/styles.css | 8 ++- 3 files changed, 130 insertions(+), 73 deletions(-) diff --git a/www/res/js/modules/locutus.js b/www/res/js/modules/locutus.js index 91ba429..463e0b1 100644 --- a/www/res/js/modules/locutus.js +++ b/www/res/js/modules/locutus.js @@ -40,7 +40,6 @@ export class App { } handleHash(hash) { - console.log(hash); if (hash[0] === '#') hash = hash.substr(1); let defaultCase = () => { @@ -81,19 +80,30 @@ export class App { //this.setHash(hash); } - login(accountName, domainName, password) { - return USIMP.Domain.fromName(domainName).then(domain => { - let session = new USIMP.Session(domain); - session.authenticate(accountName, password) - .catch((event) => { - console.error(`Unable to reach domain server: ${event}`); - }) - .then(() => { - this.session = session; - this.defaultLocation = "/"; - this.setHash("/"); - }); - }); + async login(accountName, domainName, password) { + let domain; + try { + domain = await USIMP.Domain.fromName(domainName); + } catch (error) { + if (error instanceof DOMException) { + throw Error("Connection timed out"); + } else { + throw Error("Invalid USIMP domain"); + } + } + + let session = new USIMP.Session(domain); + let rtt = await session.chooseDomainServer(); + console.log(rtt); + + let response = await session.authenticate(accountName, password); + if (response.status === "success") { + this.session = session; + this.defaultLocation = "/"; + this.setHash("/"); + } else { + throw Error(response.message); + } } hideMain() { @@ -167,15 +177,19 @@ export class App { form.appendChild(div); } - this.login(form.account.value, form.domain.value, form.password.value) - .catch(reason => { + try { + await this.login(form.account.value, form.domain.value, form.password.value); + } catch (error) { + if (error.toString() === "Error: unable to authenticate") { + document.getElementsByName("account")[0].setAttribute("invalid", "invalid"); + } else { document.getElementsByName("domain")[0].setAttribute("invalid", "invalid"); - formError("Invalid USIMP domain"); - console.error(reason); - }) - .finally(() => { - for (let e of form) e.disabled = false; - }); + } + formError(error.toString()); + console.error(error); + } finally { + for (let e of form) e.disabled = false; + } }); this.windows.appendChild(win); @@ -184,6 +198,10 @@ export class App { event.target.removeAttribute("invalid"); }); + document.getElementsByName("account")[0].addEventListener("input", (event) => { + event.target.removeAttribute("invalid"); + }); + document.getElementsByName("account")[0].focus(); } @@ -192,7 +210,7 @@ export class App {
- +
`; @@ -208,7 +226,7 @@ export class App { }); this.session.subscribe(response => { - this.addMessage(response.event.data.message); + this.addMessage(response.data.event.data.message); }); } } diff --git a/www/res/js/modules/usimp.js b/www/res/js/modules/usimp.js index bb9c87a..158218e 100644 --- a/www/res/js/modules/usimp.js +++ b/www/res/js/modules/usimp.js @@ -15,47 +15,51 @@ export class Domain { this.name = jsonData.name; this.id = jsonData.id; this.servers = []; - for (let domainServer of domainServers) { + for (const domainServer of domainServers) { this.servers.push(new DomainServer(domainServer)); } this.invalidServers = []; } static async fromName(domainName) { - return fetch(`https://${domainName}/.well-known/usimp.json`, { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 2000); + + let response = await fetch(`https://${domainName}/.well-known/usimp.json`, { redirect: "manual", - }).then(response => { - if (response.ok) { - return response.json(); - } else { - throw "Invalid response"; - } - }).then(data => { - return new Domain(data.domain, data.domain_servers); + signal: controller.signal, }); + + clearTimeout(timer); + if (!response.ok) { + throw Error("Invalid response"); + } + + const data = await response.json(); + return new Domain(data.domain, data.domain_servers); } chooseDomainServer() { if (this.servers.length === 0) throw Error("No domain servers specified"); - this.servers.filter(srv => this.invalidServers.map(srv => srv.id).includes(srv.id)); - if (this.servers.length === 0) throw Error("No domain servers reachable"); - if (this.servers.length === 1) return this.servers[0]; + const servers = this.servers.filter(srv => !this.invalidServers.map(srv => srv.id).includes(srv.id)); + if (servers.length === 0) throw Error("No domain servers reachable"); + if (servers.length === 1) return servers[0]; - let priority = this.servers.reduce((min, srv) => Math.min(min, srv.priority), Infinity); - let domainServers = this.servers.filter(srv => srv.priority === priority); - if (domainServers.length === 1) return this.servers[0]; + const priority = servers.reduce((min, srv) => Math.min(min, srv.priority), Infinity); + const domainServers = servers.filter(srv => srv.priority === priority); + if (domainServers.length === 1) return servers[0]; - let totalWeight = domainServers.reduce((total, srv) => total + srv.weight, 0); - let w = Math.floor(Math.random() * totalWeight); + const totalWeight = domainServers.reduce((total, srv) => total + srv.weight, 0); + const w = Math.floor(Math.random() * totalWeight); let accumulator = 0; - for (let srv of domainServers) { + for (const srv of domainServers) { accumulator += srv.weight; if (w < accumulator) return srv; } - throw "Domain server selection did not work correctly"; + throw Error("Domain server selection did not work correctly"); } } @@ -107,37 +111,51 @@ export class Session { constructor(domain) { this.domain = domain; - this.server = domain.chooseDomainServer(); this.numRequests = 0; + } - const host = this.server.host; - const protocols = this.server.protocols; + async chooseDomainServer() { + while (!this.server) { + this.server = this.domain.chooseDomainServer(); - /* - if ("wss" in protocols) { - this.wsConnection = new WebSocket(`wss://${host}:${protocols.wss}/_usimp/websocket`, ["usimp"]); - } else if ("ws" in protocols) { - this.wsConnection = new WebSocket(`ws://${host}:${protocols.ws}/_usimp/websocket`, ["usimp"]) - } - */ + const host = this.server.host; + const protocols = this.server.protocols; - if ("https" in protocols) { - this.httpBaseUrl = `https://${host}:${protocols.https}/_usimp`; - } else if ("http" in protocols) { - this.httpBaseUrl = `http://${host}:${protocols.http}/_usimp`; - } else { - throw "Domain server provides no supported transport protocols"; + /* + if ("wss" in protocols) { + this.wsConnection = new WebSocket(`wss://${host}:${protocols.wss}/_usimp/websocket`, ["usimp"]); + } + */ + + // TODO http -> https + if ("http" in protocols) { + this.httpBaseUrl = `http://${host}:${protocols.http}/_usimp`; + try { + return await this.ping(); + } catch { + this.domain.invalidServers.push(this.server); + this.server = null; + } + } else { + console.warn(`Domain server ${this.server} does not support 'https' transport protocol`); + this.domain.invalidServers.push(this.server); + this.server = null; + } } } - send(endpoint, data) { + async send(endpoint, data, timeout = 2000, forceHttp = false) { this.numRequests++; - if (this.wsConnection) { + + if (!forceHttp && this.wsConnection) { this.wsConnection.send(JSON.stringify({ 'request_num': this.numRequests, 'data': data })); } else { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeout); + let headers = { 'Content-Type': 'application/json', 'To-Domain': this.domain.id, @@ -147,28 +165,45 @@ export class Session { headers['Authorization'] = `usimp ${this.token}`; } - return fetch(`${this.httpBaseUrl}/${endpoint}`, { + const startTime = new Date(); + let response = await fetch(`${this.httpBaseUrl}/${endpoint}`, { method: "POST", headers: headers, body: JSON.stringify(data), - }).then(response => { - return response.json(); + signal: controller.signal, }); + const endTime = new Date(); + clearTimeout(timer); + + let responseData = await response.json(); + responseData.duration = endTime - startTime; + return responseData; } } - authenticate(accountName, password) { - return this.send("authenticate", { + async ping() { + let result = {"http": null, "ws": null}; + const res = await this.send("ping", {}, undefined, true); + result.http = res.duration; + if (this.wsConnection) { + await this.wsConnection.ping(); + } + return result; + } + + async authenticate(accountName, password) { + let response = await this.send("authenticate", { type: "password", name: accountName, password: password, - }).then(response => { - this.token = response.token; - return response; }); + if (response.status === "success") { + this.token = response.data.token; + } + return response; } - sendEvent(roomId, data) { + async sendEvent(roomId, data) { return this.send("send_event", { room_id: roomId, data: data, diff --git a/www/res/styles/styles.css b/www/res/styles/styles.css index 9c9a091..8de3afd 100644 --- a/www/res/styles/styles.css +++ b/www/res/styles/styles.css @@ -54,7 +54,6 @@ div#windows { div#windows > *, main { - backdrop-filter: blur(32px); border: 1px solid var(--bg-win); background: var(--bg-win); border-radius: 4px; @@ -68,6 +67,7 @@ main { } div#windows > * { + backdrop-filter: blur(32px); padding: 0.5em 1em; } @@ -199,6 +199,7 @@ main .chat-history { height: calc(100% - 3em); overflow-y: scroll; box-sizing: border-box; + backdrop-filter: blur(4px); } main .chat-input-wrapper { @@ -207,6 +208,7 @@ main .chat-input-wrapper { border-top: 1px solid var(--bg-win); padding: 0.5em 1em; box-sizing: border-box; + backdrop-filter: blur(32px); } main .chat-input-wrapper input { @@ -218,6 +220,7 @@ main .chat-input-wrapper input { box-sizing: border-box; outline: none; padding: 0.25em 1em; + font-size: 0.875rem; } main .chat .message { @@ -228,5 +231,6 @@ main .chat .message { display: block; width: fit-content; width: -moz-fit-content; - background-color: var(--bg); + background-color: rgba(255, 255, 255, 0.875); + font-size: 0.875rem; }