python-cqhttp icon indicating copy to clipboard operation
python-cqhttp copied to clipboard

功能请求: Python SDK退出功能和手动绑定、解绑处理函数的功能

Open SuperMarioSF opened this issue 6 years ago • 2 comments

由于一些需求,我需要能够在Python SDK中手动通过CQHttp类的方法来绑定和解绑处理函数,并且无法使用装饰器。 此外,由于相同的需求,我需要能够正确停止掉Python SDK的全部线程。目前是一旦初始化CQHttp对象并调用了run()方法,Bottle总是会有一个线程在后面持续运行不退出,结果导致必须按Ctrl+C终止。

以下是一些方法命名与参数的建议,如果起名困难的话可以参考一下这里。 更新: 重新阅读源码之后发现给出的建议参数列表中有一些不妥之处,已修改。

from typing import Callable, Iterable

class CQHttp(...):
    # 停止本地SDK的线程,如需重新启动bot则需重新启动CQHttp.run()。
    def sdk_local_stop() -> None:
        pass

    # 通过方法注册处理函数
    def set_handler(post_type: str, handler: Callable, types: Iterable=None) -> None:
        pass

    # 通过方法解除已经注册的函数
    def unset_handler(post_type: str, types: Iterable=None) -> None:
        pass

感谢你对本功能请求的关注。

SuperMarioSF avatar May 03 '18 16:05 SuperMarioSF

于是试着实现了一下关于手动注册与解除注册处理函数的功能,可供参考。

from functools import wraps
from cqhttp import CQHttp as _CQHttp
from typing import Callable, Iterable

class CQHttp(_CQHttp):
    def set_handler(self, post_type: str,  func: Callable, types: Iterable=None):
        """
        设置回调处理函数

        --------------

        通常可以用 **@self.on_message** 、 **@self.on_request** 、 **@self.on_event** 这几个装饰器来设定回调函数,但在不允许使用装饰器的情况下,可以使用本方法设定回调函数。
        每个上报类型的每个特定信息类型只能设置一个处理函数。

        --------------

        :param str post_type: 上报类型,以下三者其一:"message"、"request"、"event"
        :param Callable func: 指定处理函数
        :param Iterable | None types: 信息类型。详情参见API文档中的消息与事件类型。默认为空,为空时注册该函数处理全部类型。
        :return: None
        """
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)

        if types:
            for t in types:
                self._handlers[post_type][t] = wrapper
        else:
            self._handlers[post_type]['*'] = wrapper

    def unset_handler(self, post_type: str, types: Iterable = None):
        """
        删除回调处理函数

        --------------

        解除注册指定上报类型的回调函数。
        如果指定了信息类型,则只会解除所请求的信息类型的回调函数的注册。

        **注意**: 如果要单独解除默认监听全部信息类型的回调函数的注册,请指定 **['*']** 。如果不指定事件类型,将会解除整个上报类型的全部回调函数的注册。

        --------------

        :param str post_type: 上报类型,以下三者其一:"message"、"request"、"event"
        :param Iterable | None types: 信息类型。详情参见API文档中的消息与事件类型。默认为空,为空时解除整个上报类型的全部回调函数的注册。
        :return: None
        """

        if types:
            for t in types:
                self._handlers[post_type].pop(t)
            if len(self._handlers[post_type]) == 0:
                self._handlers.pop(post_type)
        else:
            self._handlers.pop(post_type)

SuperMarioSF avatar May 03 '18 16:05 SuperMarioSF

关于关闭服务器的问题,我在 SDK v1.2.1 给 CQHttp 的实例增加了 wsgi 属性用于获取内部 WSGI 兼容的 app 对象,然后可以用 WSGI 服务器来部署,例如 CherryPy:

# deploy.py

from cherrypy import wsgiserver
from .demo import bot

d = wsgiserver.WSGIPathInfoDispatcher({'/': bot.wsgi})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d)

if __name__ == '__main__':
   try:
      server.start()
   except KeyboardInterrupt:
      server.stop()

这里 CherryPy 是支持从其它地方来关闭服务器的。除此之外还可以用 Gunicorn 等。


手动注册处理函数这个我再考虑考虑。

stdrc avatar Jun 02 '18 15:06 stdrc