Files
romm/backend/handler/netplay_handler.py
T
Sam DornanandClaude Opus 5.5 6b13fd1698 chore(deps): bump redis to 8.1 and fakeredis to 2.38, drop types-redis (#4844)
* chore(deps): bump redis to 8.1 and fakeredis to 2.38

redis-py 6.2.0 -> 8.1.0 and fakeredis 2.30.1 -> 2.38.0. RQ 2.12
(redis!=6,>=3.5) and fakeredis (redis>=4.3) both accept redis 8.

fakeredis 2.38 types FakeServer's version argument as a tuple, so pass
(7,) instead of 7. Behaviour is unchanged since fakeredis normalises an
int to a one-element tuple.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

* chore(deps): drop types-redis in favour of redis-py's own types

types-redis only covers redis 4.6 and shadowed the inline types that
redis 8 ships, so mypy was checking calls against a stale API. Removing
it also drops its transitive stub packages (types-cffi, types-pyopenssl,
types-setuptools), which nothing else uses.

redis-py's types differ from the stubs in three ways:
- Redis, AsyncRedis and Pipeline are not generic, so drop the [str] and
  [bytes] parameters.
- Responses are typed bytes | str regardless of decode_responses, so cast
  at the few call sites that rely on the decoded (or raw) type.
- watch, unwatch, multi, aclose and execute_command are unannotated, so
  add redis to untyped_calls_exclude, as is done for rq and apprise.

Also replace setex, deprecated in redis 8, with set(..., ex=...).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

* fix(device-auth): replace deprecated GETSET with SET ... GET

code-review step. GETSET is deprecated since Redis 6.2 in favour of
SET with GET. Using it with ex= also sets the poll key's TTL in the same
command, instead of a separate EXPIRE that a crash could skip.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014wzuPg8vDEjsQ8xqvZgFwx

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-27 13:28:09 -05:00

51 lines
1.4 KiB
Python

import json
from typing import Optional, TypedDict, cast
from handler.redis_handler import async_cache
class NetplayPlayerInfo(TypedDict):
socketId: str
player_name: str
userid: str | None
playerId: str | None
class NetplayRoom(TypedDict):
owner: str
players: dict[str, NetplayPlayerInfo]
peers: list[str]
room_name: str
game_id: str
domain: Optional[str]
password: Optional[str]
max_players: int
class NetplayHandler:
"""A class to handle netplay rooms in Redis."""
def __init__(self) -> None:
self.hash_name = "netplay:rooms"
async def get(self, room_id: str) -> NetplayRoom | None:
"""Get a room from Redis."""
room = await async_cache.hget(self.hash_name, room_id)
return json.loads(room) if room else None
async def set(self, room_id: str, room_data: NetplayRoom) -> int:
"""Set a room in Redis."""
return await async_cache.hset(self.hash_name, room_id, json.dumps(room_data))
async def delete(self, room_ids: list[str]) -> int:
"""Delete a room from Redis."""
return await async_cache.hdel(self.hash_name, *room_ids)
async def get_all(self) -> dict[str, NetplayRoom]:
"""Get all rooms from Redis."""
rooms = cast(dict[str, str], await async_cache.hgetall(self.hash_name))
return {room_id: json.loads(room_data) for room_id, room_data in rooms.items()}
netplay_handler = NetplayHandler()