Allow client and server to import and export the

queue/waitingroom/recent
This commit is contained in:
Christoph Stahl 2025-06-17 00:13:25 +02:00
parent 831985e597
commit d2bca61ebd
4 changed files with 90 additions and 1 deletions

View file

@ -45,6 +45,7 @@ from . import SYNG_VERSION, jsonencoder
from .entry import Entry
from .sources import configure_sources, Source
from .log import logger
from . import jsonencoder
class ConnectionState:
@ -617,6 +618,43 @@ class Client:
logger.info("Removing room %s from server", self.state.config["room"])
await self.sio.emit("remove-room", {"room": self.state.config["room"]})
def export_queue(self, filename: str) -> None:
"""
Export the current queue to a file.
:param filename: The name of the file to export the queue to.
:type filename: str
:rtype: None
"""
with open(filename, "w", encoding="utf8") as file:
jsonencoder.dump(
{
"queue": self.state.queue,
"waiting_room": self.state.waiting_room,
"recent": self.state.recent,
},
file,
indent=2,
ensure_ascii=False,
)
async def import_queue(self, filename: str) -> None:
"""
Import a queue from a file.
:param filename: The name of the file to import the queue from.
:type filename: str
:rtype: None
"""
with open(filename, "r", encoding="utf8") as file:
data = jsonencoder.load(file)
queue = [Entry(**entry) for entry in data["queue"]]
waiting_room = [Entry(**entry) for entry in data["waiting_room"]]
recent = [Entry(**entry) for entry in data["recent"]]
await self.sio.emit(
"import-queue", {"queue": queue, "waiting_room": waiting_room, "recent": recent}
)
async def handle_room_removed(self, data: dict[str, Any]) -> None:
"""
Handle the "room-removed" message.

View file

@ -34,10 +34,20 @@ class SyngEncoder(json.JSONEncoder):
def dumps(obj: Any, **kw: Any) -> str:
"""Wrap around ``json.dump`` with the :py:class:`SyngEncoder`."""
"""Wrap around ``json.dumps`` with the :py:class:`SyngEncoder`."""
return json.dumps(obj, cls=SyngEncoder, **kw)
def dump(obj: Any, fp: Any, **kw: Any) -> None:
"""Forward everything to ``json.dump``."""
json.dump(obj, fp, cls=SyngEncoder, **kw)
def loads(string: str, **kw: Any) -> Any:
"""Forward everything to ``json.loads``."""
return json.loads(string, **kw)
def load(fp: Any, **kw: Any) -> Any:
"""Forward everything to ``json.load``."""
return json.load(fp, **kw)

View file

@ -31,6 +31,17 @@ class Queue:
self.num_of_entries_sem = asyncio.Semaphore(len(self._queue))
self.readlock = asyncio.Lock()
def extend(self, entries: Iterable[Entry]) -> None:
"""
Extend the queue with a list of entries and increase the semaphore.
:param entries: The entries to add
:type entries: Iterable[Entry]
:rtype: None
"""
for entry in entries:
self.append(entry)
def append(self, entry: Entry) -> None:
"""
Append an entry to the queue, increase the semaphore.

View file

@ -230,6 +230,7 @@ class Server:
self.sio.on("connect", self.handle_connect)
self.sio.on("search", self.handle_search)
self.sio.on("search-results", self.handle_search_results)
self.sio.on("import-queue", self.handle_import_queue)
async def is_admin(self, state: State, sid: str) -> bool:
"""
@ -963,6 +964,35 @@ class Server:
)
return True
@admin
@with_state
async def handle_import_queue(self, state: State, sid: str, data: dict[str, Any]) -> None:
"""
Handle the "import-queue" message.
This will add entries to the queue and waiting room from the client.
The data dictionary should have the following keys:
- `queue`, a list of entries to import into the queue
- `waiting_room`, a list of entries to import into the waiting room
:param sid: The session id of the client sending this request
:type sid: str
:param data: A dictionary with the keys described above
:type data: dict[str, Any]
:rtype: None
"""
queue_entries = [Entry(**entry) for entry in data.get("queue", [])]
waiting_room_entries = [Entry(**entry) for entry in data.get("waiting_room", [])]
recent_entries = [Entry(**entry) for entry in data.get("recent", [])]
state.queue.extend(queue_entries)
state.waiting_room.extend(waiting_room_entries)
state.recent.extend(recent_entries)
await self.broadcast_state(state, sid=sid)
@admin
@with_state
async def handle_remove_room(self, state: State, sid: str, data: dict[str, Any]) -> None: