Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c94db33b11 | |||
| 67382a0c0a | |||
| fd4c9302c2 | |||
| f30ad0cb7d | |||
| f7afe48680 | |||
| b42385f780 | |||
| 6cae38dea9 | |||
| 8594b59783 | |||
| f768c91430 |
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
import datetime
|
||||
import json
|
||||
@ -89,6 +91,7 @@ class LongTaskTarget(BaseModel):
|
||||
)
|
||||
return False
|
||||
await bot.send_message(self.channel_id, cast(Any, await msg.export()))
|
||||
return True
|
||||
if self.platform == "discord":
|
||||
if not isinstance(bot, DCBot):
|
||||
logger.warning(
|
||||
@ -104,6 +107,7 @@ class LongTaskTarget(BaseModel):
|
||||
),
|
||||
tts=False,
|
||||
)
|
||||
return True
|
||||
logger.warning(f"没有一个平台是期望的平台 PLATFORM={self.platform}")
|
||||
return False
|
||||
|
||||
@ -111,7 +115,7 @@ class LongTaskTarget(BaseModel):
|
||||
class LongTask(BaseModel):
|
||||
uuid: str
|
||||
data_json: str
|
||||
target: "LongTaskTarget"
|
||||
target: LongTaskTarget
|
||||
callback: str
|
||||
deadline: datetime.datetime
|
||||
canceled: bool = False
|
||||
@ -143,11 +147,25 @@ class LongTask(BaseModel):
|
||||
datafile.unhandled.setdefault(self.callback, []).append(self)
|
||||
|
||||
return
|
||||
await hdl(self)
|
||||
success = False
|
||||
try:
|
||||
await hdl(self)
|
||||
success = True
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
async with longtask_data() as datafile:
|
||||
datafile.to_handle[self.callback] = [
|
||||
t for t in datafile.to_handle[self.callback] if t.uuid != self.uuid
|
||||
]
|
||||
if not success:
|
||||
datafile.unhandled.setdefault(self.callback, []).append(self)
|
||||
logger.info(
|
||||
f"LongTask 执行失败 UUID={self.uuid} callback={self.callback}"
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"LongTask 工作完成 UUID={self.uuid} callback={self.callback}"
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
self._aio_task = None
|
||||
@ -236,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(
|
||||
@ -257,6 +274,7 @@ async def create_longtask(
|
||||
deadline=deadline,
|
||||
)
|
||||
|
||||
logger.info(f"创建了新的 LongTask UUID={task.uuid} CALLBACK={task.callback}")
|
||||
await task.start()
|
||||
|
||||
async with longtask_data() as d:
|
||||
@ -266,10 +284,17 @@ async def create_longtask(
|
||||
|
||||
|
||||
async def init_longtask():
|
||||
counter = 0
|
||||
req: set[str] = set()
|
||||
|
||||
async with longtask_data() as data:
|
||||
for v in data.to_handle.values():
|
||||
for t in v:
|
||||
await t.start()
|
||||
counter += 1
|
||||
req.add(t.callback)
|
||||
|
||||
logger.info(f"LongTask 启动了任务 数量={counter} 期望的门类=[{','.join(req)}]")
|
||||
|
||||
|
||||
DepLongTaskTarget = Annotated[LongTaskTarget, Depends(get_long_task_target)]
|
||||
|
||||
@ -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())
|
||||
|
||||
|
||||
@ -4,13 +4,11 @@ import asyncio
|
||||
from loguru import logger
|
||||
import nonebot
|
||||
|
||||
# from nonebot.adapters import Bot, Event
|
||||
# from nonebot_plugin_alconna import UniMessage
|
||||
from konabot.common.longtask import (
|
||||
# DepLongTaskTarget,
|
||||
# LongTask,
|
||||
# create_longtask,
|
||||
# get_long_task_target,
|
||||
# handle_long_task,
|
||||
init_longtask,
|
||||
)
|
||||
@ -45,6 +43,5 @@ async def _():
|
||||
# handler="test_callback_001",
|
||||
# data={},
|
||||
# target=target,
|
||||
# deadline=datetime.datetime.now() + datetime.timedelta(seconds=2),
|
||||
# deadline=datetime.datetime.now() + datetime.timedelta(seconds=20),
|
||||
# )
|
||||
# await target.send_message(UniMessage().text("Hello, world!"), at=True)
|
||||
|
||||
@ -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())
|
||||
|
||||
|
||||
@ -155,7 +162,8 @@ async def _(msg: UniMsg, mEvt: Event):
|
||||
notify_time, notify_text = segments
|
||||
# target_time = get_target_time(notify_time)
|
||||
try:
|
||||
target_time = ptimeparse.parse(notify_time)
|
||||
# target_time = ptimeparse.parse(notify_time)
|
||||
target_time = ptimeparse.Parser().parse(notify_time)
|
||||
logger.info(f"从 {notify_time} 解析出了时间:{target_time}")
|
||||
except Exception:
|
||||
logger.info(f"无法从 {notify_time} 中解析出时间")
|
||||
@ -201,8 +209,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 +265,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)
|
||||
|
||||
8
poetry.lock
generated
8
poetry.lock
generated
@ -2402,14 +2402,14 @@ reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "ptimeparse"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
description = "一个用于解析中文的时间表达的库"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "ptimeparse-0.1.2-py3-none-any.whl", hash = "sha256:0eea791396e53b63330fadb40d9f0a2e6272bd5467246f10d1d6971bc606edff"},
|
||||
{file = "ptimeparse-0.1.2.tar.gz", hash = "sha256:658be90a3cc2994c09c4ea2f276d257e7eb84bc330be79950baefe32b19779a2"},
|
||||
{file = "ptimeparse-0.2.0-py3-none-any.whl", hash = "sha256:57055f8fd99fb69e19deac3b8a5c7ac91af86c7ac09781632e9abf318df0d6d2"},
|
||||
{file = "ptimeparse-0.2.0.tar.gz", hash = "sha256:867c265f2e157fe4d793d20fe9c449b8ede5c855f336d7e6b2eb78551e622766"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
@ -3807,4 +3807,4 @@ reference = "mirrors"
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12,<4.0"
|
||||
content-hash = "d6a325b769fb3ed207c1a8891e65ea20bae20166fa281d6fa620faf54ad15bd8"
|
||||
content-hash = "02530953efe65da1a788845cd43f8856be62db5bfb59de691cad813f57bab25e"
|
||||
|
||||
@ -2,30 +2,28 @@
|
||||
name = "konabot"
|
||||
version = "0.1.0"
|
||||
description = "在 MTTU 内部使用的 bot"
|
||||
authors = [
|
||||
{name = "passthem",email = "Passthem183@gmail.com"}
|
||||
]
|
||||
authors = [{ name = "passthem", email = "Passthem183@gmail.com" }]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12,<4.0"
|
||||
dependencies = [
|
||||
"nonebot2[all] (>=2.4.3,<3.0.0)",
|
||||
"nonebot-adapter-onebot (>=2.4.6,<3.0.0)",
|
||||
"nonebot-adapter-console (>=0.9.0,<0.10.0)",
|
||||
"nonebot-adapter-discord (>=0.1.8,<0.2.0)",
|
||||
"nonebot-adapter-minecraft (>=1.5.2,<2.0.0)",
|
||||
"nonebot-plugin-alconna (>=0.59.4,<0.60.0)",
|
||||
"nonebot-plugin-apscheduler (>=0.5.0,<0.6.0)",
|
||||
"requests (>=2.32.5,<3.0.0)",
|
||||
"beautifulsoup4 (>=4.13.5,<5.0.0)",
|
||||
"lxml (>=6.0.2,<7.0.0)",
|
||||
"pillow (>=11.3.0,<12.0.0)",
|
||||
"imagetext-py (>=2.2.0,<3.0.0)",
|
||||
"opencv-python-headless (>=4.12.0.88,<5.0.0.0)",
|
||||
"returns (>=0.26.0,<0.27.0)",
|
||||
"ptimeparse (>=0.1.1,<0.2.0)",
|
||||
"skia-python (>=138.0,<139.0)",
|
||||
"nonebot-plugin-analysis-bilibili (>=2.8.1,<3.0.0)",
|
||||
"qrcode (>=8.2,<9.0)",
|
||||
"nonebot2[all] (>=2.4.3,<3.0.0)",
|
||||
"nonebot-adapter-onebot (>=2.4.6,<3.0.0)",
|
||||
"nonebot-adapter-console (>=0.9.0,<0.10.0)",
|
||||
"nonebot-adapter-discord (>=0.1.8,<0.2.0)",
|
||||
"nonebot-adapter-minecraft (>=1.5.2,<2.0.0)",
|
||||
"nonebot-plugin-alconna (>=0.59.4,<0.60.0)",
|
||||
"nonebot-plugin-apscheduler (>=0.5.0,<0.6.0)",
|
||||
"requests (>=2.32.5,<3.0.0)",
|
||||
"beautifulsoup4 (>=4.13.5,<5.0.0)",
|
||||
"lxml (>=6.0.2,<7.0.0)",
|
||||
"pillow (>=11.3.0,<12.0.0)",
|
||||
"imagetext-py (>=2.2.0,<3.0.0)",
|
||||
"opencv-python-headless (>=4.12.0.88,<5.0.0.0)",
|
||||
"returns (>=0.26.0,<0.27.0)",
|
||||
"ptimeparse (>=0.1.1,<1.0.0)",
|
||||
"skia-python (>=138.0,<139.0)",
|
||||
"nonebot-plugin-analysis-bilibili (>=2.8.1,<3.0.0)",
|
||||
"qrcode (>=8.2,<9.0)",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
@ -43,4 +41,4 @@ url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
|
||||
priority = "primary"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
ptimeparse = {source = "pt-gitea-pypi"}
|
||||
ptimeparse = { source = "pt-gitea-pypi" }
|
||||
|
||||
Reference in New Issue
Block a user