ForcePilot/backend/package/yuxi/channels/adapters/urbit/invites.py
Kris 80e3f66974 refactor(urbit): 整理导入顺序并修复多处代码细节
1.  统一调整多个文件的导入排序,将TYPE_CHECKING相关导入放在正确位置
2.  修复rate_limiter中当限制数<=0时直接返回false的逻辑
3.  为message_cache新增更新消息内容的方法
4.  重构extract_graph_content支持日记类型内容提取
5.  调整@提及匹配的正则表达式,避免误匹配
6.  完善invite_manager,添加客户端和凭据支持并实现自动接受群邀请逻辑
7.  调整adapter.py中的导入顺序和初始化逻辑
8.  修复monitor中的编辑事件处理,改为异步处理并实现消息更新缓存
9.  调整datetime导入顺序,统一使用UTC在前的格式
2026-05-13 16:16:27 +08:00

121 lines
4.3 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, Any
from yuxi.utils.logging_config import logger
if TYPE_CHECKING:
from .client import UrbitClient
class InviteManager:
def __init__(
self,
auto_accept_groups: bool = False,
group_invite_allowlist: list[str] | None = None,
auto_accept_dm: bool = False,
dm_allowlist: list[str] | None = None,
client: UrbitClient | None = None,
ship_name: str = "",
ship_code: str = "",
):
self.auto_accept_groups = auto_accept_groups
self.group_invite_allowlist = [s.lstrip("~").lower() for s in (group_invite_allowlist or [])]
self.auto_accept_dm = auto_accept_dm
self.dm_allowlist = [s.lstrip("~").lower() for s in (dm_allowlist or [])]
self._pending_invites: dict[str, dict[str, Any]] = {}
self._client = client
self._ship_name = ship_name
self._ship_code = ship_code
def should_auto_accept_group_invite(self, inviter_ship: str) -> bool:
if not self.auto_accept_groups:
return False
ship = inviter_ship.lstrip("~").lower()
if not self.group_invite_allowlist:
return False
return ship in self.group_invite_allowlist
def should_auto_accept_dm(self, inviter_ship: str) -> bool:
if not self.auto_accept_dm:
return False
ship = inviter_ship.lstrip("~").lower()
if not self.dm_allowlist:
return False
return ship in self.dm_allowlist
async def handle_foreign_update(self, foreign_update: dict[str, Any]) -> dict[str, Any] | None:
group = foreign_update.get("group", "")
ship = foreign_update.get("ship", "").lstrip("~")
join = foreign_update.get("join", False)
if not group or not ship:
return None
invite_id = f"{group}:{ship}"
if join:
self._pending_invites[invite_id] = foreign_update
if self.should_auto_accept_group_invite(ship):
logger.info(f"[Urbit] Auto-accepting group invite from ~{ship} for {group}")
await self._accept_invite(group, ship)
self._pending_invites.pop(invite_id, None)
return {"action": "auto_accepted", "group": group, "ship": ship}
logger.info(f"[Urbit] Group invite pending: {group} from ~{ship}")
return {"action": "pending", "group": group, "ship": ship, "invite_id": invite_id}
if not join and invite_id in self._pending_invites:
self._pending_invites.pop(invite_id, None)
logger.info(f"[Urbit] Ship ~{ship} left {group}, invite resolved")
return {"action": "left", "group": group, "ship": ship}
async def _accept_invite(self, group: str, inviter: str) -> None:
if not self._client:
logger.warning(f"[Urbit] Cannot accept group invite {group} from ~{inviter}: client not available")
return
logger.info(f"[Urbit] Accepting group invite: {group} from ~{inviter}")
try:
payload = {
"action": "poke",
"ship": self._ship_name,
"app": "groups",
"mark": "groups-action",
"json": {
"join": {
"group": group,
"ship": f"~{inviter.lstrip('~')}",
}
},
}
r = await self._client.put(
"/~/channel/groups-0",
json=payload,
timeout=10.0,
)
if r.status_code == 401 and self._ship_code:
from .auth import refresh_session_if_needed
await refresh_session_if_needed(self._client, self._ship_code)
payload["ship"] = self._client.ship_name
r = await self._client.put(
"/~/channel/groups-0",
json=payload,
timeout=10.0,
)
r.raise_for_status()
logger.info(f"[Urbit] Successfully accepted group invite: {group}")
except Exception as e:
logger.error(f"[Urbit] Failed to accept group invite {group} from ~{inviter}: {e}")
def get_pending_invites(self) -> list[dict[str, Any]]:
return list(self._pending_invites.values())