mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2025-06-03 18:06:13 +08:00
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
import asyncio
|
|
from collections import deque
|
|
|
|
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
|
from nonebot.log import logger
|
|
from nonebot_plugin_saa import AggregatedMessageFactory, MessageFactory, PlatformTarget
|
|
from nonebot_plugin_saa.auto_select_bot import refresh_bots
|
|
|
|
from .plugin_config import plugin_config
|
|
|
|
Sendable = MessageFactory | AggregatedMessageFactory
|
|
|
|
QUEUE: deque[tuple[PlatformTarget, Sendable, int]] = deque()
|
|
|
|
MESSGE_SEND_INTERVAL = 1.5
|
|
|
|
_MESSAGE_DISPATCH_TASKS: set[asyncio.Task] = set()
|
|
|
|
|
|
async def _do_send(send_target: PlatformTarget, msg: Sendable):
|
|
try:
|
|
await msg.send_to(send_target)
|
|
except ActionFailed: # TODO: catch exception of other adapters
|
|
await refresh_bots()
|
|
logger.warning("send msg failed, refresh bots")
|
|
|
|
|
|
async def do_send_msgs():
|
|
if not QUEUE:
|
|
return
|
|
while True:
|
|
# why read from queue then pop item from queue?
|
|
# if there is only 1 item in queue, pop it and await send
|
|
# the length of queue will be 0.
|
|
# At that time, adding items to queue will trigger a new execution of this func, which is not expected.
|
|
# So, read from queue first then pop from it
|
|
send_target, msg_factory, retry_time = QUEUE[0]
|
|
try:
|
|
await _do_send(send_target, msg_factory)
|
|
except Exception as e:
|
|
await asyncio.sleep(MESSGE_SEND_INTERVAL)
|
|
QUEUE.popleft()
|
|
if retry_time > 0:
|
|
QUEUE.appendleft((send_target, msg_factory, retry_time - 1))
|
|
else:
|
|
msg_str = str(msg_factory)
|
|
if len(msg_str) > 50:
|
|
msg_str = msg_str[:50] + "..."
|
|
logger.warning(f"send msg err {e} {msg_str}")
|
|
else:
|
|
# sleeping after popping may also cause re-execution error like above mentioned
|
|
await asyncio.sleep(MESSGE_SEND_INTERVAL)
|
|
QUEUE.popleft()
|
|
finally:
|
|
if not QUEUE:
|
|
return
|
|
|
|
|
|
async def _send_msgs_dispatch(send_target: PlatformTarget, msg: Sendable):
|
|
if plugin_config.bison_use_queue:
|
|
QUEUE.append((send_target, msg, plugin_config.bison_resend_times))
|
|
# len(QUEUE) before append was 0
|
|
if len(QUEUE) == 1:
|
|
task = asyncio.create_task(do_send_msgs())
|
|
_MESSAGE_DISPATCH_TASKS.add(task)
|
|
task.add_done_callback(_MESSAGE_DISPATCH_TASKS.discard)
|
|
else:
|
|
await _do_send(send_target, msg)
|
|
|
|
|
|
async def send_msgs(send_target: PlatformTarget, msgs: list[MessageFactory]):
|
|
if not plugin_config.bison_use_pic_merge:
|
|
for msg in msgs:
|
|
await _send_msgs_dispatch(send_target, msg)
|
|
return
|
|
msgs = msgs.copy()
|
|
if plugin_config.bison_use_pic_merge == 1:
|
|
await _send_msgs_dispatch(send_target, msgs.pop(0))
|
|
if msgs:
|
|
if len(msgs) == 1: # 只有一条消息序列就不合并转发
|
|
await _send_msgs_dispatch(send_target, msgs.pop(0))
|
|
else:
|
|
forward_message = AggregatedMessageFactory(list(msgs))
|
|
await _send_msgs_dispatch(send_target, forward_message)
|