diff --git a/v6d3vote/run-bot.py b/v6d3vote/run-bot.py index 9525d91..348ff50 100644 --- a/v6d3vote/run-bot.py +++ b/v6d3vote/run-bot.py @@ -62,6 +62,8 @@ class SavedPoll(TypedDict): class Poll: + tasks: dict[int, asyncio.Future[None]] = {} + def __init__( self, message: discord.Message, @@ -154,6 +156,29 @@ class Poll: saved.get('title', 'unnamed') ) + @classmethod + async def _scheduled_save(cls, message: discord.Message, /) -> None: + async with lock_for(message, 'no message'): + del cls.tasks[message.id] + print('saving') + poll = await cls.load(message) + if poll is None: + return + await vote_db.commit() + await poll.message.edit( + content=poll.content() + ) + print('saved') + + def schedule_save(self) -> asyncio.Future[None]: + vote_db.set_nowait( + self.message.id, + self.saved() + ) + if self.message.id not in self.tasks: + self.tasks[self.message.id] = asyncio.create_task(self._scheduled_save(self.message)) + return self.tasks[self.message.id] + @classmethod async def global_vote(cls, rrae: discord.RawReactionActionEvent): assert client.user is not None @@ -162,19 +187,24 @@ class Poll: assert rrae.guild_id is not None assert rrae.channel_id is not None guild: discord.Guild = client.get_guild(rrae.guild_id) or await client.fetch_guild(rrae.guild_id) - member: discord.Member = guild.get_member(rrae.user_id) or await guild.fetch_member(rrae.user_id) _channel = guild.get_channel(rrae.channel_id) assert isinstance(_channel, discord.TextChannel) channel: discord.TextChannel = _channel - message: discord.Message = await channel.fetch_message(rrae.message_id) + print('process? ', rrae.emoji, rrae.event_type) + async with lock_for(rrae.message_id, 'no message id'): + message: discord.Message = await channel.fetch_message(rrae.message_id) if message.author != client.user: return async with lock_for(message, 'no message'): poll = await cls.load(message) if poll is None: return + member: discord.Member = guild.get_member(rrae.user_id) or await guild.fetch_member(rrae.user_id) + print('processing', rrae.emoji, rrae.event_type) await poll.vote(member, rrae.emoji, rrae.event_type == 'REACTION_REMOVE') - await poll.save() + print('processed ', rrae.emoji, rrae.event_type) + future = poll.schedule_save() + await future async def vote(self, member: discord.Member, emoji: discord.PartialEmoji | str, remove: bool): if str(emoji) in self.reverse: @@ -255,9 +285,9 @@ if __name__ == '__main__': ALog(Db, '__aenter__').enter(es) ALog(Db, '__aexit__').enter(es) ALog(Db, 'aclose').enter(es) - SLog(Db, '_build_file_sync').enter(es) - SLog(Db, '_finish_recovery_sync').enter(es) - SLog(Db, '_copy_sync').enter(es) - ALog(loop, 'run_in_executor').enter(es) + # SLog(Db, '_build_file_sync').enter(es) + # SLog(Db, '_finish_recovery_sync').enter(es) + # SLog(Db, '_copy_sync').enter(es) + # ALog(loop, 'run_in_executor').enter(es) serve(main(), client, loop) print('after serve')