fix reconnect and add banner message when trying to reconnect5r

This commit is contained in:
hippoz 2022-01-25 17:10:35 +02:00
parent 6bbd925dbc
commit 0f881b668c
Signed by: hippoz
GPG key ID: 7C52899193467641
5 changed files with 73 additions and 29 deletions

View file

@ -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())

View file

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

View file

@ -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(`
<div class="card small-card center-text">
<h2>Login</h2>
<p>You need to enter the login code before you can start controlling your device.</p>
<br>
<div class="full-width">
<input id="code-input" class="input full-width" placeholder="Code">
<br>
<button id="continue-button" class="button-default full-width">Continue</button>
</div>
<h2 id="banner-title"></h2>
<p id="banner-text"></p>
</div>
`).children[0];
this.element.querySelector("#continue-button").addEventListener("click", () => {
if (this.onPasswordSubmitted)
this.onPasswordSubmitted(this.element.querySelector("#code-input").value);
});
target.appendChild(this.element);
}
}
unmount() {
if (!this.element)
return; // Already unmounted
this.element.parentElement.removeChild(this.element);
this.element = null;
}
}
export default Banner;

View file

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

View file

@ -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 {