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 json
|
||||
import logging
|
||||
import time
|
||||
|
||||
import mgba.core
|
||||
import mgba.image
|
||||
|
@ -10,8 +11,8 @@ import pyvirtualcam
|
|||
import websockets
|
||||
from mgba._pylib import ffi
|
||||
|
||||
WIDTH = 240
|
||||
HEIGHT = 160
|
||||
WIDTH: int = 240
|
||||
HEIGHT: int = 160
|
||||
URI: str = "ws://127.0.0.1:6789/"
|
||||
FPS: int = 60
|
||||
HZ: int = 10
|
||||
|
@ -36,7 +37,7 @@ core.set_video_buffer(screen)
|
|||
core.reset()
|
||||
mgba.log.silence()
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
# logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
def parse_message(message: dict[str, str]):
|
||||
|
@ -60,7 +61,7 @@ def parse_message(message: dict[str, str]):
|
|||
data = message["admin"]
|
||||
if data == "save": # voodoo magic incomming
|
||||
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:
|
||||
state_file.write(byte.to_bytes(4, byteorder="big", signed=False))
|
||||
elif data == "load": # black magic incomming
|
||||
|
@ -78,7 +79,7 @@ async def main():
|
|||
with pyvirtualcam.Camera(width=WIDTH, height=HEIGHT, fps=FPS) as cam:
|
||||
logging.debug(f"Using virtual camera: {cam.device}")
|
||||
async with websockets.connect(URI) as websocket:
|
||||
await websocket.send('{"auth":"password"}')
|
||||
await websocket.send('{"auth":"emulator_password"}')
|
||||
logging.debug(f"connected to: {websocket}")
|
||||
|
||||
while True:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
|
@ -8,15 +9,22 @@ import websockets
|
|||
|
||||
from utils import User, Users, Votes
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
# logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
PASSWORD_ADMIN: str = "password"
|
||||
PASSWORD_EMU: str = "password"
|
||||
PASSWORD_ADMIN: str = "admin_password"
|
||||
PASSWORD_EMU: str = "emulator_password"
|
||||
VOTES: Votes = Votes()
|
||||
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.
|
||||
|
||||
Args:
|
||||
|
@ -25,12 +33,14 @@ async def parse_message(user: User, message: dict[str, str]):
|
|||
"""
|
||||
if "auth" in message:
|
||||
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
|
||||
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
|
||||
logging.debug(f"admin authenticated: {user}")
|
||||
await user.send('{"auth":"success"}')
|
||||
|
||||
if "action" in message:
|
||||
data = message["action"]
|
||||
|
@ -65,6 +75,16 @@ async def parse_message(user: User, message: dict[str, str]):
|
|||
else:
|
||||
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):
|
||||
"""Handle the messages sent by a user.
|
||||
|
@ -84,6 +104,12 @@ async def handler(websocket: Any, path: str):
|
|||
finally:
|
||||
# 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():
|
||||
|
|
Loading…
Reference in a new issue