ForcePilot/backend/package/yuxi/channels/adapters/urbit/discovery.py
Kris 1f78c44b03 refactor: 整理并清理项目中的冗余代码与格式问题
这是一个批量整理提交,包含以下主要改动:
1.  删除多处冗余的空行和未使用的导入
2.  修复文件末尾缺少换行符的问题
3.  调整部分模块的导入顺序与代码排版
4.  修复部分配置默认值与策略逻辑
5.  新增多个功能模块与辅助工具
6.  完善异常处理与日志记录
7.  修复速率限制、消息缓存、权限校验等逻辑bug
8.  废弃部分旧有API与配置项并添加警告提示
2026-05-12 14:51:53 +08:00

120 lines
4.5 KiB
Python

from __future__ import annotations
import asyncio
from typing import TYPE_CHECKING
from yuxi.utils.logging_config import logger
from .scry import scry_groups_init
if TYPE_CHECKING:
from .client import UrbitClient
from .settings import SettingsStore
_DISCOVERY_INTERVAL = 120.0
class ChannelDiscovery:
def __init__(
self,
client: UrbitClient,
auto_discover: bool = False,
group_channels: list[str] | None = None,
settings_store: SettingsStore | None = None,
):
self._client = client
self._auto_discover = auto_discover
self._group_channels = set(group_channels or [])
self._discovered_channels: set[str] = set()
self._refresh_task: asyncio.Task | None = None
self._on_new_channel: asyncio.Event | None = None
self._settings_store = settings_store
@property
def channels(self) -> set[str]:
return self._discovered_channels | self._group_channels
async def start(self) -> set[str]:
if self._group_channels:
self._discovered_channels = set(self._group_channels)
if self._settings_store:
store_group_channels = self._settings_store.get("groupChannels", [])
if isinstance(store_group_channels, list) and store_group_channels:
self._discovered_channels |= set(store_group_channels)
logger.info(f"[Urbit] Merged {len(store_group_channels)} channels from Settings Store")
if self._auto_discover:
discovered = await self.discover_channels()
self._discovered_channels |= discovered
self._refresh_task = asyncio.create_task(self._refresh_loop())
channels = self.channels
logger.info(f"[Urbit] Channel discovery started: {len(channels)} channels")
return channels
async def stop(self) -> None:
if self._refresh_task and not self._refresh_task.done():
self._refresh_task.cancel()
try:
await self._refresh_task
except asyncio.CancelledError:
pass
self._refresh_task = None
logger.info("[Urbit] Channel discovery stopped")
async def discover_channels(self) -> set[str]:
discovered: set[str] = set()
try:
init_data = await scry_groups_init(self._client)
if init_data and isinstance(init_data, dict):
groups = init_data.get("groups", {})
for group_id, group_data in groups.items():
channels = group_data.get("channels", {})
for channel_nest in channels:
if channel_nest.startswith("chat/"):
discovered.add(channel_nest)
except Exception as e:
logger.warning(f"[Urbit] Channel discovery failed: {e}")
if discovered:
logger.info(f"[Urbit] Discovered {len(discovered)} chat channels")
return discovered
async def _refresh_loop(self) -> None:
while True:
try:
await asyncio.sleep(_DISCOVERY_INTERVAL)
new_channels = await self.discover_channels()
added = new_channels - self._discovered_channels
if added:
self._discovered_channels |= added
logger.info(f"[Urbit] Discovered {len(added)} new channels: {added}")
except asyncio.CancelledError:
break
except Exception as e:
logger.warning(f"[Urbit] Channel refresh error: {e}")
async def persist_group_channels(self) -> None:
if not self._settings_store:
return
try:
chat_channels = [ch for ch in self.channels if ch.startswith("chat/")]
self._settings_store.update_key("groupChannels", chat_channels)
logger.info(f"[Urbit] Persisted {len(chat_channels)} group channels to Settings Store")
except Exception as e:
logger.warning(f"[Urbit] Failed to persist group channels: {e}")
def add_channel(self, channel_nest: str) -> None:
if channel_nest not in self._discovered_channels:
self._discovered_channels.add(channel_nest)
logger.info(f"[Urbit] Manually added channel: {channel_nest}")
def get_chat_nests(self, ship_name: str) -> list[str]:
nests: list[str] = []
for channel in self.channels:
if channel.startswith("chat/"):
group_name = channel[len("chat/") :]
nests.append(f"~{ship_name}/{group_name}/chat")
return nests