From c12c6776b1085e2ab0707f1e28297c36c75f1e87 Mon Sep 17 00:00:00 2001
From: Christoph Stahl <christoph.stahl@uni-dortmund.de>
Date: Thu, 26 Jan 2023 10:57:57 +0100
Subject: [PATCH] clients is no longer a global variable

---
 syng/server.py | 78 ++++++++++++++++++++++++++++----------------------
 1 file changed, 43 insertions(+), 35 deletions(-)

diff --git a/syng/server.py b/syng/server.py
index 1b56b96..111e05f 100644
--- a/syng/server.py
+++ b/syng/server.py
@@ -74,7 +74,7 @@ class Config:
     :type sources: Source
     :param sources_prio: A list defining the order of the search results.
     :type sources_prio: list[str]
-    :param preview_duration: The duration in seconds the playbackclients shows
+    :param preview_duration: The duration in seconds the playback clients shows
         a preview for the next song. This is accounted for in the calculation
         of the ETA for songs later in the queue.
     :type preview_duration: int
@@ -119,9 +119,6 @@ class State:
     )
 
 
-clients: dict[str, State] = {}
-
-
 async def send_state(state: State, sid: str) -> None:
     """
     Send the current state (queue and recent-list) to sid.
@@ -160,7 +157,7 @@ async def handle_state(sid: str) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     await send_state(state, sid)
 
@@ -198,7 +195,7 @@ async def handle_append(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     source_obj = state.config.sources[data["source"]]
     entry = await source_obj.get_entry(data["performer"], data["ident"])
@@ -239,7 +236,7 @@ async def handle_append(sid: str, data: dict[str, Any]) -> None:
     await sio.emit(
         "get-meta-info",
         entry,
-        room=clients[room].sid,
+        room=app["clients"][room].sid,
     )
 
 
@@ -263,7 +260,7 @@ async def handle_meta_info(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     state.queue.update(
         data["uuid"],
@@ -294,7 +291,7 @@ async def handle_get_first(sid: str) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     current = await state.queue.peek()
     current.started_at = datetime.datetime.now().timestamp()
@@ -323,7 +320,7 @@ async def handle_pop_then_get_next(sid: str) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if sid != state.sid:
         return
@@ -386,7 +383,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
         client_id = "".join(
             [random.choice(string.ascii_letters) for _ in range(length)]
         )
-        if client_id in clients:
+        if client_id in app["clients"]:
             client_id = gen_id(length + 1)
         return client_id
 
@@ -394,8 +391,8 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
     async with sio.session(sid) as session:
         session["room"] = room
 
-    if room in clients:
-        old_state: State = clients[room]
+    if room in app["clients"]:
+        old_state: State = app["clients"][room]
         if data["secret"] == old_state.secret:
             logger.info("Got new client connection for %s", room)
             old_state.sid = sid
@@ -408,7 +405,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
             await sio.emit(
                 "client-registered", {"success": True, "room": room}, room=sid
             )
-            await send_state(clients[room], sid)
+            await send_state(app["clients"][room], sid)
         else:
             logger.warning("Got wrong secret for %s", room)
             await sio.emit(
@@ -419,7 +416,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
         initial_entries = [Entry(**entry) for entry in data["queue"]]
         initial_recent = [Entry(**entry) for entry in data["recent"]]
 
-        clients[room] = State(
+        app["clients"][room] = State(
             secret=data["secret"],
             queue=Queue(initial_entries),
             recent=initial_recent,
@@ -430,7 +427,7 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
         await sio.emit(
             "client-registered", {"success": True, "room": room}, room=sid
         )
-        await send_state(clients[room], sid)
+        await send_state(app["clients"][room], sid)
 
 
 @sio.on("sources")
@@ -457,7 +454,7 @@ async def handle_sources(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if sid != state.sid:
         return
@@ -494,7 +491,7 @@ async def handle_config_chunk(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if sid != state.sid:
         return
@@ -526,7 +523,7 @@ async def handle_config(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if sid != state.sid:
         return
@@ -551,11 +548,11 @@ async def handle_register_web(sid: str, data: dict[str, Any]) -> bool:
     :returns: True, if the room exist, False otherwise
     :rtype: bool
     """
-    if data["room"] in clients:
+    if data["room"] in app["clients"]:
         async with sio.session(sid) as session:
             session["room"] = data["room"]
             sio.enter_room(sid, session["room"])
