Exemple #1
0
 def __init__(self, config: dict):
     if not self.__first_init:
         logger.info("Initializing")
         if any(parameter not in config
                for parameter in self.necessary_parameters):
             raise ValueError(
                 f"Missing necessary parameters! (miraiHost, authKey, BotQQ)"
             )
         self.__loop = asyncio.get_event_loop()
         self.__bcc = Broadcast(loop=self.__loop)
         self.__app = GraiaMiraiApplication(broadcast=self.__bcc,
                                            connect_info=Session(
                                                host=config["miraiHost"],
                                                authKey=config["authKey"],
                                                account=config["BotQQ"],
                                                websocket=True),
                                            enable_chat_log=False)
         self.__saya = Saya(self.__bcc)
         self.__saya.install_behaviours(BroadcastBehaviour(self.__bcc))
         self.__app.debug = False
         self.__config = config
         AppCore.__first_init = True
         logger.info("Initialize end")
     else:
         raise AppCoreAlreadyInitialized()
 def __init__(self, config: GlobalConfig):
     if not self.__first_init:
         logger.info("Initializing")
         self.__loop = asyncio.get_event_loop()
         self.__bcc = Broadcast(loop=self.__loop)
         self.__app = Ariadne(broadcast=self.__bcc,
                              chat_log_config=False,
                              connect_info=DefaultAdapter(
                                  broadcast=self.__bcc,
                                  ping=False,
                                  mirai_session=MiraiSession(
                                      host=config.mirai_host,
                                      verify_key=str(config.verify_key),
                                      account=config.bot_qq),
                              ))
         self.__saya = Saya(self.__bcc)
         self.__saya.install_behaviours(BroadcastBehaviour(self.__bcc))
         if _install_scheduler:
             self.__sche = GraiaScheduler(loop=self.__loop,
                                          broadcast=self.__bcc)
             self.__saya.install_behaviours(
                 GraiaSchedulerBehaviour(self.__sche))
         self.__app.debug = False
         self.__config = config
         AppCore.__first_init = True
         logger.info("Initialize end")
     else:
         raise AppCoreAlreadyInitialized()
Exemple #3
0
def saya_init():
    channels = Saya.current().channels
    core = AppCore.get_core_instance()
    bcc = core.get_bcc()
    for channel in channels.values():
        cubes = channel.content
        logger.info(f"converting saya module: {channel.module}")
        for cube in cubes:
            if isinstance(cube.metaclass, ListenerSchema):
                bcc.removeListener(bcc.getListener(cube.content))
                if all([
                        issubclass(i, GroupEvent)
                        for i in cube.metaclass.listening_events
                ]):
                    cube.metaclass.decorators.append(manageable(
                        channel.module))
                else:
                    cube.metaclass.decorators.append(
                        manageable(channel.module, False))
                listener = cube.metaclass.build_listener(cube.content, bcc)
                if not listener.namespace:
                    listener.namespace = bcc.getDefaultNamespace()
                bcc.listeners.append(listener)
                if not cube.metaclass.inline_dispatchers:
                    logger.warning(
                        f"插件{channel._name}未使用inline_dispatchers!默认notice为False!"
                    )
                    saya_data.add_saya(channel.module, notice=False)
                else:
                    saya_data.add_saya(channel.module)
from datetime import datetime

from graia.saya import Saya, Channel
from graia.ariadne.app import Ariadne
from graia.ariadne.message.chain import MessageChain
from graia.saya.builtins.broadcast.schema import ListenerSchema
from graia.ariadne.event.message import Group, Member, GroupMessage
from graia.ariadne.message.element import ForwardNode, Plain, Forward, At

from sagiri_bot.message_sender.strategy import Normal
from sagiri_bot.decorators import switch, blacklist
from sagiri_bot.handler.handler import AbstractHandler
from sagiri_bot.message_sender.message_item import MessageItem
from sagiri_bot.message_sender.message_sender import MessageSender

saya = Saya.current()
channel = Channel.current()

channel.name("FakeForward")
channel.author("SAGIRI-kawaii")
channel.description("一个生成转发消息的插件,发送 '/fake [@目标] [内容]' 即可")


