fix: Add lock to prevent update race.

This commit is contained in:
2025-11-01 11:49:27 +10:00
parent a14cc4056e
commit 1bd2e9607a

View File

@@ -1,3 +1,4 @@
import asyncio
from string import punctuation
import datetime as dt
from datetime import datetime, timedelta
@@ -40,6 +41,7 @@ class FocusComponent(cmds.Component):
register_channel(self.channel.name, self.channel)
self._last_deleted: dict[int, datetime] = {}
self.hyperfocus_lock = asyncio.Lock()
# ----- API -----
async def component_load(self):
@@ -88,6 +90,10 @@ class FocusComponent(cmds.Component):
@cmds.Component.listener()
async def event_message(self, payload: twitchio.ChatMessage):
async with self.hyperfocus_lock:
await self.handle_message(payload)
async def handle_message(self, payload: twitchio.ChatMessage):
# Check if chatter is currently hyperfocused
profile = await self.bot.profiles.fetch_profile(payload.chatter, touch=True)
hyperfocused = await self.get_hyperfocus(profile.profileid)
@@ -173,35 +179,37 @@ class FocusComponent(cmds.Component):
pid = profile.profileid
comm = await self.bot.profiles.fetch_community(ctx.broadcaster, touch=True)
await Hyperfocuser.table.delete_where(profileid=pid)
focuser = await Hyperfocuser.create(
profileid=pid,
started_at=now,
ends_at=end_at,
started_in=comm.communityid,
)
async with self.hyperfocus_lock:
await Hyperfocuser.table.delete_where(profileid=pid)
focuser = await Hyperfocuser.create(
profileid=pid,
started_at=now,
ends_at=end_at,
started_in=comm.communityid,
)
await self.channel.send_hyperfocus_patch(comm.communityid, focuser)
await self.channel.send_hyperfocus_patch(comm.communityid, focuser)
minutes = ceil(dur / 60)
await ctx.reply(
f"{ctx.chatter.name} has gone into HYPERFOCUS! "
f"They will be in emote and command only mode for the next {minutes} minutes! "
"Use !unfocus to come back if you need to, best of luck! ☘️🍀☘️ "
)
minutes = ceil(dur / 60)
await ctx.reply(
f"{ctx.chatter.name} has gone into HYPERFOCUS! "
f"They will be in emote and command only mode for the next {minutes} minutes! "
"Use !unfocus to come back if you need to, best of luck! ☘️🍀☘️ "
)
@cmds.command(name="unfocus")
async def unfocus_cmd(self, ctx):
profile = await self.bot.profiles.fetch_profile(ctx.chatter, touch=True)
row = await Hyperfocuser.fetch(profile.profileid)
if row:
await row.delete()
await self.channel.send_hyperfocus_del(profile.profileid)
async with self.hyperfocus_lock:
row = await Hyperfocuser.fetch(profile.profileid)
if row:
await row.delete()
await self.channel.send_hyperfocus_del(profile.profileid)
await ctx.reply(
"Welcome back from focus, hope it went well!"
" Remember to have a sip and stretch if you need it~"
)
await ctx.reply(
"Welcome back from focus, hope it went well!"
" Remember to have a sip and stretch if you need it~"
)
@cmds.command(name="hyperfocused")
async def hyperfocused_cmd(self, ctx, user: twitchio.User | None = None):
@@ -209,22 +217,30 @@ class FocusComponent(cmds.Component):
profile = await self.bot.profiles.fetch_profile(user, touch=False)
if hyper := (await self.get_hyperfocus(profile.profileid)):
durstr = strfdelta(hyper.ends_at - utc_now())
await ctx.reply(
f"{user.name} is in HYPERFOCUS for another {durstr}! "
"They can only write emojis and commands in this time. Good luck!"
)
elif own:
await ctx.reply(
"You are not hyperfocused!"
" Enter HYPERFOCUS mode for e.g. 10 minutes with '!hyperfocus 10'"
)
else:
await ctx.reply(f"{user.name} is not hyperfocused!")
async with self.hyperfocus_lock:
if hyper := (await self.get_hyperfocus(profile.profileid)):
durstr = strfdelta(hyper.ends_at - utc_now())
await ctx.reply(
f"{user.name} is in HYPERFOCUS for another {durstr}! "
"They can only write emojis and commands in this time. Good luck!"
)
elif own:
await ctx.reply(
"You are not hyperfocused!"
" Enter HYPERFOCUS mode for e.g. 10 minutes with '!hyperfocus 10'"
)
else:
await ctx.reply(f"{user.name} is not hyperfocused!")
@cmds.command(name="addfocus")
async def addfocus_cmd(self, ctx):
await ctx.reply(
"Add HYPERFOCUS to your channel by authorising me here: https://croccyfocus.thewisewolf.dev/invite"
)
@cmds.command(name="focuslist")
@cmds.is_moderator()
async def focuslist_cmd(self, ctx):
comm = await self.bot.profiles.fetch_community(ctx.broadcaster, touch=True)
link = f"https://croccyfocus.thewisewolf.dev/widget/?community={comm}"
await ctx.reply(f"Browser source link for your channel's hyperfocus: {link}")