-        state = clients[session["room"]]
+        state = app["clients"][session["room"]]
         await send_state(state, sid)
         return True
     return False
@@ -578,7 +575,7 @@ async def handle_register_admin(sid: str, data: dict[str, Any]) -> bool:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     is_admin: bool = data["secret"] == state.secret
     async with sio.session(sid) as session:
@@ -602,12 +599,14 @@ async def handle_skip_current(sid: str) -> None:
     async with sio.session(sid) as session:
         room = session["room"]
         is_admin = session["admin"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if is_admin:
         old_entry = await state.queue.popleft()
         state.recent.append(old_entry)
-        await sio.emit("skip-current", old_entry, room=clients[room].sid)
+        await sio.emit(
+            "skip-current", old_entry, room=app["clients"][room].sid
+        )
         await send_state(state, room)
 
 
@@ -628,7 +627,7 @@ async def handle_move_up(sid: str, data: dict[str, Any]) -> None:
     async with sio.session(sid) as session:
         room = session["room"]
         is_admin = session["admin"]
-    state = clients[room]
+    state = app["clients"][room]
     if is_admin:
         await state.queue.move_up(data["uuid"])
         await send_state(state, room)
@@ -651,7 +650,7 @@ async def handle_skip(sid: str, data: dict[str, Any]) -> None:
     async with sio.session(sid) as session:
         room = session["room"]
         is_admin = session["admin"]
-    state = clients[room]
+    state = app["clients"][room]
 
     if is_admin:
         entry = state.queue.find_by_uuid(data["uuid"])
@@ -699,7 +698,7 @@ async def handle_search(sid: str, data: dict[str, Any]) -> None:
     """
     async with sio.session(sid) as session:
         room = session["room"]
-    state = clients[room]
+    state = app["clients"][room]
 
     query = data["query"]
     results_list = await asyncio.gather(
@@ -722,24 +721,26 @@ async def handle_search(sid: str, data: dict[str, Any]) -> None:
 
 
 async def cleanup() -> None:
-    """ Clean up the unused playback clients
+    """Clean up the unused playback clients
 
     This runs every hour, and removes every client, that did not requested a song for four hours
     """
 
     logger.info("Start Cleanup")
     to_remove: list[str] = []
-    for sid, state in clients.items():
+    for sid, state in app["clients"].items():
         logger.info("Client %s, last seen: %s", sid, str(state.last_seen))
-        if state.last_seen + datetime.timedelta(hours=4) < datetime.datetime.now():
+        if (
+            state.last_seen + datetime.timedelta(hours=4)
+            < datetime.datetime.now()
+        ):
             logger.info("No activity for 4 hours, removing %s", sid)
             to_remove.append(sid)
     for sid in to_remove:
         await sio.disconnect(sid)
-        del clients[sid]
+        del app["clients"][sid]
     logger.info("End Cleanup")
 
-
     # The internal loop counter does not use a regular timestamp, so we need to convert between
     # regular datetime and the async loop time
     now = datetime.datetime.now()
@@ -751,10 +752,15 @@ async def cleanup() -> None:
     loop_next = asyncio.get_event_loop().time() + offset
 
     logger.info("Next Cleanup at %s", str(next))
-    asyncio.get_event_loop().call_at(loop_next, lambda: asyncio.create_task(cleanup()))
+    asyncio.get_event_loop().call_at(
+        loop_next, lambda: asyncio.create_task(cleanup())
+    )
 
-async def background_tasks(iapp: web.Application) -> AsyncGenerator[None, None]:
-    """ Create all the background tasks
+
+async def background_tasks(
+    iapp: web.Application,
+) -> AsyncGenerator[None, None]:
+    """Create all the background tasks
 
     For now, this is only the cleanup task
     """
@@ -766,6 +772,7 @@ async def background_tasks(iapp: web.Application) -> AsyncGenerator[None, None]:
     iapp["repeated_cleanup"].cancel()
     await iapp["repeated_cleanup"]
 
+
 def main() -> None:
     """
     Configure and start the server.
@@ -785,6 +792,7 @@ def main() -> None:
     app.router.add_route("*", "/{room}", root_handler)
     app.router.add_route("*", "/{room}/", root_handler)
 
+    app["clients"] = {}
     app.cleanup_ctx.append(background_tasks)
 
     web.run_app(app, host=args.host, port=args.port)
-- 
GitLab