@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def fake_forward(app: Ariadne, message: MessageChain, group: Group,
                       member: Member):
    if result := await FakeForward.handle(app, message, group, member):
        await MessageSender(result.strategy).send(app, result.message, message,
                                                  group, member)

Exemple #5
0
import asyncio
from graia.saya import Saya
from graia.broadcast import Broadcast
from graia.saya.builtins.broadcast import BroadcastBehaviour
from graia.scheduler import GraiaScheduler
from graia.scheduler.saya import GraiaSchedulerBehaviour
from graia.application.entry import (
    GraiaMiraiApplication, Session
)
from utils import ModuleLoader, BotAttributes
from utils import logger

loop = asyncio.get_event_loop()
broadcast = Broadcast(loop=loop)
scheduler = GraiaScheduler(loop, broadcast)
saya = Saya(broadcast)

bot = BotAttributes("./config.json")

saya.install_behaviours(BroadcastBehaviour(broadcast))
saya.install_behaviours(GraiaSchedulerBehaviour(scheduler))

ModuleLoader.load(saya)

app = GraiaMiraiApplication(
    broadcast=broadcast,
    connect_info=Session(
        host=bot.host,
        authKey=bot.authKey,
        account=bot.account,
        websocket=True
class AppCore(object):
    """
    应用核心,用于管理所有相关组件
    """
    __instance = None
    __first_init: bool = False
    __app: Ariadne = None
    __loop: AbstractEventLoop = None
    __bcc = None
    __saya = None
    __thread_pool = None
    __config: GlobalConfig = None
    __launched: bool = False
    __exception_resender: ExceptionReSender = None
    __frequency_limit_instance: GlobalFrequencyLimitDict = None
    necessary_parameters = ["miraiHost", "verify_key", "BotQQ"]

    def __new__(cls, config: GlobalConfig):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self, config: GlobalConfig):
        if not self.__first_init:
            logger.info("Initializing")
            self.__loop = asyncio.get_event_loop()
            self.__bcc = Broadcast(loop=self.__loop)
            self.__app = Ariadne(broadcast=self.__bcc,
                                 chat_log_config=False,
                                 connect_info=DefaultAdapter(
                                     broadcast=self.__bcc,
                                     ping=False,
                                     mirai_session=MiraiSession(
                                         host=config.mirai_host,
                                         verify_key=str(config.verify_key),
                                         account=config.bot_qq),
                                 ))
            self.__saya = Saya(self.__bcc)
            self.__saya.install_behaviours(BroadcastBehaviour(self.__bcc))
            if _install_scheduler:
                self.__sche = GraiaScheduler(loop=self.__loop,
                                             broadcast=self.__bcc)
                self.__saya.install_behaviours(
                    GraiaSchedulerBehaviour(self.__sche))
            self.__app.debug = False
            self.__config = config
            AppCore.__first_init = True
            logger.info("Initialize end")
        else:
            raise AppCoreAlreadyInitialized()

    @classmethod
    def get_core_instance(cls) -> "AppCore":
        """ 获取 AppCore 实例 """
        if cls.__instance:
            return cls.__instance
        else:
            raise AppCoreNotInitialized()

    def get_bcc(self) -> Broadcast:
        """ 获取 Broadcast 实例 """
        if self.__bcc:
            return self.__bcc
        else:
            raise AppCoreNotInitialized()

    def get_loop(self) -> AbstractEventLoop:
        """ 获取 loop """
        if self.__loop:
            return self.__loop
        else:
            raise AppCoreNotInitialized()

    def get_app(self) -> Ariadne:
        """ 获取 Ariadne 实例 """
        if self.__app:
            return self.__app
        else:
            raise AppCoreNotInitialized()

    def get_saya(self) -> Saya:
        """ 获取 Saya 实例 """
        return self.__saya

    def get_config(self) -> GlobalConfig:
        """ 获取配置 """
        return self.__config

    def launch(self) -> None:
        """ 启动 Ariadne 实例 """
        if not self.__launched:
            self.__app.launch_blocking()
            self.__launched = True
        else:
            raise AriadneAlreadyLaunched()

    def get_frequency_limit_instance(self) -> GlobalFrequencyLimitDict:
        """ 返回频率限制模块实例 """
        return self.__frequency_limit_instance

    def get_exception_resender(self) -> ExceptionReSender:
        """ 返回错误重发模块实例 """
        return self.__exception_resender

    async def bot_launch_init(self) -> None:
        """ 机器人启动初始化 """
        self.config_check()
        try:
            try:
                await orm.init_check()
            except (AttributeError, InternalError, ProgrammingError):
                await orm.create_all()
            if not os.path.exists(f"{os.getcwd()}/alembic"):
                logger.info("未检测到alembic目录,进行初始化")
                os.system("alembic init alembic")
                with open(f"{os.getcwd()}/statics/alembic_env_py_content.txt",
                          "r") as r:
                    alembic_env_py_content = r.read()
                with open(f"{os.getcwd()}/alembic/env.py", "w") as w:
                    w.write(alembic_env_py_content)
                logger.warning(
                    f"请前往更改 {os.getcwd()}/alembic.ini 文件,将其中的 sqlalchemy.url 替换为自己的数据库url(不需注明引擎)后重启机器人"
                )
                exit(0)
            if not os.path.exists(f"{os.getcwd()}/alembic/versions"):
                os.mkdir(f"{os.getcwd()}/alembic/versions")
            os.system("alembic revision --autogenerate -m 'update'")
            os.system("alembic upgrade head")
            await orm.update(Setting, [], {"active": False})
            group_list = await self.__app.getGroupList()
            frequency_limit_dict = {}
            for group in group_list:
                frequency_limit_dict[group.id] = 0
                await orm.insert_or_update(Setting,
                                           [Setting.group_id == group.id], {
                                               "group_id": group.id,
                                               "group_name": group.name,
                                               "active": True
                                           })
            results = await orm.fetchall(
                select(Setting.group_id,
                       Setting.group_name).where(Setting.active == True))
            self.load_required_saya_modules()
            logger.info("本次启动活动群组如下:")
            for result in results:
                logger.info(
                    f"群ID: {str(result.group_id).ljust(14)}群名: {result.group_name}"
                )
            for result in results:
                await orm.insert_or_update(
                    UserPermission, [
                        UserPermission.member_id == self.__config.host_qq,
                        UserPermission.group_id == result[0]
                    ], {
                        "member_id": self.__config.host_qq,
                        "group_id": result[0],
                        "level": 4
                    })
            self.__frequency_limit_instance = GlobalFrequencyLimitDict(
                frequency_limit_dict)
            threading.Thread(target=frequency_limit,
                             args=(self.__frequency_limit_instance, )).start()
            exception_resender_instance = ExceptionReSender(self.__app)
            listener = threading.Thread(target=exception_resender_listener,
                                        args=(self.__app,
                                              exception_resender_instance,
                                              self.__loop))
            listener.start()
            await group_setting.data_init()
        except:
            logger.error(traceback.format_exc())
            exit(0)

    @staticmethod
    def dict_check(dictionary: dict, indent: int = 4) -> None:
        for key in dictionary.keys():
            if isinstance(dictionary[key], dict):
                logger.success(f"{' ' * indent}{key}:")
                AppCore.dict_check(dictionary[key], indent + 4)
            elif dictionary[key] == key:
                logger.warning(
                    f"{' ' * indent}Unchanged initial value detected: {key} - {dictionary[key]}"
                )
            else:
                logger.success(f"{' ' * indent}{key} - {dictionary[key]}")

    def config_check(self) -> None:
        """ 配置检查 """
        required_key = ("bot_qq", "host_qq", "mirai_host", "verify_key")
        logger.info("Start checking configuration")
        father_properties = tuple(dir(BaseModel))
        properties = [
            _ for _ in dir(self.__config)
            if _ not in father_properties and not _.startswith("_")
        ]
        for key in properties:
            value = self.__config.__getattribute__(key)
            if key in required_key and key == value:
                logger.error(
                    f"Required initial value not changed detected: {key} - {value}"
                )
                exit(0)
            elif isinstance(value, dict):
                logger.success(f"{key}:")
                self.dict_check(value)
            elif key == value:
                logger.warning(
                    f"Unchanged initial value detected: {key} - {value}")
            else:
                logger.success(f"{key} - {value}")
        logger.info("Configuration check completed")

    def load_saya_modules(self) -> None:
        """ 加载自定义 saya 模块 """
        ignore = ["__init__.py", "__pycache__"]
        with self.__saya.module_context():
            for module in os.listdir(f"modules"):
                if module in ignore:
                    continue
                try:
                    if os.path.isdir(module):
                        self.__saya.require(f"modules.{module}")
                    else:
                        self.__saya.require(f"modules.{module.split('.')[0]}")
                except ModuleNotFoundError as e:
                    logger.error(f"saya模块:{module} - {e}")

    def load_required_saya_modules(self) -> None:
        """ 加载必要 saya 模块 """
        ignore = ["__init__.py", "__pycache__"]
        with self.__saya.module_context():
            for module in os.listdir(f"sagiri_bot/handler/required_module"):
                if module in ignore:
                    continue
                try:
                    if os.path.isdir(module):
                        self.__saya.require(
                            f"sagiri_bot.handler.required_module.{module}")
                    else:
                        self.__saya.require(
                            f"sagiri_bot.handler.required_module.{module.split('.')[0]}"
                        )
                except ModuleNotFoundError as e:
                    logger.error(f"saya模块:{module} - {e}")

    def get_saya_channels(self) -> Dict[str, Channel]:
        """ 获取 saya channels """
        return self.__saya.channels

    def load_schedulers(self):
        pass
Exemple #7
0
import asyncio
import sys
from pathlib import Path

import yaml
from graia.application import GraiaMiraiApplication, Session
from graia.broadcast import Broadcast
from graia.saya import Saya
from graia.saya.builtins.broadcast import BroadcastBehaviour
from yaml.loader import SafeLoader

from utils.utils import get_all_package_name

loop = asyncio.get_event_loop()
bcc = Broadcast(loop=loop)
saya = Saya(bcc)

config_path = Path("config.yaml")
if not config_path.is_file():
    config_path.write_text(Path("config.yaml.sample").read_text())
    sys.exit(1)
config = yaml.load(config_path.read_text(), Loader=SafeLoader)

saya.install_behaviours(BroadcastBehaviour(bcc))
app = GraiaMiraiApplication(
    broadcast=bcc,
    connect_info=Session(
        host=config["mirai"]["host"],
        authKey=config["mirai"]["authKey"],
        account=config["mirai"]["account"],
        websocket=config["mirai"]["websocket"],
import asyncio

from graia.saya import Saya
from graia.broadcast import Broadcast
from graia.saya.builtins.broadcast import BroadcastBehaviour
from graia.application.entry import GraiaMiraiApplication
from config import connection_config

loop = asyncio.get_event_loop()
broadcast = Broadcast(loop=loop)
saya = Saya(broadcast)
saya.install_behaviours(BroadcastBehaviour(broadcast))

app = GraiaMiraiApplication(broadcast=broadcast,
                            connect_info=connection_config(),
                            enable_chat_log=True,
                            debug=True)

with saya.module_context():
    saya.require("modules.module_as_file")

try:
    app.launch_blocking()
except KeyboardInterrupt:
    exit()
Exemple #9
0
class AppCore:
    __instance = None
    __first_init: bool = False
    __app: GraiaMiraiApplication = None
    __loop: AbstractEventLoop = None
    __bcc = None
    __saya = None
    __thread_pool = None
    __config: dict = None
    __launched: bool = False
    __group_handler_chain = {}
    __exception_resender: ExceptionReSender = None
    __frequency_limit_instance: GlobalFrequencyLimitDict = None
    necessary_parameters = ["miraiHost", "authKey", "BotQQ"]

    def __new__(cls, config: dict):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self, config: dict):
        if not self.__first_init:
            logger.info("Initializing")
            if any(parameter not in config
                   for parameter in self.necessary_parameters):
                raise ValueError(
                    f"Missing necessary parameters! (miraiHost, authKey, BotQQ)"
                )
            self.__loop = asyncio.get_event_loop()
            self.__bcc = Broadcast(loop=self.__loop)
            self.__app = GraiaMiraiApplication(broadcast=self.__bcc,
                                               connect_info=Session(
                                                   host=config["miraiHost"],
                                                   authKey=config["authKey"],
                                                   account=config["BotQQ"],
                                                   websocket=True),
                                               enable_chat_log=False)
            self.__saya = Saya(self.__bcc)
            self.__saya.install_behaviours(BroadcastBehaviour(self.__bcc))
            self.__app.debug = False
            self.__config = config
            AppCore.__first_init = True
            logger.info("Initialize end")
        else:
            raise AppCoreAlreadyInitialized()

    @classmethod
    def get_core_instance(cls):
        if cls.__instance:
            return cls.__instance
        else:
            raise AppCoreNotInitialized()

    def get_bcc(self) -> Broadcast:
        if self.__bcc:
            return self.__bcc
        else:
            raise AppCoreNotInitialized()

    def get_loop(self) -> AbstractEventLoop:
        if self.__loop:
            return self.__loop
        else:
            raise AppCoreNotInitialized()

    def get_app(self) -> GraiaMiraiApplication:
        if self.__app:
            return self.__app
        else:
            raise AppCoreNotInitialized()

    def get_config(self):
        return self.__config

    def launch(self):
        if not self.__launched:
            self.__app.launch_blocking()
            self.__launched = True
        else:
            raise GraiaMiraiApplicationAlreadyLaunched()

    def set_group_chain(self, chains: list):
        for chain in chains:
            self.__group_handler_chain[chain.__name__] = chain

    def get_group_chains(self):
        return self.__group_handler_chain

    def get_group_chain(self, chain_name: str):
        return self.__group_handler_chain[
            chain_name] if chain_name in self.__group_handler_chain else None

    def get_frequency_limit_instance(self):
        return self.__frequency_limit_instance

    def get_exception_resender(self):
        return self.__exception_resender

    async def bot_launch_init(self):
        self.config_check()
        try:
            await orm.create_all()
            await orm.update(Setting, [], {"active": False})
            group_list = await self.__app.groupList()
            frequency_limit_dict = {}
            for group in group_list:
                frequency_limit_dict[group.id] = 0
                await orm.insert_or_update(Setting,
                                           [Setting.group_id == group.id], {
                                               "group_id": group.id,
                                               "group_name": group.name,
                                               "active": True
                                           })
            results = await orm.fetchall(
                select(Setting.group_id,
                       Setting.group_name).where(Setting.active == True))
            logger.info("本次启动活动群组如下:")
            for result in results:
                logger.info(
                    f"群ID: {str(result.group_id).ljust(14)}群名: {result.group_name}"
                )
            for result in results:
                await orm.insert_or_update(
                    UserPermission, [
                        UserPermission.member_id == self.__config["HostQQ"],
                        UserPermission.group_id == result[0]
                    ], {
                        "member_id": self.__config["HostQQ"],
                        "group_id": result[0],
                        "level": 4
                    })
            self.__frequency_limit_instance = GlobalFrequencyLimitDict(
                frequency_limit_dict)
            threading.Thread(target=frequency_limit,
                             args=(self.__frequency_limit_instance, )).start()
            exception_resender_instance = ExceptionReSender(self.__app)
            listener = threading.Thread(target=exception_resender_listener,
                                        args=(self.__app,
                                              exception_resender_instance,
                                              self.__loop))
            listener.start()
        except:
            logger.error(traceback.format_exc())
            exit()

    def config_check(self):
        logger.info("checking config")
        pic_paths = [
            "setuPath", "setu18Path", "realPath", "realHighqPath",
            "wallpaperPath", "sketchPath"
        ]
        if self.__config["HostQQ"] == 123:
            logger.warning(f"HostQQ无效,请检查配置!")
        for path in pic_paths:
            if not os.path.exists(self.__config[path]):
                logger.warning(f"{path}无效,请检查配置!")
        if self.__config["saucenaoApiKey"] == "balabala":
            logger.warning("saucenaoApiKey无效,请检查配置!")
        if self.__config["txAppId"] == "1234567890":
            logger.warning("txAppId无效,请检查配置!")
        if self.__config["txAppKey"] == "ABCDEFGHIJKLMN":
            logger.warning("txAppKey无效,请检查配置!")
        if self.__config["loliconApiKey"] == "loliconApiKey":
            logger.warning("loliconApiKey无效,请检查配置!")
        if self.__config["wolframAlphaKey"] == "wolframAlphaKey":
            logger.warning("wolframAlphaKey无效,请检查配置!")
        logger.info("check done")

    def load_saya_modules(self):
        ignore = ["__init__.py", "__pycache__"]
        with self.__saya.module_context():
            for module in os.listdir(f"modules"):
                if module in ignore:
                    continue
                try:
                    if os.path.isdir(module):
                        self.__saya.require(f"modules.{module}")
                    else:
                        self.__saya.require(f"modules.{module.split('.')[0]}")
                except ModuleNotFoundError as e:
                    logger.error(f"saya模块:{module} - {e}")

    def get_saya_channels(self):
        return self.__saya.channels

    def get_saya(self):
        return self.__saya
Exemple #10
0
from graia.saya.builtins.broadcast import BroadcastBehaviour
from . import TestSchema


class TestBehaviour(Behaviour):
    def allocate(self, content: Cube) -> Any:
        if isinstance(content.metaclass, TestSchema):
            print("cube detected", content, content.metaclass)
            return content

    def uninstall(self, cube: Cube) -> Any:
        return cube


loop = asyncio.get_event_loop()
broadcast = Broadcast(loop=loop)
saya = Saya(broadcast=broadcast)
saya.install_behaviours(TestBehaviour())
saya.install_behaviours(BroadcastBehaviour(broadcast))

with saya.module_context():
    test_sub1_export = saya.require("test.test_sub1")
    print(broadcast.listeners)
    saya.uninstall_channel(test_sub1_export)


async def do_nothing():
    pass


loop.run_until_complete(do_nothing())
Exemple #11
0
import asyncio

from graia.saya import Saya
from graia.broadcast import Broadcast
from graia.saya.builtins.broadcast import BroadcastBehaviour

loop = asyncio.get_event_loop()
broadcast = Broadcast(loop=loop)
saya = Saya(broadcast)

with saya.module_context():
    saya.require("modules.module_as_file")
    saya.require("modules.module_as_dir")

try:
    loop.run_forever()
except KeyboardInterrupt:
    exit()
import asyncio
from graia.saya import Saya
from graia.broadcast import Broadcast
from graia.saya.builtins.broadcast import BroadcastBehaviour
from graia.application import GraiaMiraiApplication, Session

from util import get_module_in_dir
import yaml
import logging
logging.basicConfig(format="[%(asctime)s][%(levelname)s]: %(message)s",
                    level=logging.INFO)

loop = asyncio.get_event_loop()
bcc = Broadcast(loop=loop)
saya = Saya(bcc)
saya.install_behaviours(BroadcastBehaviour(bcc))

with open('configs.yml', encoding='UTF-8') as f:
    configs = yaml.safe_load(f)

app = GraiaMiraiApplication(broadcast=bcc,
                            connect_info=Session(host=configs["miraiHost"],
                                                 authKey=configs["authKey"],
                                                 account=configs['account'],
                                                 websocket=True))

load_module = [
    module for folder in configs['load_folder']
    for module in get_module_in_dir(folder)
]
Exemple #13
0
 def load(cls, saya: Saya):
     modules = "modules.{}"
     with saya.module_context():
         for module_name in cls._get_module_str():
             saya.require(modules.format(module_name))
import asyncio
import os

from graia.saya import Saya
from graia.broadcast import Broadcast
from graia.saya.builtins.broadcast import BroadcastBehaviour
from graia.application import GraiaMiraiApplication, Session

from utils import load_config

loop = asyncio.get_event_loop()
bcc = Broadcast(loop=loop)
saya = Saya(bcc)
saya.install_behaviours(BroadcastBehaviour(bcc))

configs = load_config()

app = GraiaMiraiApplication(broadcast=bcc,
                            connect_info=Session(host=configs["miraiHost"],
                                                 authKey=configs["authKey"],
                                                 account=configs["BotQQ"],
                                                 websocket=True))

ignore = ["__init__.py", "__pycache__"]

with saya.module_context():
    for module in os.listdir("modules"):
        if module in ignore:
            continue
        try:
            if os.path.isdir(module):