Compare commits

..

5 Commits

Author SHA1 Message Date
67382a0c0a 在我写的模块采用更安全的 asyncio 锁写法
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2025-10-19 20:27:18 +08:00
fd4c9302c2 async with lock
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-19 20:24:47 +08:00
f30ad0cb7d 判定部分优化
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-19 18:48:10 +08:00
f7afe48680 精度修复
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-19 18:36:27 +08:00
b42385f780 修复成语接龙
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2025-10-19 18:24:03 +08:00
3 changed files with 62 additions and 53 deletions

View File

@ -254,11 +254,10 @@ def _save_longtask_data(data: LongTaskModuleData):
@asynccontextmanager
async def longtask_data():
await longtask_lock.acquire()
data = _load_longtask_data()
yield data
_save_longtask_data(data)
longtask_lock.release()
async with longtask_lock:
data = _load_longtask_data()
yield data
_save_longtask_data(data)
async def create_longtask(

View File

@ -1,22 +1,18 @@
import asyncio as asynkio
import base64
from pathlib import Path
import secrets
import json
import datetime
from typing import Literal, Optional
import json
import secrets
from enum import Enum
from pathlib import Path
from typing import Optional
from loguru import logger
from nonebot import on_message
from nonebot.adapters import Event as BaseEvent
from nonebot.adapters.console.event import MessageEvent as ConsoleMessageEvent
from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent
from nonebot_plugin_alconna import (
Alconna,
Args,
Field,
Subcommand,
UniMessage,
UniMsg,
on_alconna,
@ -161,24 +157,24 @@ class IdiomGame:
"""
跳过当前成语,选择下一个成语
"""
await self.lock.acquire()
self._skip_idiom_async(buff_score)
self.lock.release()
async with self.lock:
self._skip_idiom_async()
self.add_buff_score(buff_score)
return self.last_idiom
def _skip_idiom_async(self, buff_score: int = -100) -> str:
def _skip_idiom_async(self) -> str:
self.last_idiom = secrets.choice(IdiomGame.ALL_IDIOMS)
self.last_char = self.last_idiom[-1]
self.add_buff_score(buff_score)
if not self.is_nextable(self.last_char):
self._skip_idiom_async()
return self.last_idiom
async def try_verify_idiom(self, idiom: str, user_id: str) -> TryVerifyState:
"""
用户发送成语
"""
await self.lock.acquire()
state = self._verify_idiom(idiom, user_id)
self.lock.release()
async with self.lock:
state = self._verify_idiom(idiom, user_id)
return state
def is_nextable(self, last_char: str) -> bool:
@ -207,10 +203,12 @@ class IdiomGame:
return TryVerifyState.VERIFIED_BUT_NO_NEXT
return TryVerifyState.VERIFIED
def get_user_score(self, user_id: str) -> int:
def get_user_score(self, user_id: str) -> float:
if user_id not in self.score_board:
return 0
return self.score_board[user_id]["score"]
# 避免浮点数精度问题导致过长
handled_score = round(self.score_board[user_id]["score"], 1)
return handled_score
def add_score(self, user_id: str, score: int):
if user_id not in self.score_board:
@ -360,8 +358,10 @@ evt = on_alconna(
@evt.handle()
async def force_play_game(event: BaseEvent, rounds: Optional[int] = 100):
await play_game(event, force=True, rounds=rounds)
async def force_play_game(
event: BaseEvent, target: DepLongTaskTarget, rounds: Optional[int] = 100
):
await play_game(event, target, force=True, rounds=rounds)
async def end_game(event: BaseEvent, group_id: str):
@ -379,7 +379,7 @@ async def end_game(event: BaseEvent, group_id: str):
result_text += (
f"{i + 1}. "
+ UniMessage().at(user_id)
+ f": {info['score'] + instance.get_all_buff_score()}\n"
+ f": {round(info['score'] + instance.get_all_buff_score(), 1)}\n"
)
await evt.send(await result_text.export())
instance.clear_score_board()
@ -518,4 +518,3 @@ async def _(event: BaseEvent, target: DepLongTaskTarget):
group_id = target.channel_id
remove_banned_id(group_id)
await evt.send(await UniMessage().text("本群已开启成语接龙功能!").export())

View File

@ -15,10 +15,10 @@ from nonebot.adapters.console.event import MessageEvent as ConsoleMessageEvent
from nonebot.adapters.discord import Bot as DiscordBot
from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent
from nonebot.adapters.onebot.v11 import Bot as OnebotV11Bot
from nonebot.adapters.onebot.v11.event import \
GroupMessageEvent as OnebotV11GroupMessageEvent
from nonebot.adapters.onebot.v11.event import \
MessageEvent as OnebotV11MessageEvent
from nonebot.adapters.onebot.v11.event import (
GroupMessageEvent as OnebotV11GroupMessageEvent,
)
from nonebot.adapters.onebot.v11.event import MessageEvent as OnebotV11MessageEvent
from nonebot_plugin_alconna import UniMessage, UniMsg
from pydantic import BaseModel
@ -68,14 +68,14 @@ def save_notify_config(config: NotifyConfigFile):
async def notify_now(notify: Notify):
if notify.platform == 'console':
if notify.platform == "console":
bot = [b for b in nonebot.get_bots().values() if isinstance(b, ConsoleBot)]
if len(bot) != 1:
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
return False
bot = bot[0]
await bot.send_private_message(notify.target, f"代办通知:{notify.notify_msg}")
elif notify.platform == 'discord':
elif notify.platform == "discord":
bot = [b for b in nonebot.get_bots().values() if isinstance(b, DiscordBot)]
if len(bot) != 1:
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
@ -83,7 +83,7 @@ async def notify_now(notify: Notify):
bot = bot[0]
channel = await bot.create_DM(recipient_id=int(notify.target))
await bot.send_to(channel.id, f"代办通知:{notify.notify_msg}")
elif notify.platform == 'qq':
elif notify.platform == "qq":
bot = [b for b in nonebot.get_bots().values() if isinstance(b, OnebotV11Bot)]
if len(bot) != 1:
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
@ -92,17 +92,22 @@ async def notify_now(notify: Notify):
if notify.target_env is None:
await bot.send_private_msg(
user_id=int(notify.target),
message=cast(Any, await UniMessage.text(f"代办通知:{notify.notify_msg}").export(
bot=bot,
)),
message=cast(
Any,
await UniMessage.text(f"代办通知:{notify.notify_msg}").export(
bot=bot,
),
),
)
else:
await bot.send_group_msg(
group_id=int(notify.target_env),
message=cast(Any,
await UniMessage().at(
notify.target
).text(f" 代办通知:{notify.notify_msg}").export(bot=bot)
message=cast(
Any,
await UniMessage()
.at(notify.target)
.text(f" 代办通知:{notify.notify_msg}")
.export(bot=bot),
),
)
else:
@ -127,15 +132,17 @@ def create_notify_task(notify: Notify, fail2remove: bool = True):
)
res = await notify_now(notify)
if fail2remove or res:
await DATA_FILE_LOCK.acquire()
cfg = load_notify_config()
cfg.notifies = [n for n in cfg.notifies if n.get_str() != notify.get_str()]
if not res:
cfg.unsent.append(notify)
save_notify_config(cfg)
DATA_FILE_LOCK.release()
async with DATA_FILE_LOCK:
cfg = load_notify_config()
cfg.notifies = [
n for n in cfg.notifies if n.get_str() != notify.get_str()
]
if not res:
cfg.unsent.append(notify)
save_notify_config(cfg)
else:
pass
return asynkio.create_task(mission())
@ -201,8 +208,12 @@ async def _(msg: UniMsg, mEvt: Event):
save_notify_config(cfg)
DATA_FILE_LOCK.release()
await evt.send(await UniMessage().at(mEvt.get_user_id()).text(
f" 了解啦!将会在 {notify.notify_time} 提醒你哦~").export())
await evt.send(
await UniMessage()
.at(mEvt.get_user_id())
.text(f" 了解啦!将会在 {notify.notify_time} 提醒你哦~")
.export()
)
logger.info(f"创建了一条于 {notify.notify_time} 的代办提醒")
@ -253,8 +264,8 @@ async def _():
logger.info("所有的代办提醒 Task 都已经退出了")
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, functools.partial(
asynkio.create_task, shutdown(sig)
))
loop.add_signal_handler(
sig, functools.partial(asynkio.create_task, shutdown(sig))
)
await asynkio.gather(*ASYNK_TASKS)