mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2025-07-28 06:50:57 +00:00
✨ 添加对主流框架的消息io支持
This commit is contained in:
@ -20,7 +20,6 @@ from liteyuki.log import (
|
||||
logger
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"LiteyukiBot",
|
||||
"get_bot",
|
||||
@ -34,6 +33,8 @@ __all__ = [
|
||||
"logger",
|
||||
]
|
||||
|
||||
__version__ = "6.3.7" # 测试版本号
|
||||
|
||||
__version__ = "6.3.8" # 测试版本号
|
||||
|
||||
# 6.3.8
|
||||
# 1. 初步添加对聊天的支持
|
||||
# 2. 优化了通道的性能
|
||||
|
@ -10,6 +10,7 @@ from typing import Any, Optional
|
||||
|
||||
from liteyuki.bot.lifespan import (LIFESPAN_FUNC, Lifespan)
|
||||
from liteyuki.comm.channel import get_channel
|
||||
from liteyuki.comm.storage import shared_memory
|
||||
from liteyuki.core.manager import ProcessManager
|
||||
from liteyuki.log import init_log, logger
|
||||
from liteyuki.plugin import load_plugin
|
||||
|
@ -60,7 +60,7 @@ class Channel(Generic[T]):
|
||||
|
||||
elif type_check:
|
||||
if self._get_generic_type() is None:
|
||||
raise TypeError("Type hint is required for enforcing type_ check.")
|
||||
raise TypeError("Type hint is required for enforcing type check.")
|
||||
self.type_check = type_check
|
||||
|
||||
def _get_generic_type(self) -> Optional[type]:
|
||||
@ -158,7 +158,7 @@ class Channel(Generic[T]):
|
||||
async def wrapper(data: T) -> Any:
|
||||
if filter_func is not None:
|
||||
if is_coroutine_callable(filter_func):
|
||||
if not (await filter_func(data)): # type_: ignore
|
||||
if not (await filter_func(data)): # type: ignore
|
||||
return
|
||||
else:
|
||||
if not filter_func(data):
|
||||
|
@ -13,9 +13,9 @@ from liteyuki.utils import IS_MAIN_PROCESS, is_coroutine_callable, run_coroutine
|
||||
if IS_MAIN_PROCESS:
|
||||
_locks = {}
|
||||
|
||||
_on_main_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type_: ignore
|
||||
_on_main_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type: ignore
|
||||
"""主进程订阅者接收函数"""
|
||||
_on_sub_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type_: ignore
|
||||
_on_sub_subscriber_receive_funcs: dict[str, list[ASYNC_ON_RECEIVE_FUNC]] = {} # type: ignore
|
||||
"""子进程订阅者接收函数"""
|
||||
|
||||
|
||||
@ -169,7 +169,7 @@ class KeyValueStore:
|
||||
(
|
||||
"publish",
|
||||
{
|
||||
"channel_": channel_,
|
||||
"channel": channel_,
|
||||
"data" : data
|
||||
}
|
||||
)
|
||||
@ -234,7 +234,7 @@ class KeyValueStore:
|
||||
data = self.active_chan.receive()
|
||||
if data[0] == "publish":
|
||||
# 运行主进程订阅函数
|
||||
self.run_subscriber_receive_funcs(data[1]["channel_"], data[1]["data"])
|
||||
self.run_subscriber_receive_funcs(data[1]["channel"], data[1]["data"])
|
||||
# 推送给子进程
|
||||
self.publish_channel.send(data)
|
||||
else:
|
||||
@ -242,7 +242,7 @@ class KeyValueStore:
|
||||
data = self.publish_channel.receive()
|
||||
if data[0] == "publish":
|
||||
# 运行子进程订阅函数
|
||||
self.run_subscriber_receive_funcs(data[1]["channel_"], data[1]["data"])
|
||||
self.run_subscriber_receive_funcs(data[1]["channel"], data[1]["data"])
|
||||
|
||||
|
||||
class GlobalKeyValueStore:
|
||||
|
@ -8,9 +8,49 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
@File : event.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
from liteyuki.comm.storage import shared_memory
|
||||
|
||||
|
||||
class Event:
|
||||
def __init__(self, type_: str, data: dict):
|
||||
self.type = type_
|
||||
def __init__(self, type: str, data: dict[str, Any], bot_id: str, session_id: str, session_type: str, receive_channel: str = "event_to_nonebot"):
|
||||
"""
|
||||
事件
|
||||
Args:
|
||||
type: 类型
|
||||
data: 数据
|
||||
bot_id: 机器人ID
|
||||
session_id: 会话ID
|
||||
session_type: 会话类型
|
||||
receive_channel: 接收频道
|
||||
"""
|
||||
self.type = type
|
||||
self.data = data
|
||||
self.bot_id = bot_id
|
||||
self.session_id = session_id
|
||||
self.session_type = session_type
|
||||
self.receive_channel = receive_channel
|
||||
|
||||
def __str__(self):
|
||||
return f"Event(type={self.type}, data={self.data}, bot_id={self.bot_id}, session_id={self.session_id}, session_type={self.session_type})"
|
||||
|
||||
def reply(self, message: str | dict[str, Any]):
|
||||
"""
|
||||
回复消息
|
||||
Args:
|
||||
message:
|
||||
Returns:
|
||||
"""
|
||||
to_nonebot_event = Event(
|
||||
type=self.session_type,
|
||||
data={
|
||||
"message": message
|
||||
},
|
||||
bot_id=self.bot_id,
|
||||
session_id=self.session_id,
|
||||
session_type=self.session_type,
|
||||
receive_channel="_"
|
||||
)
|
||||
print(to_nonebot_event)
|
||||
shared_memory.publish(self.receive_channel, to_nonebot_event)
|
||||
|
@ -8,7 +8,55 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
@File : matcher.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
import traceback
|
||||
from typing import Any, TypeAlias, Callable, Coroutine
|
||||
|
||||
from liteyuki import Event
|
||||
from liteyuki.message.rule import Rule
|
||||
|
||||
EventHandler: TypeAlias = Callable[[Event], Coroutine[None, None, Any]]
|
||||
|
||||
|
||||
class Matcher:
|
||||
pass
|
||||
def __init__(self, rule: Rule, priority: int, block: bool):
|
||||
"""
|
||||
匹配器
|
||||
Args:
|
||||
rule: 规则
|
||||
priority: 优先级 >= 0
|
||||
block: 是否阻断后续优先级更低的匹配器
|
||||
"""
|
||||
self.rule = rule
|
||||
self.priority = priority
|
||||
self.block = block
|
||||
self.handlers: list[EventHandler] = []
|
||||
|
||||
def __str__(self):
|
||||
return f"Matcher(rule={self.rule}, priority={self.priority}, block={self.block})"
|
||||
|
||||
def handle(self, handler: EventHandler) -> EventHandler:
|
||||
"""
|
||||
添加处理函数,装饰器
|
||||
Args:
|
||||
handler:
|
||||
Returns:
|
||||
EventHandler
|
||||
"""
|
||||
self.handlers.append(handler)
|
||||
return handler
|
||||
|
||||
async def run(self, event: Event) -> None:
|
||||
"""
|
||||
运行处理函数
|
||||
Args:
|
||||
event:
|
||||
Returns:
|
||||
"""
|
||||
if not await self.rule(event):
|
||||
return
|
||||
|
||||
for handler in self.handlers:
|
||||
try:
|
||||
await handler(event)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
@ -8,11 +8,40 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
@File : on.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
import threading
|
||||
|
||||
from queue import Queue
|
||||
|
||||
from liteyuki.comm.storage import shared_memory
|
||||
from liteyuki.log import logger
|
||||
from liteyuki.message.event import Event
|
||||
from liteyuki.message.matcher import Matcher
|
||||
from liteyuki.message.rule import Rule
|
||||
|
||||
_matcher_list: list[Matcher] = []
|
||||
_queue: Queue = Queue()
|
||||
|
||||
|
||||
def on_message(permission) -> Matcher:
|
||||
pass
|
||||
@shared_memory.on_subscriber_receive("event_to_liteyuki")
|
||||
async def _(event: Event):
|
||||
current_priority = -1
|
||||
for i, matcher in enumerate(_matcher_list):
|
||||
logger.info(f"Running matcher {matcher} for event: {event}")
|
||||
await matcher.run(event)
|
||||
# 同优先级不阻断,不同优先级阻断
|
||||
if current_priority != matcher.priority:
|
||||
current_priority = matcher.priority
|
||||
if matcher.block:
|
||||
break
|
||||
|
||||
|
||||
def on_message(rule: Rule = Rule(), priority: int = 0, block: bool = True) -> Matcher:
|
||||
matcher = Matcher(rule, priority, block)
|
||||
# 按照优先级插入
|
||||
for i, m in enumerate(_matcher_list):
|
||||
if m.priority < matcher.priority:
|
||||
_matcher_list.insert(i, matcher)
|
||||
break
|
||||
else:
|
||||
_matcher_list.append(matcher)
|
||||
return matcher
|
||||
|
@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/19 下午10:55
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : permission.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
|
||||
from typing import Callable, Coroutine, TypeAlias
|
||||
|
||||
PERMISSION_HANDLER: TypeAlias = Callable[[str], bool | Coroutine[None, None, bool]]
|
||||
|
||||
|
||||
class Permission:
|
||||
def __init__(self, handler: PERMISSION_HANDLER):
|
||||
self.handler = handler
|
||||
|
@ -7,4 +7,27 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
@Email : snowykami@outlook.com
|
||||
@File : rule.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
"""
|
||||
|
||||
from typing import Optional, TypeAlias, Callable, Coroutine
|
||||
|
||||
from liteyuki.message.event import Event
|
||||
|
||||
RuleHandler: TypeAlias = Callable[[Event], Coroutine[None, None, bool]]
|
||||
"""规则函数签名"""
|
||||
|
||||
|
||||
class Rule:
|
||||
def __init__(self, handler: Optional[RuleHandler] = None):
|
||||
self.handler = handler
|
||||
|
||||
def __or__(self, other: "Rule") -> "Rule":
|
||||
return Rule(lambda event: self.handler(event) or other.handler(event))
|
||||
|
||||
def __and__(self, other: "Rule") -> "Rule":
|
||||
return Rule(lambda event: self.handler(event) and other.handler(event))
|
||||
|
||||
async def __call__(self, event: Event) -> bool:
|
||||
if self.handler is None:
|
||||
return True
|
||||
return await self.handler(event)
|
||||
|
@ -117,7 +117,7 @@ def format_display_name(display_name: str, plugin_type: PluginType) -> str:
|
||||
match plugin_type:
|
||||
case PluginType.APPLICATION:
|
||||
color = "m"
|
||||
case PluginType.IMPLEMENTATION:
|
||||
case PluginType.TEST:
|
||||
color = "g"
|
||||
case PluginType.MODULE:
|
||||
color = "e"
|
||||
|
@ -25,15 +25,15 @@ class PluginType(Enum):
|
||||
SERVICE = "service"
|
||||
"""服务端:例如AI绘画后端"""
|
||||
|
||||
IMPLEMENTATION = "implementation"
|
||||
"""实现端:例如与聊天平台的协议实现"""
|
||||
|
||||
MODULE = "module"
|
||||
"""模块:导出对象给其他插件使用"""
|
||||
|
||||
UNCLASSIFIED = "unclassified"
|
||||
"""未分类:默认值"""
|
||||
|
||||
TEST = "test"
|
||||
"""测试:测试插件"""
|
||||
|
||||
|
||||
class PluginMetadata(BaseModel):
|
||||
"""
|
||||
@ -47,7 +47,7 @@ class PluginMetadata(BaseModel):
|
||||
插件描述
|
||||
usage: str
|
||||
插件使用方法
|
||||
type_: str
|
||||
type: str
|
||||
插件类型
|
||||
author: str
|
||||
插件作者
|
||||
|
Reference in New Issue
Block a user