From 73abc7a981e058a19327c1a7e8c62a465462beb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laure=CE=B7t?= Date: Sun, 14 Nov 2021 22:07:47 +0100 Subject: [PATCH] feat: now possible to load and save data through redis "messages" --- src/emulator.py | 17 ++++++++++------- src/server.py | 1 - src/settings.py | 2 +- src/utils.py | 42 +++++++++++++++++++++++------------------- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/emulator.py b/src/emulator.py index 54e347c..67e7d14 100644 --- a/src/emulator.py +++ b/src/emulator.py @@ -27,6 +27,7 @@ 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) @@ -37,6 +38,8 @@ 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. @@ -94,12 +97,13 @@ def state_manager(loop): ps.subscribe("admin") while True: for message in ps.listen(): - print(message) - asyncio.ensure_future(save(), loop=loop) - - -async def save(): - print("saving") + logging.debug(message) + if message["type"] == "message": + data = message["data"].decode("utf-8") + if data == "save": + asyncio.ensure_future(states.save(core), loop=loop) + elif data.startswith("load:"): + asyncio.ensure_future(states.load(core, data.removeprefix("load:")), loop=loop) async def emulator(): @@ -129,7 +133,6 @@ async def main(loop): task_emulator = loop.create_task(emulator()) await task_emulator - thread.join() if __name__ == "__main__": diff --git a/src/server.py b/src/server.py index ea943c5..99f21a4 100644 --- a/src/server.py +++ b/src/server.py @@ -61,7 +61,6 @@ async def parse_message(user: User, message: dict[str, str]) -> None: elif data in KEYS_ID: r.incr(data) user.last_message = time.time() - user.has_voted = True else: logging.error(f"unsupported action: {data}") diff --git a/src/settings.py b/src/settings.py index ceabd41..1ffd051 100644 --- a/src/settings.py +++ b/src/settings.py @@ -30,7 +30,7 @@ FFMPEG_BITRATE: str = getenv("FFMPEG_BIRATE", "2M") PASSWORD_ADMIN: str = getenv("PASSWORD_ADMIN", "password_admin") -USER_TIMEOUT: float = 0.5 +USER_TIMEOUT: float = float(getenv("USER_TIMEOUT", 0.5)) KEYMAP: dict[str, int] = { "a": 0, diff --git a/src/utils.py b/src/utils.py index 79910b7..04b99df 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,15 +1,17 @@ import logging +import os import time from dataclasses import dataclass from typing import Any, Optional +from mgba._pylib import ffi + class User: """Store infos related to a connected user.""" websocket: Any last_message: float - has_voted: bool def __init__(self, websocket: Any) -> None: """Construct a User object. @@ -19,7 +21,6 @@ class User: """ self.websocket = websocket self.last_message = time.time() - self.has_voted = False async def send(self, data: str): """Send data through the user's websocket. @@ -42,7 +43,6 @@ class User: class Users(set): """Store `User`s connected to the server.""" - emulator: Optional[User] = None admin: Optional[User] = None def register(self, user: User): @@ -63,22 +63,26 @@ class Users(set): self.remove(user) logging.debug(f"user unregistered: {self}") - def clear(self) -> None: - """Clear the `has_voted` of each user in the set.""" - for user in self: - user.has_voted = False +class States(set): + """Save and load states from files.""" -# class States(set): -# 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)) + def __init__(self) -> None: + """Construct a `States` object.""" + files = os.listdir("states") + states = list(filter(lambda x: x.endswith(".state"), files)) + self.update(states) -# def load(self, core, state): -# state = ffi.new("unsigned char[397312]") -# with open("states/test.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 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)