add call_api and implement send func

This commit is contained in:
StarHeartHunt 2021-07-05 11:08:24 +08:00
parent 33bd7582be
commit 0c39300f4b

View File

@ -1,6 +1,7 @@
import json import json
import httpx
from typing import Any, Tuple, Union, Optional, TYPE_CHECKING from typing import Any, Dict, Tuple, Union, Optional, TYPE_CHECKING
from nonebot.log import logger from nonebot.log import logger
from nonebot.typing import overrides from nonebot.typing import overrides
@ -9,7 +10,8 @@ from nonebot.adapters import Bot as BaseBot
from nonebot.drivers import Driver, HTTPRequest, HTTPResponse from nonebot.drivers import Driver, HTTPRequest, HTTPResponse
from .config import Config as FeishuConfig from .config import Config as FeishuConfig
from .event import Event, get_event_model from .event import Event, GroupMessageEvent, get_event_model
from .exception import ActionFailed, ApiNotAvailable, NetworkError
from .message import Message, MessageSegment from .message import Message, MessageSegment
from .utils import log, AESCipher from .utils import log, AESCipher
@ -59,6 +61,30 @@ def _check_nickname(bot: "Bot", event: "Event"):
... ...
def _handle_api_result(result: Optional[Dict[str, Any]]) -> Any:
"""
:说明:
处理 API 请求返回值
:参数:
* ``result: Optional[Dict[str, Any]]``: API 返回数据
:返回:
- ``Any``: API 调用返回数据
:异常:
- ``ActionFailed``: API 调用失败
"""
if isinstance(result, dict):
if result.get("code") != 0:
raise ActionFailed(**result)
return result.get("data")
class Bot(BaseBot): class Bot(BaseBot):
""" """
飞书 协议 Bot 适配继承属性参考 `BaseBot <./#class-basebot>`_ 。 飞书 协议 Bot 适配继承属性参考 `BaseBot <./#class-basebot>`_ 。
@ -68,6 +94,10 @@ class Bot(BaseBot):
def type(self) -> str: def type(self) -> str:
return "feishu" return "feishu"
@property
def api_root(self) -> str:
return "https://open.feishu.cn/open-apis/"
@classmethod @classmethod
def register(cls, driver: Driver, config: "Config"): def register(cls, driver: Driver, config: "Config"):
super().register(driver, config) super().register(driver, config)
@ -134,6 +164,10 @@ class Bot(BaseBot):
try: try:
header = data["header"] header = data["header"]
event_type = header["event_type"] event_type = header["event_type"]
if data.get("event"):
if data["event"].get("message"):
event_type += f".{data['event']['message']['chat_type']}"
models = get_event_model(event_type) models = get_event_model(event_type)
for model in models: for model in models:
try: try:
@ -149,10 +183,105 @@ class Bot(BaseBot):
f"<r><bg #f8bbd0>Failed to handle event. Raw: {message}</bg #f8bbd0></r>" f"<r><bg #f8bbd0>Failed to handle event. Raw: {message}</bg #f8bbd0></r>"
) )
async def _call_api(self, api: str, **data) -> Any: def _construct_url(self, path: str) -> str:
raise NotImplementedError return self.api_root + path
async def _fetch_tenant_access_token(self) -> str:
try:
async with httpx.AsyncClient() as client:
response = await client.post(
self._construct_url(
"auth/v3/tenant_access_token/internal/"),
json={
"app_id": self.feishu_config.app_id,
"app_secret": self.feishu_config.app_secret
},
timeout=self.config.api_timeout)
if 200 <= response.status_code < 300:
result = response.json()
return result["tenant_access_token"]
else:
raise NetworkError(f"HTTP request received unexpected "
f"status code: {response.status_code}")
except httpx.InvalidURL:
raise NetworkError("API root url invalid")
except httpx.HTTPError:
raise NetworkError("HTTP request failed")
@overrides(BaseBot)
async def _call_api(self, api: str, **data) -> Any:
log("DEBUG", f"Calling API <y>{api}</y>")
if isinstance(self.request, HTTPRequest):
if not self.api_root:
raise ApiNotAvailable
headers = {}
if self.feishu_config.tenant_access_token is None:
self.feishu_config.tenant_access_token = await self._fetch_tenant_access_token(
)
headers[
"Authorization"] = "Bearer " + self.feishu_config.tenant_access_token
try:
print(data)
async with httpx.AsyncClient(headers=headers) as client:
response = await client.post(
self.api_root + api,
json=data,
timeout=self.config.api_timeout)
print(response.json())
if 200 <= response.status_code < 300:
result = response.json()
return _handle_api_result(result)
raise NetworkError(f"HTTP request received unexpected "
f"status code: {response.status_code}")
except httpx.InvalidURL:
raise NetworkError("API root url invalid")
except httpx.HTTPError:
raise NetworkError("HTTP request failed")
@overrides(BaseBot)
async def call_api(self, api: str, **data) -> Any:
"""
:说明:
调用 飞书 协议 API
:参数:
* ``api: str``: API 名称
* ``**data: Any``: API 参数
:返回:
- ``Any``: API 调用返回数据
:异常:
- ``NetworkError``: 网络错误
- ``ActionFailed``: API 调用失败
"""
return await super().call_api(api, **data)
@overrides(BaseBot)
async def send(self, event: Event, message: Union[str, Message, async def send(self, event: Event, message: Union[str, Message,
MessageSegment], MessageSegment],
**kwargs) -> Any: **kwargs) -> Any:
raise NotImplementedError msg = message if isinstance(message, Message) else Message(message)
params = {
"receive_id":
event.event.message.chat_id if isinstance(
event, GroupMessageEvent) else event.get_user_id(),
"content":
str(message),
"msg_type":
"text" if len(message) == 1 else "content"
}
receive_id_type = 'chat_id' if isinstance(
event, GroupMessageEvent) else 'union_id'
return await self.call_api(
f"im/v1/messages?receive_id_type={receive_id_type}", **params)