feat: working admin interface

(need rework/styling)
This commit is contained in:
Laureηt 2021-11-20 19:58:48 +01:00
parent 32cd1080bf
commit 89d3ef103e
No known key found for this signature in database
GPG key ID: D88C6B294FD40994
4 changed files with 52 additions and 43 deletions

View file

@ -30,13 +30,13 @@
</div>
<script>
var websocket = new WebSocket("ws://127.0.0.1:6789/");
var passwordInput = document.querySelector('#password-text');
let websocket = new WebSocket("ws://127.0.0.1:6789/");
let 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');
let divLogin = document.querySelector("#login");
let divDashboard = document.querySelector("#dashboard");
let stateList = document.querySelector("#stateList");
let saveButton = document.getElementById('save');
saveButton.onclick = function (event) {
websocket.send(JSON.stringify({ 'admin': 'save' }));
@ -44,11 +44,14 @@
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));
let states = msg.states
for (let i = 0; i < states.length; i++) {
let state = states[i];
let li = document.createElement('li');
let button = document.createElement('button');
button.onclick = () => websocket.send(JSON.stringify({ 'admin': "load:" + state }))
button.appendChild(document.createTextNode(state));
li.appendChild(button);
stateList.appendChild(li);
}
}
@ -59,13 +62,12 @@
divLogin.style.display = "none";
divDashboard.style.display = "unset";
websocket.removeEventListener('message', authSuccess);
websocket.send(JSON.stringify({ "state": "get" }));
websocket.addEventListener('message', receiveStates);
receiveStates(ev);
}
};
function sendCreds() {
var message = JSON.stringify({ "auth": passwordInput.value });
let message = JSON.stringify({ "auth": passwordInput.value });
websocket.send(message)
websocket.addEventListener('message', authSuccess);
};

View file

@ -1,5 +1,6 @@
import asyncio
import logging
import os
import threading
import time
from subprocess import PIPE, Popen # nosec
@ -9,6 +10,7 @@ import mgba.image
import mgba.log
import redis
import utils
from settings import (
EMULATOR_FPS,
EMULATOR_HEIGHT,
@ -27,7 +29,6 @@ from settings import (
REDIS_PORT,
RTMP_STREAM_URI,
)
from utils import States
core = mgba.core.load_path(EMULATOR_ROM_PATH)
screen = mgba.image.Image(EMULATOR_WIDTH, EMULATOR_HEIGHT)
@ -38,8 +39,6 @@ logging.basicConfig(level=logging.DEBUG)
mgba.log.silence()
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0)
states: States = States()
def next_action():
"""Select the next key from the redis database.
@ -97,13 +96,12 @@ def state_manager(loop):
ps.subscribe("admin")
while True:
for message in ps.listen():
logging.debug(message)
if message["type"] == "message":
data = message["data"].decode("utf-8")
if data == "save":
asyncio.ensure_future(states.save(core), loop=loop)
asyncio.ensure_future(utils.save(core), loop=loop)
elif data.startswith("load:"):
asyncio.ensure_future(states.load(core, data.removeprefix("load:")), loop=loop)
asyncio.ensure_future(utils.load(core, data.removeprefix("load:")), loop=loop)
async def emulator():
@ -127,6 +125,13 @@ async def emulator():
async def main(loop):
# setup states in redis
files = os.listdir("states")
states = list(filter(lambda x: x.endswith(".state"), files))
for state in states:
r.sadd("states", state.removesuffix(".state")) # voir si oneline possible
thread = threading.Thread(target=state_manager, args=(loop,))
thread.start()

View file

@ -2,6 +2,7 @@ import asyncio
import json
import logging
import time
from typing import Union
import redis
import websockets
@ -38,14 +39,20 @@ async def parse_message(user: User, message: dict[str, str]) -> None:
if USERS.admin is None and data == PASSWORD_ADMIN:
USERS.admin = user
logging.debug(f"admin authenticated: {user}")
await user.send('{"auth":"success"}')
response: dict[str, Union[str, list[str]]] = dict()
response["auth"] = "success"
states = r.smembers("states")
stringlist = [x.decode("utf-8") for x in states]
response["states"] = sorted(stringlist)
await user.send(json.dumps(response))
if "admin" in message:
if user == USERS.admin:
data = message["admin"]
if data == "save":
r.publish("admin", "save")
elif data == data.startswith("load:"):
elif data.startswith("load:"):
r.publish("admin", data)
else:
logging.error(f"unsupported admin action: {data}")
@ -82,6 +89,8 @@ async def handler(websocket, path: str):
await parse_message(user, message)
finally:
# Unregister user
if user == USERS.admin:
USERS.admin = None
USERS.unregister(user)

View file

@ -1,5 +1,4 @@
import logging
import os
import time
from dataclasses import dataclass
from typing import Any, Optional
@ -64,25 +63,19 @@ class Users(set):
logging.debug(f"user unregistered: {self}")
class States(set):
"""Save and load states from files."""
async def save(core):
state = core.save_raw_state()
current_time = time.strftime("%Y-%m-%dT%H:%M:%S")
with open(f"states/{current_time}.state", "wb") as state_file:
for byte in state:
state_file.write(byte.to_bytes(4, byteorder="big", signed=False))
logging.debug(f"state saved : {current_time}.state")
def __init__(self) -> None:
"""Construct a `States` object."""
files = os.listdir("states")
states = list(filter(lambda x: x.endswith(".state"), files))
self.update(states)
async def save(self, core):
state = core.save_raw_state()
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))
self.add(state)
async def load(self, core, filename):
state = ffi.new("unsigned char[397312]") # pulled 397312 from my ass
with open(f"states/{filename}.state", "rb") as state_file:
for i in range(len(state)):
state[i] = int.from_bytes(state_file.read(4), byteorder="big", signed=False)
core.load_raw_state(state)
async def load(core, filename):
state = ffi.new("unsigned char[397312]") # pulled 397312 from my ass
with open(f"states/{filename}.state", "rb") as state_file:
for i in range(len(state)):
state[i] = int.from_bytes(state_file.read(4), byteorder="big", signed=False)
core.load_raw_state(state)
logging.debug(f"state loaded : {filename}")