diff --git a/capybara.py b/capybara.py index 97805c4..421c9fc 100755 --- a/capybara.py +++ b/capybara.py @@ -2,7 +2,7 @@ import sys from asyncio import wait_for, TimeoutError from base64 import b64encode from sanic import Sanic -from sanic.response import file, redirect +from sanic.response import file, redirect, empty from InputController import InputController from MessageParser import MessageParser @@ -10,7 +10,7 @@ from MessageParser import MessageParser app = Sanic( "capybara", - load_env="CAPYBARA_" + env_prefix="CAPYBARA_" ) input_controller = InputController() control_message_parser = MessageParser() @@ -40,13 +40,15 @@ async def gateway(req, ws): return code, args = control_message_parser.parse(auth_payload) - if (not code or + if ( + not code or code != "0" or - args["auth_string"] != app.ctx.EXPECTED_AUTH_STRING): # 0 is the code for the initial auth packet + args["auth_string"] != app.ctx.EXPECTED_AUTH_STRING + ): # 0 is the code for the initial auth packet await ws.close(code=4001, reason="Invalid auth packet") return - await ws.send("1") # send a single `1` to let the client know the server is input packets + await ws.send("1") # send a single `1` to let the client know the server is accepting input packets while True: input_controller.process_message(await ws.recv()) diff --git a/frontend/src/App.js b/frontend/src/App.js index 49473a4..85d193c 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,3 +1,4 @@ +import Banner from "./Banner"; import Connection from "./Connection"; import KeyboardController from "./Keyboard"; import { getAuth, setAuth } from "./LocalConfiguration"; @@ -18,6 +19,8 @@ class App { this.unmountApp(); if (code === 4001) { // 4001 - code for bad auth this.transitionTo("login"); + } else { + this.transitionTo("reconnectingBanner"); } }); this.connection.onHandshakeCompleted = () => { @@ -28,24 +31,45 @@ class App { transitionTo(type) { switch (type) { case "login": + this.unmountBannerComponent(); this.unmountApp(); this.mountLoginComponent(); break; case "app": + this.unmountBannerComponent(); this.unmountLoginComponent(); this.mountApp(); break; + case "reconnectingBanner": + this.unmountApp(); + this.unmountLoginComponent(); + this.mountBannerComponent("Connecting...", "Looks like you've lost connection. We're trying to reconnect you."); + break; default: throw new Error(`transitionTo type ${type} is invalid`); } } + mountBannerComponent(title, text) { + if (!this.bannerComponent) + this.bannerComponent = new Banner(); + + this.bannerComponent.mountOn(this.mountElement); + this.bannerComponent.updateTitle(title); + this.bannerComponent.updateText(text); + } + + unmountBannerComponent() { + if (this.bannerComponent) + this.bannerComponent.unmount(); + } + mountLoginComponent() { if (!this.loginPromptComponent) this.loginPromptComponent = new LoginPrompt(this.connection); this.loginPromptComponent.mountOn(this.mountElement); - this.loginPromptComponent.onPasswordSubmitted = p => { + this.loginPromptComponent.onPasswordSubmitted = (p) => { setAuth(p); this.connection.connect(p); }; diff --git a/frontend/src/Banner.js b/frontend/src/Banner.js index 7395654..d9f1f6d 100644 --- a/frontend/src/Banner.js +++ b/frontend/src/Banner.js @@ -1,10 +1,19 @@ class Banner { constructor() { - this.text = null; + this.element = null; + + this.title = ""; + this.text = ""; } - updateText(text) { - this.text = text; + updateText(newText) { + this.text = newText; + this.element.querySelector("#banner-text").innerText = this.text; + } + + updateTitle(newTitle) { + this.title = newTitle; + this.element.querySelector("#banner-title").innerText = this.title; } mountOn(target) { @@ -13,22 +22,21 @@ class Banner { this.element = document.createRange().createContextualFragment(`
-

Login

-

You need to enter the login code before you can start controlling your device.

-
-
- -
- -
+ +
`).children[0]; - this.element.querySelector("#continue-button").addEventListener("click", () => { - if (this.onPasswordSubmitted) - this.onPasswordSubmitted(this.element.querySelector("#code-input").value); - }); - target.appendChild(this.element); } -} \ No newline at end of file + + unmount() { + if (!this.element) + return; // Already unmounted + + this.element.parentElement.removeChild(this.element); + this.element = null; + } +} + +export default Banner; diff --git a/frontend/src/Connection.js b/frontend/src/Connection.js index 75e4113..0eae6f2 100644 --- a/frontend/src/Connection.js +++ b/frontend/src/Connection.js @@ -7,6 +7,7 @@ class Connection { this.messageLog = Logger(["Connection", "Message"], ["log"]).log; this.url = url; this.isReady = false; + this.reconnectTimeout = 0; } formatAuthString(password) { @@ -18,6 +19,7 @@ class Connection { this.ws.onerror = (e) => this.log("Error", e); this.ws.onopen = () => { this.log("Open"); + this.reconnectTimeout = 0; this.log("Sending authentication packet"); this.ws.send(`0${this.formatAuthString(password)}`); // send auth packet }; @@ -35,9 +37,12 @@ class Connection { this.log("Closed due to bad auth - skipping reconnect"); return; } - this.log("Closed - attempting to reconnect in 4000ms"); this.isReady = false; - setTimeout(() => this.connect(), 4000); + this.reconnectTimeout += 400; + if (this.reconnectTimeout >= 30000) + this.reconnectTimeout = 30000; + this.log(`Closed - will reconnect in ${this.reconnectTimeout}ms`); + setTimeout(() => this.connect(password), this.reconnectTimeout); } } diff --git a/frontend/src/styles/main.css b/frontend/src/styles/main.css index 09a36ef..daba610 100644 --- a/frontend/src/styles/main.css +++ b/frontend/src/styles/main.css @@ -20,7 +20,7 @@ body { color: var(--accent-bg-color); overflow-x: none; margin: 0; - padding: 8px; + padding: 12px; } .card { @@ -105,7 +105,7 @@ body { } .touchpad { - height: clamp(5rem, 30rem, 55vh); + height: clamp(5rem, 30rem, 50vh); width: 100%; background-color: var(--accent-bg-color); border-radius: var(--card-border-radius); @@ -113,9 +113,15 @@ body { /* for virtual keyboard */ +.hg-theme-default { + font-weight: var(--main-font-weight); + font-family: var(--fonts-regular); +} + .keyboard { + padding: 8px; color: var(--body-bg-color); - margin-top: 28px; + margin-top: 24px; border-radius: var(--card-border-radius); background-color: var(--accent-bg-color); } @@ -126,7 +132,6 @@ body { .hg-button { margin: 2px; - padding: 12px; } .hg-activeButton {