Skip to content

Commit

Permalink
feat: SDK支持Async
Browse files Browse the repository at this point in the history
* [feat]sdk异步化,重构session pool逻辑

* [feat]sdk异步化,新增async模块增加异步的逻辑

* [feat]sdk异步化,增加一些错误处理

* [feat]sdk异步化,增加一些错误处理

* [feat]sdk异步化,完成websocket的部分

* [feat]sdk异步化,完成websocket的部分

* [feat]sdk异化,完成http部分

* [fix]sdk异步化,删除loop.close

* [fix]sdk异步化,重构代码目录

* [feat]sdk异步化,增加一些错误处理

* [fix]sdk异步化,新增async api模块,增加单元测试

* [feat]sdk异步化,删除loop.close

* [feat]sdk异步化,重构代码目录

* [feat]sdk异步化,增加一些错误处理

* [feat]sdk异步化,新增async api模块,增加单元测试

* [feat]sdk异步化,修改文档

* [feat]sdk异步化,解决内存泄漏的问题

* [feat]sdk异步化,解决内存泄漏的问题

* [feat]sdk异步化,解决内存泄漏的问题

* [feat]sdk异步化,解决链接超过一定时间失败的问题

* [fix]增加异步ws断连的问题

* [doc]修改setup的项目地址和描述

Co-authored-by: veehou <veehou@tencent.com>
Co-authored-by: chukuanli <chukuanli@tencent.com>
  • Loading branch information
3 people committed Jan 13, 2022
1 parent f9f9962 commit 44473de
Show file tree
Hide file tree
Showing 37 changed files with 2,250 additions and 623 deletions.
3 changes: 2 additions & 1 deletion .flake8
Expand Up @@ -3,12 +3,13 @@ ignore =
;W503 line break before binary operator
W503,
;E203 whitespace before ':'
E203,
E203

; exclude file
exclude =
.tox,
.git,
__init__.py,
__pycache__,
build,
dist,
Expand Down
47 changes: 45 additions & 2 deletions README.md
Expand Up @@ -38,12 +38,28 @@ import qqbot
import qqbot

token = qqbot.Token("{appid}","{token}")
api = qqbot.UserAPITestCase(token, False)
api = qqbot.UserAPI(token, False)

user = api.me()

print(user.username) # 打印机器人名字
```

async 示例:

``` py
import qqbot

token = qqbot.Token("{appid}","{token}")
api = qqbot.AsyncUserAPI(token, False)

# 获取loop
loop = asyncio.get_event_loop()
user = loop.run_until_complete(api.me())

print(user.username) # 打印机器人名字
```

## qqbot-事件监听

异步模块基于 websocket 技术用于监听频道内的相关事件,如消息、成员变化等事件,用于开发者对事件进行相应的处理。
Expand Down Expand Up @@ -78,7 +94,34 @@ print(user.username) # 打印机器人名字
msg_api.post_message(message.channel_id, send)
```

注:当前支持事件及回调数据对象为:
- async 示例:

``` py
# async的异步接口的使用示例
t_token = qqbot.Token(test_config["token"]["appid"], test_config["token"]["token"])
qqbot_handler = qqbot.Handler(qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler)
qqbot.async_listen_events(t_token, False, qqbot_handler)
```
``` py
async def _message_handler(event, message: qqbot.Message):
"""
定义事件回调的处理
:param event: 事件类型
:param message: 事件对象(如监听消息是Message对象)
"""
msg_api = qqbot.AsyncMessageAPI(t_token, False)
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
for i in range(5):
await asyncio.sleep(5)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油 " % message.author.id, message.id)
# 通过api发送回复消息
await msg_api.post_message(message.channel_id, send)

```
- 注:当前支持事件及回调数据对象为:

