mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-28 08:12:14 +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 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user