wip(sync): clean stale username from redis

We wanted to use the HEXPIRE command, but discovered that this command
is only available since the Redis 7.4 version (the latest), and this version
does not have an OSI compliant licence, so it is generally not installable
through common packages managers. The OSS fork is Valkey, but it still does
not have the HEXPIRE command.

So we decide to clean those keys manually, and in order no do this clean
task at each websocket connection, we only do it when we are the first user
to connect to a given map.

Co-authored-by: David Larlet <david@larlet.fr>
This commit is contained in:
Yohan Boniface 2025-01-23 17:05:13 +01:00
parent 0d5e3047f4
commit 476c160fd5

View file

@ -69,12 +69,20 @@ class Peer:
async def get_peers(self): async def get_peers(self):
known = await self.client.hgetall(self.room_key) known = await self.client.hgetall(self.room_key)
active = await self.client.pubsub_channels(f"user:{self.map_id}:*") active = await self.client.pubsub_channels(f"user:{self.map_id}:*")
if not active:
# Poor man way of deleting stale usernames from the store
# HEXPIRE command is not in the open source Redis version
await self.client.delete(self.room_key)
await self.store_username()
active = [name.split(b":")[-1] for name in active] active = [name.split(b":")[-1] for name in active]
if self.peer_id.encode() not in active: if self.peer_id.encode() not in active:
# Our connection may not yet be active # Our connection may not yet be active
active.append(self.peer_id.encode()) active.append(self.peer_id.encode())
return {k: v for k, v in known.items() if k in active} return {k: v for k, v in known.items() if k in active}
async def store_username(self):
await self.client.hset(self.room_key, self.peer_id, self.username)
async def listen_to_channel(self, channel_name): async def listen_to_channel(self, channel_name):
async def reader(pubsub): async def reader(pubsub):
await pubsub.subscribe(channel_name) await pubsub.subscribe(channel_name)
@ -136,7 +144,7 @@ class Peer:
self.peer_id = message.peer self.peer_id = message.peer
self.username = message.username self.username = message.username
print("AUTHENTICATED", self.peer_id) print("AUTHENTICATED", self.peer_id)
await self.client.hset(self.room_key, self.peer_id, self.username) await self.store_username()
await self.listen() await self.listen()
response = JoinResponse(peer=self.peer_id, peers=await self.get_peers()) response = JoinResponse(peer=self.peer_id, peers=await self.get_peers())
await self.send(response.model_dump_json()) await self.send(response.model_dump_json())