``` py
class HandlerType(Enum):
Expand Down
201 changes: 151 additions & 50 deletions README.rst
Expand Up @@ -2,26 +2,30 @@ qq-bot-python
=============

sdk安装
=======
-------

外发版本通过下面方式安装

.. code:: bash
pip install qq-bot
pip install qq-bot # 注意是 qq-bot 而不是 qqbot!
更新包的话需要添加 ``--upgrade`` ``注:需要python3.7+``

sdk使用
=======
-------

需要使用的地方import SDK

.. code:: python
import qqbot
示例机器人
----------

```examples`` <./examples/>`__ 目录下存放示例机器人,可供实现参考。

qqbot-API
---------

Expand All @@ -41,11 +45,27 @@ qqbot-API
import qqbot
token = qqbot.Token("{appid}","{token}")
api = qqbot.UserAPITestCase(token, False)
api = qqbot.UserAPI(token, False)
user = api.me()
print(user.username) # 打印机器人名字
async 示例:

.. code:: py
import qqbot
token = qqbot.Token("{appid}","{token}")
api = qqbot.AsyncUserAPI(token, False)
# 获取loop
loop = asyncio.get_event_loop()
user = loop.run_until_complete(api.me())
print(user.username) # 打印机器人名字
qqbot-事件监听
--------------

Expand All @@ -62,59 +82,89 @@ qqbot-事件监听
比如下面这个例子:需要监听机器人被@后消息并进行相应的回复。

- 先初始化需要用的 ``token`` 对象

- 通过 ``qqbot.listen_events`` 注册需要监听的事件

- 通过 ``qqbot.HandlerType``
定义需要监听的事件(部分事件可能需要权限申请)

.. code:: py
.. code:: py
t_token = qqbot.Token(test_config["token"]["appid"], test_config["token"]["token"])
# 注册事件类型和回调,可以注册多个
qqbot_handler = qqbot.Handler(qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler)
qqbot.listen_events(t_token, False, qqbot_handler)
t_token = qqbot.Token(test_config["token"]["appid"], test_config["token"]["token"])
# 注册事件类型和回调,可以注册多个
qqbot_handler = qqbot.Handler(qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler)
qqbot.listen_events(t_token, False, qqbot_handler)
- 最后定义注册事件回调执行函数,如 ``_message_handler`` 。

.. code:: py
def _message_handler(event, message: Message):
msg_api = qqbot.MessageAPI(t_token, False)
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油" % message.author.id, message.id)
# 通过api发送回复消息
msg_api.post_message(message.channel_id, send)
注:当前支持事件及回调数据对象为:

.. code:: py
class HandlerType(Enum):
PLAIN_EVENT_HANDLER = 0 #透传事件
GUILD_EVENT_HANDLER = 1 #频道事件
GUILD_MEMBER_EVENT_HANDLER = 2 #频道成员事件
CHANNEL_EVENT_HANDLER = 3 #子频道事件
MESSAGE_EVENT_HANDLER = 4 #消息事件
AT_MESSAGE_EVENT_HANDLER = 5 #At消息事件
# DIRECT_MESSAGE_EVENT_HANDLER = 6 #私信消息事件
# AUDIO_EVENT_HANDLER = 7 #音频事件
事件回调函数的参数 1 为事件名称,参数 2 返回具体的数据对象。

.. code:: py
#透传事件(无具体的数据对象,根据后台返回Json对象)
def _plain_handler(event, data):
#频道事件
def _guild_handler(event, guild:Guild):
#频道成员事件
def _guild_member_handler(event, guild_member: GuildMember):
#子频道事件
def _channel_handler(event, channel: Channel):
#消息事件 #At消息事件
def _message_handler(event, message: Message):
.. code:: py
def _message_handler(event, message: Message):
msg_api = qqbot.MessageAPI(t_token, False)
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油" % message.author.id, message.id)
# 通过api发送回复消息
msg_api.post_message(message.channel_id, send)
- async 示例:

.. code:: py
# async的异步接口的使用示例
t_token = qqbot.Token(test_config["token"]["appid"], test_config["token"]["token"])
qqbot_handler = qqbot.Handler(qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler)
qqbot.async_listen_events(t_token, False, qqbot_handler)
.. code:: py
async def _message_handler(event, message: qqbot.Message):
"""
定义事件回调的处理
:param event: 事件类型
:param message: 事件对象(如监听消息是Message对象)
"""
msg_api = qqbot.AsyncMessageAPI(t_token, False)
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
for i in range(5):
await asyncio.sleep(5)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油 " % message.author.id, message.id)
# 通过api发送回复消息
await msg_api.post_message(message.channel_id, send)
- 注:当前支持事件及回调数据对象为:

.. code:: py
class HandlerType(Enum):
PLAIN_EVENT_HANDLER = 0 # 透传事件
GUILD_EVENT_HANDLER = 1 # 频道事件
GUILD_MEMBER_EVENT_HANDLER = 2 # 频道成员事件
CHANNEL_EVENT_HANDLER = 3 # 子频道事件
MESSAGE_EVENT_HANDLER = 4 # 消息事件
AT_MESSAGE_EVENT_HANDLER = 5 # At消息事件
# DIRECT_MESSAGE_EVENT_HANDLER = 6 # 私信消息事件
# AUDIO_EVENT_HANDLER = 7 # 音频事件
事件回调函数的参数 1 为事件名称,参数 2 返回具体的数据对象。

.. code:: py
# 透传事件(无具体的数据对象,根据后台返回Json对象)
def _plain_handler(event, data):
# 频道事件
def _guild_handler(event, guild:Guild):
# 频道成员事件
def _guild_member_handler(event, guild_member: GuildMember):
# 子频道事件
def _channel_handler(event, channel: Channel):
# 消息事件
# At消息事件
def _message_handler(event, message: Message):
日志打印
--------
Expand Down Expand Up @@ -177,3 +227,54 @@ NOTSET 0
export QQBOT_DISABLE_LOG=1 # 1表示禁用日志
sdk开发
=======

环境配置
--------

.. code:: bash
pip install -r requirements.txt # 安装依赖的pip包
pre-commit install # 安装格式化代码的钩子
python3 setup.py sdist bdist_wheel # 打包SDK
单元测试
--------

代码库提供API接口测试和 websocket 的单测用例,位于 ``tests``
目录中。如果需要自己运行,可以在 ``tests`` 目录重命名 ``.test.yaml``
文件后添加自己的测试参数启动测试:

.. code:: yaml
# test yaml 用于设置test相关的参数,开源版本需要去掉参数
token:
appid: "xxx"
token: "xxxxx"
test_params:
guild_id: "xx"
guild_owner_id: "xx"
guild_owner_name: "xx"
guild_test_member_id: "xx"
guild_test_role_id: "xx"
channel_id: "xx"
channel_name: "xx"
robot_name: "xxx"
is_sandbox: False
单测执行方法:

先确保已安装 ``pytest`` :

.. code:: bash
pip install pytest
然后在项目根目录下执行单测:

.. code:: bash
pytest
10 changes: 8 additions & 2 deletions examples/run_websocket.py
Expand Up @@ -19,7 +19,7 @@ def _message_handler(event, message: qqbot.Message):
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油" % message.author.id, message.id)
send = qqbot.MessageSendRequest("收到你的消息: %s" % message.content)
# 通过api发送回复消息
msg_api.post_message(message.channel_id, send)

Expand All @@ -35,7 +35,7 @@ def _direct_message_handler(event, message: qqbot.Message):
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油" % message.author.id, message.id)
send = qqbot.MessageSendRequest("收到你的私信消息了:%s" % message.content, message.id)
# 通过api发送回复消息
msg_api.post_direct_message(message.guild_id, send)

Expand All @@ -46,3 +46,9 @@ def _direct_message_handler(event, message: qqbot.Message):
qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler
)
qqbot.listen_events(t_token, False, qqbot_handler)

# # 多事件监听
# qqbot_dms_handler = qqbot.Handler(
# qqbot.HandlerType.DIRECT_MESSAGE_EVENT_HANDLER, _direct_message_handler
# )
# qqbot.listen_events(t_token, False, qqbot_handler, qqbot_dms_handler)
36 changes: 36 additions & 0 deletions examples/run_websocket_async.py
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
import os.path

import qqbot
from qqbot.core.util.yaml_util import YamlUtil

test_config = YamlUtil.read(os.path.join(os.path.dirname(__file__), "config.yaml"))


async def _message_handler(event, message: qqbot.Message):
"""
定义事件回调的处理
:param event: 事件类型
:param message: 事件对象(如监听消息是Message对象)
"""
msg_api = qqbot.AsyncMessageAPI(t_token, False)
# 打印返回信息
qqbot.logger.info("event %s" % event + ",receive message %s" % message.content)
for i in range(5):
await asyncio.sleep(5)
# 构造消息发送请求数据对象
send = qqbot.MessageSendRequest("<@%s>谢谢你,加油 " % message.author.id, message.id)
# 通过api发送回复消息
await msg_api.post_message(message.channel_id, send)


if __name__ == "__main__":
# async的异步接口的使用示例
t_token = qqbot.Token(test_config["token"]["appid"], test_config["token"]["token"])
qqbot_handler = qqbot.Handler(
qqbot.HandlerType.AT_MESSAGE_EVENT_HANDLER, _message_handler
)
qqbot.async_listen_events(t_token, False, qqbot_handler)

0 comments on commit 44473de

Please sign in to comment.