1. 调整导入顺序和导入项顺序优化代码结构 2. 新增位置消息类型映射支持 3. 新增频道帖子事件的消息分发处理 4. 重构WebSocket认证失败日志格式 5. 优化令牌刷新错误提示的换行格式 6. 简化事件队列满时的日志输出 7. 新增系统事件处理和打字状态上报支持 8. 实现打字指示器接口的实际调用逻辑 9. 更新通道能力配置,补充缺失的能力项
171 lines
5.6 KiB
Python
171 lines
5.6 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
import aiohttp
|
|
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
|
|
@dataclass
|
|
class PeerInfo:
|
|
open_id: str
|
|
username: str = ""
|
|
avatar_url: str = ""
|
|
display_name: str = ""
|
|
|
|
|
|
@dataclass
|
|
class GroupInfo:
|
|
group_open_id: str
|
|
name: str = ""
|
|
avatar_url: str = ""
|
|
member_count: int = 0
|
|
bot_is_member: bool = False
|
|
|
|
|
|
@dataclass
|
|
class DirectoryResult:
|
|
peers: list[PeerInfo] = field(default_factory=list)
|
|
groups: list[GroupInfo] = field(default_factory=list)
|
|
|
|
|
|
async def get_user_info(
|
|
api_base: str,
|
|
token: str,
|
|
http_client: aiohttp.ClientSession,
|
|
user_id: str,
|
|
) -> PeerInfo | None:
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{api_base}/api/v1/user/{user_id}"
|
|
|
|
try:
|
|
async with http_client.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
if resp.status == 200:
|
|
data = await resp.json()
|
|
return PeerInfo(
|
|
open_id=data.get("open_id", user_id),
|
|
username=data.get("username", ""),
|
|
avatar_url=data.get("avatar_url", ""),
|
|
display_name=data.get("display_name", ""),
|
|
)
|
|
else:
|
|
logger.debug(f"[Yuanbao] get_user_info returned {resp.status} for {user_id}")
|
|
return None
|
|
except Exception as e:
|
|
logger.warning(f"[Yuanbao] Failed to get user info for {user_id}: {e}")
|
|
return None
|
|
|
|
|
|
async def get_group_list(
|
|
api_base: str,
|
|
token: str,
|
|
http_client: aiohttp.ClientSession,
|
|
) -> list[GroupInfo]:
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{api_base}/api/v1/bot/groups"
|
|
|
|
try:
|
|
async with http_client.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
if resp.status == 200:
|
|
data = await resp.json()
|
|
groups = []
|
|
for g in data.get("groups", []):
|
|
groups.append(
|
|
GroupInfo(
|
|
group_open_id=g.get("group_open_id", ""),
|
|
name=g.get("group_name", ""),
|
|
avatar_url=g.get("avatar_url", ""),
|
|
member_count=g.get("member_count", 0),
|
|
bot_is_member=g.get("bot_is_member", False),
|
|
)
|
|
)
|
|
logger.info(f"[Yuanbao] Fetched {len(groups)} groups")
|
|
return groups
|
|
else:
|
|
logger.warning(f"[Yuanbao] get_group_list returned {resp.status}")
|
|
return []
|
|
except Exception as e:
|
|
logger.warning(f"[Yuanbao] Failed to get group list: {e}")
|
|
return []
|
|
|
|
|
|
async def get_group_detail(
|
|
api_base: str,
|
|
token: str,
|
|
http_client: aiohttp.ClientSession,
|
|
group_open_id: str,
|
|
) -> GroupInfo | None:
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{api_base}/api/v1/bot/groups/{group_open_id}"
|
|
|
|
try:
|
|
async with http_client.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
if resp.status == 200:
|
|
data = await resp.json()
|
|
return GroupInfo(
|
|
group_open_id=data.get("group_open_id", group_open_id),
|
|
name=data.get("group_name", ""),
|
|
avatar_url=data.get("avatar_url", ""),
|
|
member_count=data.get("member_count", 0),
|
|
bot_is_member=data.get("bot_is_member", False),
|
|
)
|
|
else:
|
|
logger.debug(f"[Yuanbao] get_group_detail returned {resp.status} for {group_open_id}")
|
|
return None
|
|
except Exception as e:
|
|
logger.warning(f"[Yuanbao] Failed to get group detail for {group_open_id}: {e}")
|
|
return None
|
|
|
|
|
|
async def get_group_members(
|
|
api_base: str,
|
|
token: str,
|
|
http_client: aiohttp.ClientSession,
|
|
group_open_id: str,
|
|
) -> list[PeerInfo]:
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{api_base}/api/v1/bot/groups/{group_open_id}/members"
|
|
|
|
try:
|
|
async with http_client.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
if resp.status == 200:
|
|
data = await resp.json()
|
|
members = []
|
|
for m in data.get("members", []):
|
|
members.append(
|
|
PeerInfo(
|
|
open_id=m.get("open_id", ""),
|
|
username=m.get("username", ""),
|
|
avatar_url=m.get("avatar_url", ""),
|
|
display_name=m.get("display_name", ""),
|
|
)
|
|
)
|
|
logger.info(f"[Yuanbao] Fetched {len(members)} members from group {group_open_id}")
|
|
return members
|
|
else:
|
|
logger.warning(f"[Yuanbao] get_group_members returned {resp.status} for {group_open_id}")
|
|
return []
|
|
except Exception as e:
|
|
logger.warning(f"[Yuanbao] Failed to get group members for {group_open_id}: {e}")
|
|
return []
|
|
|
|
|
|
async def list_directory(
|
|
api_base: str,
|
|
token: str,
|
|
http_client: aiohttp.ClientSession,
|
|
user_ids: list[str] | None = None,
|
|
) -> DirectoryResult:
|
|
result = DirectoryResult()
|
|
|
|
result.groups = await get_group_list(api_base, token, http_client)
|
|
|
|
if user_ids:
|
|
for user_id in user_ids:
|
|
peer = await get_user_info(api_base, token, http_client, user_id)
|
|
if peer:
|
|
result.peers.append(peer)
|
|
|
|
return result
|