mirror of
https://github.com/LiteyukiStudio/LiteyukiBot.git
synced 2024-11-22 20:17:39 +08:00
✨ 添加对lyfunction的支持
This commit is contained in:
parent
96c85d9dca
commit
c2b3018908
@ -19,6 +19,7 @@ from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_s
|
|||||||
from liteyuki.utils.base.reloader import Reloader
|
from liteyuki.utils.base.reloader import Reloader
|
||||||
from liteyuki.utils import event as event_utils, satori_utils
|
from liteyuki.utils import event as event_utils, satori_utils
|
||||||
from .api import update_liteyuki
|
from .api import update_liteyuki
|
||||||
|
from ..utils.base.ly_function import get_function
|
||||||
|
|
||||||
require("nonebot_plugin_alconna")
|
require("nonebot_plugin_alconna")
|
||||||
require("nonebot_plugin_apscheduler")
|
require("nonebot_plugin_apscheduler")
|
||||||
@ -219,8 +220,11 @@ async def _(result: Arparma, bot: T_Bot, event: T_MessageEvent, matcher: Matcher
|
|||||||
else:
|
else:
|
||||||
_args.append(arg.replace("EQUAL_SIGN", "="))
|
_args.append(arg.replace("EQUAL_SIGN", "="))
|
||||||
|
|
||||||
|
ly_func = get_function(function_name)
|
||||||
|
ly_func.bot = bot if "bot_id" not in _kwargs else nonebot.get_bot(_kwargs["bot_id"])
|
||||||
|
ly_func.matcher = matcher
|
||||||
|
|
||||||
|
await ly_func(*tuple(_args), **_kwargs)
|
||||||
|
|
||||||
@on_alconna(
|
@on_alconna(
|
||||||
command=Alconna(
|
command=Alconna(
|
||||||
@ -265,7 +269,6 @@ async def _(result: Arparma, bot: T_Bot, event: T_MessageEvent, matcher: Matcher
|
|||||||
print(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
|
print(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
|
||||||
await matcher.finish(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
|
await matcher.finish(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
|
||||||
|
|
||||||
|
|
||||||
# system hook
|
# system hook
|
||||||
@Bot.on_calling_api # 图片模式检测
|
@Bot.on_calling_api # 图片模式检测
|
||||||
async def test_for_md_image(bot: T_Bot, api: str, data: dict):
|
async def test_for_md_image(bot: T_Bot, api: str, data: dict):
|
||||||
@ -297,7 +300,6 @@ async def test_for_md_image(bot: T_Bot, api: str, data: dict):
|
|||||||
return
|
return
|
||||||
raise MockApiException(result=result)
|
raise MockApiException(result=result)
|
||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
async def on_startup():
|
async def on_startup():
|
||||||
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
|
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
|
||||||
@ -307,12 +309,10 @@ async def on_startup():
|
|||||||
temp_data.data["delta_time"] = delta_time
|
temp_data.data["delta_time"] = delta_time
|
||||||
common_db.save(temp_data) # 更新数据
|
common_db.save(temp_data) # 更新数据
|
||||||
|
|
||||||
|
|
||||||
@driver.on_shutdown
|
@driver.on_shutdown
|
||||||
async def on_shutdown():
|
async def on_shutdown():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@driver.on_bot_connect
|
@driver.on_bot_connect
|
||||||
async def _(bot: T_Bot):
|
async def _(bot: T_Bot):
|
||||||
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
|
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
|
||||||
@ -342,7 +342,6 @@ async def _(bot: T_Bot):
|
|||||||
message="Liteyuki reloaded in %.2f s" % delta_time
|
message="Liteyuki reloaded in %.2f s" % delta_time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# 每天4点更新
|
# 每天4点更新
|
||||||
@scheduler.scheduled_job("cron", hour=4)
|
@scheduler.scheduled_job("cron", hour=4)
|
||||||
async def every_day_update():
|
async def every_day_update():
|
||||||
@ -356,7 +355,6 @@ async def every_day_update():
|
|||||||
else:
|
else:
|
||||||
nonebot.logger.info(logs)
|
nonebot.logger.info(logs)
|
||||||
|
|
||||||
|
|
||||||
# 需要用户id的api
|
# 需要用户id的api
|
||||||
need_user_id = (
|
need_user_id = (
|
||||||
"send_private_msg",
|
"send_private_msg",
|
||||||
|
@ -1,2 +1,11 @@
|
|||||||
var qq=2751454815
|
var qq={0} msg={1} a=A
|
||||||
api send_private_msg user_id=qq message="Hello"
|
api send_private_msg user_id=qq message=msg
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# 使用asyncio.create_task()创建一个新的任务,不等待任务完成直接执行下一条命令
|
||||||
|
nohup function hello
|
||||||
|
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# cancel所有的tasks
|
||||||
|
end
|
@ -0,0 +1,6 @@
|
|||||||
|
var user_id={0}
|
||||||
|
api friend_poke user_id=user_id
|
||||||
|
api friend_poke user_id=user_id
|
||||||
|
sleep 0.2
|
||||||
|
nohup function poke
|
||||||
|
await
|
@ -5,14 +5,17 @@ liteyuki function是一种类似于mcfunction的函数,用于在liteyuki中实
|
|||||||
可以用于一些轻量级插件的编写,无需Python代码
|
可以用于一些轻量级插件的编写,无需Python代码
|
||||||
SnowyKami
|
SnowyKami
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
# cmd *args **kwargs
|
# cmd *args **kwargs
|
||||||
# api api_name **kwargs
|
# api api_name **kwargs
|
||||||
import os
|
import os
|
||||||
from typing import Any, Awaitable, Callable, Coroutine
|
from typing import Any, Awaitable, Callable, Coroutine
|
||||||
|
|
||||||
|
import nonebot
|
||||||
from nonebot import Bot
|
from nonebot import Bot
|
||||||
from nonebot.adapters.satori import bot
|
from nonebot.adapters.satori import bot
|
||||||
|
from nonebot.internal.matcher import Matcher
|
||||||
|
|
||||||
ly_function_extensions = (
|
ly_function_extensions = (
|
||||||
"lyf",
|
"lyf",
|
||||||
@ -24,57 +27,115 @@ loaded_functions = dict()
|
|||||||
|
|
||||||
|
|
||||||
class LiteyukiFunction:
|
class LiteyukiFunction:
|
||||||
def __init__(self, name: str, path: str):
|
def __init__(self, name: str):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.path = path
|
self.functions: list[str] = list()
|
||||||
self.functions = list()
|
|
||||||
|
|
||||||
self.bot: Bot = None
|
self.bot: Bot = None
|
||||||
|
|
||||||
self.var_data = dict()
|
self.var_data = dict()
|
||||||
self.macro_data = dict()
|
self.macro_data = dict()
|
||||||
|
self.matcher: Matcher = None
|
||||||
|
self.end = False
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
self.sub_tasks: list[asyncio.Task] = list()
|
||||||
for _callable in self.functions:
|
|
||||||
if _callable is not None:
|
async def __call__(self, *args, **kwargs):
|
||||||
_callable(*args, **kwargs)
|
for i, cmd in enumerate(self.functions):
|
||||||
|
r = await self.execute_line(cmd, i, *args, **kwargs)
|
||||||
|
if r == 0:
|
||||||
|
msg = f"End function {self.name} by line {i}"
|
||||||
|
nonebot.logger.debug(msg)
|
||||||
|
for task in self.sub_tasks:
|
||||||
|
task.cancel(msg)
|
||||||
|
return
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"LiteyukiFunction({self.name}, {self.path})"
|
return f"LiteyukiFunction({self.name})"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
async def execute_line(self, line: str) -> Callable[[tuple, dict], Coroutine[Any, Any, Any] | Any] | None:
|
async def execute_line(self, cmd: str, line: int = 0, *args, **kwargs) -> Any:
|
||||||
"""
|
"""
|
||||||
解析一行轻雪函数
|
解析一行轻雪函数
|
||||||
Args:
|
Args:
|
||||||
line:
|
cmd: 命令
|
||||||
|
line: 行数
|
||||||
Returns:
|
Returns:
|
||||||
"""
|
"""
|
||||||
|
cmd = cmd.format(*args, **kwargs)
|
||||||
|
no_head = cmd.split(" ", 1)[1] if len(cmd.split(" ")) > 1 else ""
|
||||||
|
try:
|
||||||
|
head, args, kwargs = self.get_args(cmd)
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"Parsing error in {self.name} at line {line}: {e}"
|
||||||
|
nonebot.logger.error(error_msg)
|
||||||
|
await self.matcher.send(error_msg)
|
||||||
|
return
|
||||||
|
|
||||||
args: list[str] = line.split(" ")
|
if head == "var":
|
||||||
head = args.pop(0)
|
|
||||||
if head.startswith("#"):
|
|
||||||
# 注释
|
|
||||||
return None
|
|
||||||
|
|
||||||
elif head == "var":
|
|
||||||
# 变量定义
|
# 变量定义
|
||||||
for arg in args:
|
self.var_data.update(kwargs)
|
||||||
self.var_data[arg.split("=", 1)[0]] = eval(arg.split("=", 1)[1])
|
|
||||||
|
|
||||||
elif head == "cmd":
|
elif head == "cmd":
|
||||||
# 在当前计算机上执行命令
|
# 在当前计算机上执行命令
|
||||||
os.system(line.split(" ", 1)[1])
|
os.system(no_head)
|
||||||
|
|
||||||
elif head == "api":
|
elif head == "api":
|
||||||
# 调用Bot API 需要Bot实例
|
# 调用Bot API 需要Bot实例
|
||||||
await self.bot.call_api(line.split(" ", 1)[1])
|
await self.bot.call_api(args[1], **kwargs)
|
||||||
|
|
||||||
elif head == "function":
|
elif head == "function":
|
||||||
# 调用轻雪函数
|
# 调用轻雪函数
|
||||||
return functools.partial(get_function, line.split(" ", 1)[1])
|
func = get_function(args[1])
|
||||||
|
func.bot = self.bot
|
||||||
|
func.matcher = self.matcher
|
||||||
|
await func(*args[2:], **kwargs)
|
||||||
|
|
||||||
|
elif head == "sleep":
|
||||||
|
# 等待一段时间
|
||||||
|
await asyncio.sleep(float(args[1]))
|
||||||
|
|
||||||
|
elif head == "nohup":
|
||||||
|
# 挂起运行
|
||||||
|
print("挂起运行")
|
||||||
|
task = asyncio.create_task(self.execute_line(no_head))
|
||||||
|
self.sub_tasks.append(task)
|
||||||
|
|
||||||
|
elif head == "end":
|
||||||
|
# 结束所有函数
|
||||||
|
self.end = True
|
||||||
|
return 0
|
||||||
|
|
||||||
|
elif head == "await":
|
||||||
|
# 等待所有协程执行完毕
|
||||||
|
await asyncio.gather(*self.sub_tasks)
|
||||||
|
|
||||||
|
def get_args(self, line: str) -> tuple[str, tuple[str, ...], dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取参数
|
||||||
|
Args:
|
||||||
|
line: 命令
|
||||||
|
Returns:
|
||||||
|
命令头 参数 关键字
|
||||||
|
"""
|
||||||
|
line = line.replace("\\=", "EQUAL_SIGN")
|
||||||
|
head = ""
|
||||||
|
args = list()
|
||||||
|
kwargs = dict()
|
||||||
|
for i, arg in enumerate(line.split(" ")):
|
||||||
|
if "=" in arg:
|
||||||
|
key, value = arg.split("=", 1)
|
||||||
|
value = value.replace("EQUAL_SIGN", "=")
|
||||||
|
try:
|
||||||
|
value = eval(value)
|
||||||
|
except:
|
||||||
|
value = self.var_data.get(value, value)
|
||||||
|
kwargs[key] = value
|
||||||
|
else:
|
||||||
|
if i == 0:
|
||||||
|
head = arg
|
||||||
|
args.append(arg)
|
||||||
|
return head, tuple(args), kwargs
|
||||||
|
|
||||||
|
|
||||||
def get_function(name: str) -> LiteyukiFunction | None:
|
def get_function(name: str) -> LiteyukiFunction | None:
|
||||||
@ -89,7 +150,7 @@ def get_function(name: str) -> LiteyukiFunction | None:
|
|||||||
|
|
||||||
def load_from_dir(path: str):
|
def load_from_dir(path: str):
|
||||||
"""
|
"""
|
||||||
从目录中加载轻雪函数,类似mcfunction
|
从目录及其子目录中递归加载所有轻雪函数,类似mcfunction
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path: 目录路径
|
path: 目录路径
|
||||||
@ -99,6 +160,8 @@ def load_from_dir(path: str):
|
|||||||
if os.path.isfile(f):
|
if os.path.isfile(f):
|
||||||
if f.endswith(ly_function_extensions):
|
if f.endswith(ly_function_extensions):
|
||||||
load_from_file(f)
|
load_from_file(f)
|
||||||
|
if os.path.isdir(f):
|
||||||
|
load_from_dir(f)
|
||||||
|
|
||||||
|
|
||||||
def load_from_file(path: str):
|
def load_from_file(path: str):
|
||||||
@ -108,4 +171,12 @@ def load_from_file(path: str):
|
|||||||
path:
|
path:
|
||||||
Returns:
|
Returns:
|
||||||
"""
|
"""
|
||||||
pass
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
name = ".".join(os.path.basename(path).split(".")[:-1])
|
||||||
|
func = LiteyukiFunction(name)
|
||||||
|
for i, line in enumerate(f.read().split("\n")):
|
||||||
|
if line.startswith("#") or line.strip() == "":
|
||||||
|
continue
|
||||||
|
func.functions.append(line)
|
||||||
|
loaded_functions[name] = func
|
||||||
|
nonebot.logger.debug(f"Loaded function {name}")
|
||||||
|
@ -9,6 +9,7 @@ import yaml
|
|||||||
|
|
||||||
from .data import LiteModel
|
from .data import LiteModel
|
||||||
from .language import Language, get_default_lang_code
|
from .language import Language, get_default_lang_code
|
||||||
|
from .ly_function import loaded_functions
|
||||||
|
|
||||||
_loaded_resource_packs: list["ResourceMetadata"] = [] # 按照加载顺序排序
|
_loaded_resource_packs: list["ResourceMetadata"] = [] # 按照加载顺序排序
|
||||||
temp_resource_root = "data/liteyuki/resources"
|
temp_resource_root = "data/liteyuki/resources"
|
||||||
@ -127,6 +128,7 @@ def load_resources():
|
|||||||
# 加载默认资源和语言
|
# 加载默认资源和语言
|
||||||
# 清空临时资源包路径data/liteyuki/resources
|
# 清空临时资源包路径data/liteyuki/resources
|
||||||
_loaded_resource_packs.clear()
|
_loaded_resource_packs.clear()
|
||||||
|
loaded_functions.clear()
|
||||||
if os.path.exists(temp_resource_root):
|
if os.path.exists(temp_resource_root):
|
||||||
shutil.rmtree(temp_resource_root)
|
shutil.rmtree(temp_resource_root)
|
||||||
os.makedirs(temp_resource_root, exist_ok=True)
|
os.makedirs(temp_resource_root, exist_ok=True)
|
||||||
|
@ -4,10 +4,6 @@ from os import getcwd
|
|||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import nonebot
|
import nonebot
|
||||||
from nonebot import require
|
|
||||||
|
|
||||||
require("nonebot_plugin_htmlrender")
|
|
||||||
|
|
||||||
from nonebot_plugin_htmlrender import *
|
from nonebot_plugin_htmlrender import *
|
||||||
from .tools import random_hex_string
|
from .tools import random_hex_string
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user