mirror of
https://github.com/Genshin-bots/gsuid_core.git
synced 2025-05-12 06:55:49 +08:00
✨ 使大部分功能可用、修改部分配置
This commit is contained in:
parent
706bb59abc
commit
eb8789c823
2
.gitignore
vendored
2
.gitignore
vendored
@ -663,3 +663,5 @@ FodyWeavers.xsd
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,jetbrains+all,python,data
|
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,jetbrains+all,python,data
|
||||||
|
|
||||||
config.json
|
config.json
|
||||||
|
res_data
|
||||||
|
GsData.db
|
||||||
|
@ -41,7 +41,7 @@ poetry run python core.py
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from gsuid_core.sv import SL, SV
|
from gsuid_core.sv import SL, SV
|
||||||
from gsuid_core.server import Bot
|
from gsuid_core.bot import Bot
|
||||||
from gsuid_core.models import MessageContent
|
from gsuid_core.models import MessageContent
|
||||||
|
|
||||||
|
|
||||||
|
49
gsuid_core/bot.py
Normal file
49
gsuid_core/bot.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import asyncio
|
||||||
|
from typing import List, Union, Optional
|
||||||
|
|
||||||
|
from logger import logger
|
||||||
|
from fastapi import WebSocket
|
||||||
|
from gs_logger import GsLogger
|
||||||
|
from segment import MessageSegment
|
||||||
|
from msgspec import json as msgjson
|
||||||
|
from models import Message, MessageSend
|
||||||
|
|
||||||
|
|
||||||
|
class Bot:
|
||||||
|
def __init__(self, _id: str, ws: WebSocket):
|
||||||
|
self.bot_id = _id
|
||||||
|
self.bot = ws
|
||||||
|
self.logger = GsLogger(self.bot_id, ws)
|
||||||
|
self.queue = asyncio.queues.Queue()
|
||||||
|
self.background_tasks = set()
|
||||||
|
self.user_id: Optional[str] = None
|
||||||
|
self.group_id: Optional[str] = None
|
||||||
|
self.user_type: Optional[str] = None
|
||||||
|
|
||||||
|
async def send(self, message: Union[Message, List[Message], str, bytes]):
|
||||||
|
if isinstance(message, Message):
|
||||||
|
message = [message]
|
||||||
|
elif isinstance(message, str):
|
||||||
|
if message.startswith('base64://'):
|
||||||
|
message = [MessageSegment.image(message)]
|
||||||
|
else:
|
||||||
|
message = [MessageSegment.text(message)]
|
||||||
|
elif isinstance(message, bytes):
|
||||||
|
message = [MessageSegment.image(message)]
|
||||||
|
send = MessageSend(
|
||||||
|
content=message,
|
||||||
|
bot_id=self.bot_id,
|
||||||
|
target_type=self.user_type,
|
||||||
|
target_id=self.group_id if self.group_id else self.user_id,
|
||||||
|
)
|
||||||
|
logger.info(f'[发送消息] {send}')
|
||||||
|
await self.bot.send_bytes(msgjson.encode(send))
|
||||||
|
|
||||||
|
async def _process(self):
|
||||||
|
while True:
|
||||||
|
data = await self.queue.get()
|
||||||
|
task = asyncio.create_task(data)
|
||||||
|
self.background_tasks.add(task)
|
||||||
|
task.add_done_callback(
|
||||||
|
lambda _: self.background_tasks.discard(task)
|
||||||
|
)
|
@ -36,8 +36,9 @@ class GsClient:
|
|||||||
intent = await self._input()
|
intent = await self._input()
|
||||||
msg = MessageReceive(
|
msg = MessageReceive(
|
||||||
bot_id='Nonebot',
|
bot_id='Nonebot',
|
||||||
user_type='group',
|
user_type='DIRECT',
|
||||||
group_id='123456789',
|
user_pm=2,
|
||||||
|
group_id=None,
|
||||||
user_id='5253123',
|
user_id='5253123',
|
||||||
content=[Message(type='text', data=intent)],
|
content=[Message(type='text', data=intent)],
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from server import gss
|
from gss import gss
|
||||||
from config import core_config
|
from config import core_config
|
||||||
from handler import handle_event
|
from handler import handle_event
|
||||||
from models import MessageReceive
|
from models import MessageReceive
|
||||||
|
42
gsuid_core/gs_logger.py
Normal file
42
gsuid_core/gs_logger.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
from fastapi import WebSocket
|
||||||
|
from models import MessageSend
|
||||||
|
from segment import MessageSegment
|
||||||
|
from msgspec import json as msgjson
|
||||||
|
|
||||||
|
|
||||||
|
class GsLogger:
|
||||||
|
def __init__(self, bot_id: str, ws: WebSocket):
|
||||||
|
self.bot_id = bot_id
|
||||||
|
self.bot = ws
|
||||||
|
|
||||||
|
def get_msg_send(
|
||||||
|
self, type: Literal['INFO', 'WARNING', 'ERROR', 'SUCCESS'], msg: str
|
||||||
|
):
|
||||||
|
return MessageSend(
|
||||||
|
content=[MessageSegment.log(type, msg)],
|
||||||
|
bot_id=self.bot_id,
|
||||||
|
target_type=None,
|
||||||
|
target_id=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def info(self, msg: str):
|
||||||
|
await self.bot.send_bytes(
|
||||||
|
msgjson.encode(self.get_msg_send('INFO', msg))
|
||||||
|
)
|
||||||
|
|
||||||
|
async def warning(self, msg: str):
|
||||||
|
await self.bot.send_bytes(
|
||||||
|
msgjson.encode(self.get_msg_send('WARNING', msg))
|
||||||
|
)
|
||||||
|
|
||||||
|
async def error(self, msg: str):
|
||||||
|
await self.bot.send_bytes(
|
||||||
|
msgjson.encode(self.get_msg_send('ERROR', msg))
|
||||||
|
)
|
||||||
|
|
||||||
|
async def success(self, msg: str):
|
||||||
|
await self.bot.send_bytes(
|
||||||
|
msgjson.encode(self.get_msg_send('SUCCESS', msg))
|
||||||
|
)
|
6
gsuid_core/gss.py
Normal file
6
gsuid_core/gss.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from server import GsServer
|
||||||
|
|
||||||
|
gss = GsServer()
|
||||||
|
if not gss.is_load:
|
||||||
|
gss.is_load = True
|
||||||
|
gss.load_plugins()
|
@ -1,6 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from server import Bot
|
from bot import Bot
|
||||||
from trigger import Trigger
|
from trigger import Trigger
|
||||||
from config import core_config
|
from config import core_config
|
||||||
from models import MessageContent, MessageReceive
|
from models import MessageContent, MessageReceive
|
||||||
@ -50,6 +50,11 @@ async def handle_event(ws: Bot, msg: MessageReceive):
|
|||||||
SL.lst[sv].enabled
|
SL.lst[sv].enabled
|
||||||
and user_pm <= SL.lst[sv].permission
|
and user_pm <= SL.lst[sv].permission
|
||||||
and msg.group_id not in SL.lst[sv].black_list
|
and msg.group_id not in SL.lst[sv].black_list
|
||||||
|
and True
|
||||||
|
if SL.lst[sv].area == 'ALL'
|
||||||
|
or (msg.group_id and SL.lst[sv].area == 'GROUP')
|
||||||
|
or (not msg.group_id and SL.lst[sv].area == 'DIRECT')
|
||||||
|
else False
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
await asyncio.gather(*pending, return_exceptions=True)
|
await asyncio.gather(*pending, return_exceptions=True)
|
||||||
|
19
gsuid_core/hook.py
Normal file
19
gsuid_core/hook.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from functools import wraps
|
||||||
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
from gsuid_core.server import gss
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
def on_bot_connect():
|
||||||
|
def deco(func: Callable) -> Callable:
|
||||||
|
gss.bot_connect_def.append(func)
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(*args, **kwargs) -> Optional[Callable]:
|
||||||
|
logger.info('@on_bot_connect已成功调用...')
|
||||||
|
return await func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return deco
|
22
gsuid_core/logger.py
Normal file
22
gsuid_core/logger.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
import rollbar
|
||||||
|
from rollbar.logger import RollbarHandler
|
||||||
|
|
||||||
|
# Initialize Rollbar SDK with your server-side access token
|
||||||
|
rollbar.init(
|
||||||
|
'ACCESS_TOKEN',
|
||||||
|
environment='staging',
|
||||||
|
handler='async',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set root logger to log DEBUG and above
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Report ERROR and above to Rollbar
|
||||||
|
rollbar_handler = RollbarHandler()
|
||||||
|
rollbar_handler.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
# Attach Rollbar handler to the root logger
|
||||||
|
logger.addHandler(rollbar_handler)
|
@ -8,19 +8,19 @@ class Message(Struct):
|
|||||||
data: Optional[Any] = None
|
data: Optional[Any] = None
|
||||||
|
|
||||||
|
|
||||||
class MessageReceive(Struct):
|
class MessageReceive(Struct, frozen=True):
|
||||||
bot_id: str = 'Bot'
|
bot_id: str = 'Bot'
|
||||||
user_type: Optional[str] = None
|
user_type: Optional[str] = None
|
||||||
group_id: Optional[str] = None
|
group_id: Optional[str] = None
|
||||||
user_id: Optional[str] = None
|
user_id: str = ''
|
||||||
user_pm: int = 3
|
user_pm: int = 3
|
||||||
content: List[Message] = []
|
content: List[Message] = []
|
||||||
|
|
||||||
|
|
||||||
class MessageContent(Struct):
|
class MessageContent(Struct):
|
||||||
raw: Optional[MessageReceive] = None
|
raw: MessageReceive = MessageReceive()
|
||||||
raw_text: str = ''
|
raw_text: str = ''
|
||||||
command: Optional[str] = None
|
command: str = ''
|
||||||
text: str = ''
|
text: str = ''
|
||||||
image: Optional[str] = None
|
image: Optional[str] = None
|
||||||
at: Optional[str] = None
|
at: Optional[str] = None
|
||||||
|
@ -2,94 +2,31 @@ import sys
|
|||||||
import asyncio
|
import asyncio
|
||||||
import importlib
|
import importlib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Union, Literal, Optional
|
from typing import Dict, Callable
|
||||||
|
|
||||||
|
from bot import Bot
|
||||||
|
from logger import logger
|
||||||
from fastapi import WebSocket
|
from fastapi import WebSocket
|
||||||
from segment import MessageSegment
|
|
||||||
from msgspec import json as msgjson
|
|
||||||
from models import Message, MessageSend
|
|
||||||
|
|
||||||
sys.path.append(str(Path(__file__).parents[1]))
|
sys.path.append(str(Path(__file__).parents[1]))
|
||||||
|
|
||||||
|
|
||||||
class Bot:
|
|
||||||
def __init__(self, _id: str):
|
|
||||||
self.bot_id = _id
|
|
||||||
self.bot = gss.active_bot[_id]
|
|
||||||
self.logger = GsLogger(self.bot_id)
|
|
||||||
self.queue = asyncio.queues.Queue()
|
|
||||||
self.background_tasks = set()
|
|
||||||
self.user_id: Optional[str] = None
|
|
||||||
self.group_id: Optional[str] = None
|
|
||||||
self.user_type: Optional[str] = None
|
|
||||||
|
|
||||||
async def send(self, message: Union[Message, List[Message], str]):
|
|
||||||
if isinstance(message, Message):
|
|
||||||
message = [message]
|
|
||||||
elif isinstance(message, str):
|
|
||||||
if message.startswith('base64://'):
|
|
||||||
message = [MessageSegment.image(message)]
|
|
||||||
else:
|
|
||||||
message = [MessageSegment.text(message)]
|
|
||||||
send = MessageSend(
|
|
||||||
content=message,
|
|
||||||
bot_id=self.bot_id,
|
|
||||||
target_type=self.user_type,
|
|
||||||
target_id=self.group_id if self.group_id else self.user_id,
|
|
||||||
)
|
|
||||||
print(f'[发送消息] {send}')
|
|
||||||
await self.bot.send_bytes(msgjson.encode(send))
|
|
||||||
|
|
||||||
async def _process(self):
|
|
||||||
while True:
|
|
||||||
data = await self.queue.get()
|
|
||||||
task = asyncio.create_task(data)
|
|
||||||
self.background_tasks.add(task)
|
|
||||||
task.add_done_callback(
|
|
||||||
lambda _: self.background_tasks.discard(task)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class GsLogger:
|
|
||||||
def __init__(self, bot_id: str):
|
|
||||||
self.bot_id = bot_id
|
|
||||||
self.bot = gss.active_bot[bot_id]
|
|
||||||
|
|
||||||
def get_msg_send(
|
|
||||||
self, type: Literal['INFO', 'WARNING', 'ERROR', 'SUCCESS'], msg: str
|
|
||||||
):
|
|
||||||
return MessageSend(
|
|
||||||
content=[MessageSegment.log(type, msg)],
|
|
||||||
bot_id=self.bot_id,
|
|
||||||
target_type=None,
|
|
||||||
target_id=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def info(self, msg: str):
|
|
||||||
await self.bot.send_bytes(
|
|
||||||
msgjson.encode(self.get_msg_send('INFO', msg))
|
|
||||||
)
|
|
||||||
|
|
||||||
async def warning(self, msg: str):
|
|
||||||
await self.bot.send_bytes(
|
|
||||||
msgjson.encode(self.get_msg_send('WARNING', msg))
|
|
||||||
)
|
|
||||||
|
|
||||||
async def error(self, msg: str):
|
|
||||||
await self.bot.send_bytes(
|
|
||||||
msgjson.encode(self.get_msg_send('ERROR', msg))
|
|
||||||
)
|
|
||||||
|
|
||||||
async def success(self, msg: str):
|
|
||||||
await self.bot.send_bytes(
|
|
||||||
msgjson.encode(self.get_msg_send('SUCCESS', msg))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class GsServer:
|
class GsServer:
|
||||||
|
_instance = None
|
||||||
|
is_initialized = False
|
||||||
|
is_load = False
|
||||||
|
bot_connect_def = set()
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
# 判断sv是否已经被初始化
|
||||||
|
if cls._instance is None:
|
||||||
|
cls._instance = super().__new__(cls)
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
if not self.is_initialized:
|
||||||
self.active_bot: Dict[str, WebSocket] = {}
|
self.active_bot: Dict[str, WebSocket] = {}
|
||||||
self.load_plugins()
|
self.is_initialized = True
|
||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
sys.path.append(str(Path(__file__).parents[1]))
|
sys.path.append(str(Path(__file__).parents[1]))
|
||||||
@ -121,12 +58,14 @@ class GsServer:
|
|||||||
async def connect(self, websocket: WebSocket, bot_id: str) -> Bot:
|
async def connect(self, websocket: WebSocket, bot_id: str) -> Bot:
|
||||||
await websocket.accept()
|
await websocket.accept()
|
||||||
self.active_bot[bot_id] = websocket
|
self.active_bot[bot_id] = websocket
|
||||||
print(f'{bot_id}已连接!')
|
logger.info(f'{bot_id}已连接!')
|
||||||
return Bot(bot_id)
|
_task = [_def() for _def in self.bot_connect_def]
|
||||||
|
asyncio.gather(*_task)
|
||||||
|
return Bot(bot_id, websocket)
|
||||||
|
|
||||||
def disconnect(self, bot_id: str):
|
def disconnect(self, bot_id: str):
|
||||||
del self.active_bot[bot_id]
|
del self.active_bot[bot_id]
|
||||||
print(f'{bot_id}已中断!')
|
logger.warning(f'{bot_id}已中断!')
|
||||||
|
|
||||||
async def send(self, message: str, bot_id: str):
|
async def send(self, message: str, bot_id: str):
|
||||||
await self.active_bot[bot_id].send_text(message)
|
await self.active_bot[bot_id].send_text(message)
|
||||||
@ -135,5 +74,7 @@ class GsServer:
|
|||||||
for bot_id in self.active_bot:
|
for bot_id in self.active_bot:
|
||||||
await self.send(message, bot_id)
|
await self.send(message, bot_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
gss = GsServer()
|
def on_bot_connect(cls, func: Callable):
|
||||||
|
cls.bot_connect_def.add(func)
|
||||||
|
return func
|
||||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Dict, List, Tuple, Union, Literal, Callable, Optional
|
from typing import Dict, List, Tuple, Union, Literal, Callable, Optional
|
||||||
|
|
||||||
|
from logger import logger
|
||||||
from trigger import Trigger
|
from trigger import Trigger
|
||||||
from config import core_config
|
from config import core_config
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ config_sv = core_config.get_config('sv')
|
|||||||
class SV:
|
class SV:
|
||||||
is_initialized = False
|
is_initialized = False
|
||||||
|
|
||||||
def __new__(cls, *args):
|
def __new__(cls, *args, **kwargs):
|
||||||
# 判断sv是否已经被初始化
|
# 判断sv是否已经被初始化
|
||||||
if args[0] in SL.lst:
|
if args[0] in SL.lst:
|
||||||
return SL.lst[args[0]]
|
return SL.lst[args[0]]
|
||||||
@ -34,14 +35,15 @@ class SV:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str = '',
|
||||||
permission: int = 3,
|
permission: int = 3,
|
||||||
priority: int = 5,
|
priority: int = 5,
|
||||||
enabled: bool = True,
|
enabled: bool = True,
|
||||||
|
area: Literal['GROUP', 'DIRECT', 'ALL'] = 'ALL',
|
||||||
black_list: List = [],
|
black_list: List = [],
|
||||||
):
|
):
|
||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
print(f'【{name}】模块初始化中...')
|
logger.info(f'【{name}】模块初始化中...')
|
||||||
# sv名称,重复的sv名称将被并入一个sv里
|
# sv名称,重复的sv名称将被并入一个sv里
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
# sv内包含的触发器
|
# sv内包含的触发器
|
||||||
@ -54,21 +56,25 @@ class SV:
|
|||||||
self.enabled = config_sv[name]['enabled']
|
self.enabled = config_sv[name]['enabled']
|
||||||
self.permission = config_sv[name]['permission']
|
self.permission = config_sv[name]['permission']
|
||||||
self.black_list = config_sv[name]['black_list']
|
self.black_list = config_sv[name]['black_list']
|
||||||
|
self.area = config_sv[name]['area']
|
||||||
else:
|
else:
|
||||||
# sv优先级
|
# sv优先级
|
||||||
self.priority: int = priority
|
self.priority = priority
|
||||||
# sv是否开启
|
# sv是否开启
|
||||||
self.enabled: bool = enabled
|
self.enabled = enabled
|
||||||
# 黑名单群
|
# 黑名单群
|
||||||
self.black_list: List = black_list
|
self.black_list = black_list
|
||||||
# 权限 0为master,1为superuser,2为群的群主&管理员,3为普通
|
# 权限 0为master,1为superuser,2为群的群主&管理员,3为普通
|
||||||
self.permission: int = permission
|
self.permission = permission
|
||||||
|
# 作用范围
|
||||||
|
self.area = area
|
||||||
# 写入
|
# 写入
|
||||||
self.set(
|
self.set(
|
||||||
priority=priority,
|
priority=priority,
|
||||||
enabled=enabled,
|
enabled=enabled,
|
||||||
permission=permission,
|
permission=permission,
|
||||||
black_list=black_list,
|
black_list=black_list,
|
||||||
|
area=area,
|
||||||
)
|
)
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
@ -96,7 +102,7 @@ class SV:
|
|||||||
keyword_list = (keyword,)
|
keyword_list = (keyword,)
|
||||||
for _k in keyword_list:
|
for _k in keyword_list:
|
||||||
if _k not in self.TL:
|
if _k not in self.TL:
|
||||||
print(f'载入{type}触发器【{_k}】!')
|
logger.info(f'载入{type}触发器【{_k}】!')
|
||||||
self.TL[_k] = Trigger(type, _k, func)
|
self.TL[_k] = Trigger(type, _k, func)
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user