feat: created (partially) an admin interface
This commit is contained in:
parent
337a0618b9
commit
7c8b2d8cf1
79
src/admin.html
Normal file
79
src/admin.html
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Admin</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dashboard {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="login">
|
||||||
|
<input type="password" id="password-text">
|
||||||
|
<input type="button" id="password-button" value="Login" onclick="sendCreds();">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dashboard">
|
||||||
|
<ul id="stateList"></ul>
|
||||||
|
<button id="save">save</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var websocket = new WebSocket("ws://127.0.0.1:6789/");
|
||||||
|
var passwordInput = document.querySelector('#password-text');
|
||||||
|
|
||||||
|
var divLogin = document.querySelector("#login");
|
||||||
|
var divDashboard = document.querySelector("#dashboard");
|
||||||
|
var stateList = document.querySelector("#stateList");
|
||||||
|
var saveButton = document.getElementById('save');
|
||||||
|
|
||||||
|
saveButton.onclick = function (event) {
|
||||||
|
websocket.send(JSON.stringify({ 'admin': 'save' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function receiveStates(ev) {
|
||||||
|
let msg = JSON.parse(ev.data);
|
||||||
|
let states = msg.state
|
||||||
|
for (var i = 0; i < states.length; i++) {
|
||||||
|
var state = states[i];
|
||||||
|
var li = document.createElement('li');
|
||||||
|
li.appendChild(document.createTextNode(state));
|
||||||
|
stateList.appendChild(li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function authSuccess(ev) {
|
||||||
|
let msg = JSON.parse(ev.data);
|
||||||
|
if (msg.auth === "success") {
|
||||||
|
divLogin.style.display = "none";
|
||||||
|
divDashboard.style.display = "unset";
|
||||||
|
websocket.removeEventListener('message', authSuccess);
|
||||||
|
websocket.send(JSON.stringify({ "state": "get" }));
|
||||||
|
websocket.addEventListener('message', receiveStates);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function sendCreds() {
|
||||||
|
var message = JSON.stringify({ "auth": passwordInput.value });
|
||||||
|
websocket.send(message)
|
||||||
|
websocket.addEventListener('message', authSuccess);
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordInput.addEventListener("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") { sendCreds(); }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
import mgba.core
|
import mgba.core
|
||||||
import mgba.image
|
import mgba.image
|
||||||
|
@ -10,8 +11,8 @@ import pyvirtualcam
|
||||||
import websockets
|
import websockets
|
||||||
from mgba._pylib import ffi
|
from mgba._pylib import ffi
|
||||||
|
|
||||||
WIDTH = 240
|
WIDTH: int = 240
|
||||||
HEIGHT = 160
|
HEIGHT: int = 160
|
||||||
URI: str = "ws://127.0.0.1:6789/"
|
URI: str = "ws://127.0.0.1:6789/"
|
||||||
FPS: int = 60
|
FPS: int = 60
|
||||||
HZ: int = 10
|
HZ: int = 10
|
||||||
|
@ -36,7 +37,7 @@ core.set_video_buffer(screen)
|
||||||
core.reset()
|
core.reset()
|
||||||
mgba.log.silence()
|
mgba.log.silence()
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
# logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def parse_message(message: dict[str, str]):
|
def parse_message(message: dict[str, str]):
|
||||||
|
@ -60,7 +61,7 @@ def parse_message(message: dict[str, str]):
|
||||||
data = message["admin"]
|
data = message["admin"]
|
||||||
if data == "save": # voodoo magic incomming
|
if data == "save": # voodoo magic incomming
|
||||||
state = core.save_raw_state()
|
state = core.save_raw_state()
|
||||||
with open("states/test.state", "wb") as state_file:
|
with open(f"states/{time.strftime('%Y-%m-%dT%H:%M:%S')}.state", "wb") as state_file:
|
||||||
for byte in state:
|
for byte in state:
|
||||||
state_file.write(byte.to_bytes(4, byteorder="big", signed=False))
|
state_file.write(byte.to_bytes(4, byteorder="big", signed=False))
|
||||||
elif data == "load": # black magic incomming
|
elif data == "load": # black magic incomming
|
||||||
|
@ -78,7 +79,7 @@ async def main():
|
||||||
with pyvirtualcam.Camera(width=WIDTH, height=HEIGHT, fps=FPS) as cam:
|
with pyvirtualcam.Camera(width=WIDTH, height=HEIGHT, fps=FPS) as cam:
|
||||||
logging.debug(f"Using virtual camera: {cam.device}")
|
logging.debug(f"Using virtual camera: {cam.device}")
|
||||||
async with websockets.connect(URI) as websocket:
|
async with websockets.connect(URI) as websocket:
|
||||||
await websocket.send('{"auth":"password"}')
|
await websocket.send('{"auth":"emulator_password"}')
|
||||||
logging.debug(f"connected to: {websocket}")
|
logging.debug(f"connected to: {websocket}")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
@ -8,15 +9,22 @@ import websockets
|
||||||
|
|
||||||
from utils import User, Users, Votes
|
from utils import User, Users, Votes
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
# logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
PASSWORD_ADMIN: str = "password"
|
PASSWORD_ADMIN: str = "admin_password"
|
||||||
PASSWORD_EMU: str = "password"
|
PASSWORD_EMU: str = "emulator_password"
|
||||||
VOTES: Votes = Votes()
|
VOTES: Votes = Votes()
|
||||||
USERS: Users = Users()
|
USERS: Users = Users()
|
||||||
|
|
||||||
|
|
||||||
async def parse_message(user: User, message: dict[str, str]):
|
async def send_states(user: User) -> None:
|
||||||
|
files = os.listdir("states")
|
||||||
|
states = list(filter(lambda x: x.endswith(".state"), files))
|
||||||
|
message = json.dumps({"state": states})
|
||||||
|
await user.send(message)
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_message(user: User, message: dict[str, str]) -> None:
|
||||||
"""Parse the user's message.
|
"""Parse the user's message.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -25,12 +33,14 @@ async def parse_message(user: User, message: dict[str, str]):
|
||||||
"""
|
"""
|
||||||
if "auth" in message:
|
if "auth" in message:
|
||||||
data = message["auth"]
|
data = message["auth"]
|
||||||
if USERS.emulator is None and data == PASSWORD_EMU:
|
if USERS.emulator is None and data == PASSWORD_EMU and user != USERS.admin:
|
||||||
USERS.emulator = user
|
USERS.emulator = user
|
||||||
logging.debug(f"emulator authenticated: {user}")
|
logging.debug(f"emulator authenticated: {user}")
|
||||||
elif USERS.admin is None and data == PASSWORD_ADMIN:
|
await user.send('{"auth":"success"}')
|
||||||
|
elif USERS.admin is None and data == PASSWORD_ADMIN and user != USERS.emulator:
|
||||||
USERS.admin = user
|
USERS.admin = user
|
||||||
logging.debug(f"admin authenticated: {user}")
|
logging.debug(f"admin authenticated: {user}")
|
||||||
|
await user.send('{"auth":"success"}')
|
||||||
|
|
||||||
if "action" in message:
|
if "action" in message:
|
||||||
data = message["action"]
|
data = message["action"]
|
||||||
|
@ -65,6 +75,16 @@ async def parse_message(user: User, message: dict[str, str]):
|
||||||
else:
|
else:
|
||||||
logging.error(f"user is not emulator: {user}")
|
logging.error(f"user is not emulator: {user}")
|
||||||
|
|
||||||
|
if "state" in message:
|
||||||
|
data = message["state"]
|
||||||
|
if user == USERS.admin:
|
||||||
|
if data == "get":
|
||||||
|
await send_states(user)
|
||||||
|
else:
|
||||||
|
logging.error(f"unsupported state action: {data}")
|
||||||
|
else:
|
||||||
|
logging.error(f"user is not admin: {user}")
|
||||||
|
|
||||||
|
|
||||||
async def handler(websocket: Any, path: str):
|
async def handler(websocket: Any, path: str):
|
||||||
"""Handle the messages sent by a user.
|
"""Handle the messages sent by a user.
|
||||||
|
@ -84,6 +104,12 @@ async def handler(websocket: Any, path: str):
|
||||||
finally:
|
finally:
|
||||||
# Unregister user
|
# Unregister user
|
||||||
USERS.unregister(user)
|
USERS.unregister(user)
|
||||||
|
if user == USERS.admin:
|
||||||
|
USERS.admin = None
|
||||||
|
logging.debug(f"admin disconnected: {user}")
|
||||||
|
elif user == USERS.emulator:
|
||||||
|
logging.debug(f"emulator disconnected: {user}")
|
||||||
|
USERS.emulator = None
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
|
Loading…
Reference in a new issue