mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-24 17:15:05 +08:00
✨ add call_api
and implement send
func
This commit is contained in:
parent
33bd7582be
commit
0c39300f4b
@ -1,6 +1,7 @@
|
||||
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.typing import overrides
|
||||
@ -9,7 +10,8 @@ from nonebot.adapters import Bot as BaseBot
|
||||
from nonebot.drivers import Driver, HTTPRequest, HTTPResponse
|
||||
|
||||
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 .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):
|
||||
"""
|
||||
飞书 协议 Bot 适配。继承属性参考 `BaseBot <./#class-basebot>`_ 。
|
||||
@ -68,6 +94,10 @@ class Bot(BaseBot):
|
||||
def type(self) -> str:
|
||||
return "feishu"
|
||||
|
||||
@property
|
||||
def api_root(self) -> str:
|
||||
return "https://open.feishu.cn/open-apis/"
|
||||
|
||||
@classmethod
|
||||
def register(cls, driver: Driver, config: "Config"):
|
||||
super().register(driver, config)
|
||||
@ -134,6 +164,10 @@ class Bot(BaseBot):
|
||||
try:
|
||||
header = data["header"]
|
||||
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)
|
||||
for model in models:
|
||||
try:
|
||||
@ -149,10 +183,105 @@ class Bot(BaseBot):
|
||||
f"<r><bg #f8bbd0>Failed to handle event. Raw: {message}</bg #f8bbd0></r>"
|
||||
)
|
||||
|
||||
async def _call_api(self, api: str, **data) -> Any:
|
||||
raise NotImplementedError
|
||||
def _construct_url(self, path: str) -> str:
|
||||
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,
|
||||
MessageSegment],
|
||||
**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)
|
||||
|
Loading…
Reference in New Issue
Block a user