From 497419a4415d1bbb035dba94f2721d92d8b201ba Mon Sep 17 00:00:00 2001 From: Conatum Date: Fri, 7 Jul 2023 18:26:43 +0300 Subject: [PATCH] fix (voice): Fix data preconditions. Fixes issue where voice session would start without member data. Fixes issue where voice session would start without channel data. Fixes issue on init where sessions would start without keys. Fixes issue on guild join where sessions would start without keys. Fixes issue in schedule where data cache key was built incorrectly. --- src/modules/schedule/data.py | 10 +++++----- src/tracking/voice/cog.py | 33 ++++++++++++++++++++++++++++++++- src/tracking/voice/data.py | 33 +++++++++++++++++++++++++++++++++ src/tracking/voice/session.py | 12 +++++++----- 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/modules/schedule/data.py b/src/modules/schedule/data.py index 1e007fe9..b6248aa8 100644 --- a/src/modules/schedule/data.py +++ b/src/modules/schedule/data.py @@ -22,8 +22,8 @@ class ScheduleData(Registry): results = {} to_fetch = set() for slotid in slotids: - row = cls._cache_.get(slotid, None) - if row is None: + row = cls._cache_.get((slotid,), None) + if row is None or row.data is None: to_fetch.add(slotid) else: results[slotid] = row @@ -82,7 +82,7 @@ class ScheduleData(Registry): to_fetch = set() for key in keys: row = cls._cache_.get(key, None) - if row is None: + if row is None or row.data is None: to_fetch.add(key) else: results[key] = row @@ -129,8 +129,8 @@ class ScheduleData(Registry): results = {} to_fetch = set() for guildid in guildids: - row = cls._cache_.get(guildid, None) - if row is None: + row = cls._cache_.get((guildid,), None) + if row is None or row.data is None: to_fetch.add(guildid) else: results[guildid] = row diff --git a/src/tracking/voice/cog.py b/src/tracking/voice/cog.py index 30040648..c075029f 100644 --- a/src/tracking/voice/cog.py +++ b/src/tracking/voice/cog.py @@ -247,6 +247,16 @@ class VoiceTrackerCog(LionCog): )) # Bulk create the ongoing sessions if to_create: + # First ensure the lion members exist + await self.bot.core.lions.fetch_members( + *(item[:2] for item in to_create) + ) + + # Then ensure the TrackedChannels exist + cids = set((item[2], item[0]) for item in to_create) + await self.data.TrackedChannel.fetch_multiple(*cids) + + # Then actually create the ongoing sessions rows = await self.data.VoiceSessionsOngoing.table.insert_many( ('guildid', 'userid', 'channelid', 'start_time', 'last_update', 'live_stream', 'live_video', 'hourly_coins'), @@ -415,6 +425,16 @@ class VoiceTrackerCog(LionCog): )) if to_create: + # Ensure LionMembers exist + await self.bot.core.lions.fetch_members( + *(item[:2] for item in to_create) + ) + + # Ensure TrackedChannels exist + cids = set((item[2], item[0]) for item in to_create) + await self.data.TrackedChannel.fetch_multiple(*cids) + + # Create new sessions rows = await self.data.VoiceSessionsOngoing.table.insert_many( ('guildid', 'userid', 'channelid', 'start_time', 'last_update', 'live_stream', 'live_video', 'hourly_coins'), @@ -567,6 +587,16 @@ class VoiceTrackerCog(LionCog): )) if to_create: + # Ensure LionMembers exist + await self.bot.core.lions.fetch_members( + *(item[:2] for item in to_create) + ) + + # Ensure TrackedChannels exist + cids = set((item[2], item[0]) for item in to_create) + await self.data.TrackedChannel.fetch_multiple(*cids) + + # Create new sessions rows = await self.data.VoiceSessionsOngoing.table.insert_many( ('guildid', 'userid', 'channelid', 'start_time', 'last_update', 'live_stream', 'live_video', 'hourly_coins'), @@ -599,7 +629,8 @@ class VoiceTrackerCog(LionCog): if session.expiry_task is not None: session.expiry_task.cancel() to_close.append(session.guildid, session.userid, now) - await self.data.VoiceSessionsOngoing.close_voice_sessions_at(*to_close) + if to_close: + await self.data.VoiceSessionsOngoing.close_voice_sessions_at(*to_close) logger.info( f"Closed {len(to_close)} voice sessions after leaving guild '{guild.name}' " ) diff --git a/src/tracking/voice/data.py b/src/tracking/voice/data.py index a8576eac..164c7137 100644 --- a/src/tracking/voice/data.py +++ b/src/tracking/voice/data.py @@ -37,6 +37,39 @@ class VoiceTrackerData(Registry): deleted = Bool() _timestamp = Timestamp() + @classmethod + async def fetch_multiple(cls, *keys, create=True): + """ + Fetch and optionally create multiple row, applying cache where possible. + + Provided keys should be in the form (channelid, guildid) + Results will be provided as a map channelid -> Row + """ + cidmap = {cid: gid for cid, gid in keys} + + results = {} + to_fetch = set() + for cid in cidmap: + row = cls._cache_.get((cid,), None) + if row is None or row.data is None: + to_fetch.add(cid) + else: + results[cid] = row + + if to_fetch: + rows = await cls.fetch_where(channelid=list(cidmap.keys())) + for row in rows: + results[row.channelid] = row + to_fetch.remove(row.channelid) + if to_fetch and create: + rows = await cls.table.insert_many( + ('channelid', 'guildid', 'deleted'), + *((cid, cidmap[cid], False) for cid in to_fetch) + ).with_adapter(cls._make_rows) + for row in rows: + results[row.channelid] = row + return results + class VoiceSessionsOngoing(RowModel): """ Model describing currently active voice sessions. diff --git a/src/tracking/voice/session.py b/src/tracking/voice/session.py index 160dafb6..cf662caa 100644 --- a/src/tracking/voice/session.py +++ b/src/tracking/voice/session.py @@ -153,14 +153,16 @@ class VoiceSession: f"Starting voice session for member in guild " f"and channel ." ) + # Create the lion if required + await self.bot.core.lions.fetch_member(self.guildid, self.userid) + + # Create the tracked channel if required + await self.registry.TrackedChannel.fetch_or_create( + self.state.channelid, guildid=self.guildid, deleted=False + ) conn = await self.bot.db.get_connection() async with conn.transaction(): - # Create the tracked channel if required - await self.registry.TrackedChannel.fetch_or_create( - self.state.channelid, guildid=self.guildid, deleted=False - ) - # Insert an ongoing_session with the correct state, set data state = self.state self.data = await self.registry.VoiceSessionsOngoing.create(