ForcePilot/backend/package/yuxi/channel/extensions/flock/status.py
Kris 0bad70ec19 feat(flock): 新增Flock团队协作IM渠道插件
实现了完整的Flock渠道接入能力,包含消息收发、Webhook事件监听、账号配置、安全校验、媒体文件处理等功能,支持私聊和群组聊天,适配ForcePilot插件规范。
2026-05-21 10:47:01 +08:00

116 lines
3.6 KiB
Python

from __future__ import annotations
import logging
import time
import httpx
from .config import _apply_env_overrides, _dict_to_account
from .constants import BASE_URL, ENDPOINT_USER_GET_INFO, ENDPOINT_USER_PUBLIC_PROFILE, PROBE_TIMEOUT
from .types import ProbeResult
from .utils import build_auth_headers, create_http_client, flock_api_call
logger = logging.getLogger(__name__)
async def probe(config: dict, account_id: str = "default") -> ProbeResult:
account_data = config.get("accounts", {}).get(account_id, {})
account = _dict_to_account(account_data)
account = _apply_env_overrides(account)
if not account.bot_token:
return ProbeResult(ok=False, reason="bot_token not configured")
start = time.monotonic()
client = create_http_client(timeout=PROBE_TIMEOUT)
try:
headers = build_auth_headers(account.bot_token)
resp = await client.post(
f"{BASE_URL}{ENDPOINT_USER_GET_INFO}",
json={},
headers=headers,
)
latency_ms = (time.monotonic() - start) * 1000
if resp.status_code == 200:
logger.info("Flock probe OK for account %s", account_id)
return ProbeResult(ok=True, latency_ms=latency_ms)
error_code = _try_extract_error(resp)
logger.warning(
"Flock probe failed for account %s: %s (HTTP %d)",
account_id,
error_code,
resp.status_code,
)
return ProbeResult(ok=False, reason=error_code, latency_ms=latency_ms)
except Exception as e:
latency_ms = (time.monotonic() - start) * 1000
logger.warning("Flock probe error for account %s: %s", account_id, e)
return ProbeResult(ok=False, reason=str(e), latency_ms=latency_ms)
finally:
await client.aclose()
def _try_extract_error(resp: httpx.Response) -> str:
try:
body = resp.json()
return body.get("error", f"HTTP {resp.status_code}")
except Exception:
return f"HTTP {resp.status_code}"
def build_summary(config: dict) -> dict:
accounts = config.get("accounts", {})
configured = any(bool(a.get("bot_token") or a.get("incoming_webhook_url")) for a in accounts.values())
return {
"channel": "flock",
"configured": configured,
"accounts_count": len(accounts) if accounts else 1,
}
def build_account_snapshot(account: dict, config: dict) -> dict:
acct = _dict_to_account(account)
acct = _apply_env_overrides(acct)
return {
"account_id": acct.account_id,
"configured": bool(acct.bot_token or acct.incoming_webhook_url),
"enabled": acct.enabled,
"dm_policy": acct.dm_policy,
"group_policy": acct.group_policy,
}
async def get_user_info(
user_id: str | None = None,
*,
config: dict,
account_id: str = "default",
) -> dict | None:
account_data = config.get("accounts", {}).get(account_id, {})
account = _dict_to_account(account_data)
account = _apply_env_overrides(account)
if not account.bot_token:
logger.warning("Flock get_user_info: bot_token not configured")
return None
if user_id:
payload = {"userId": user_id}
endpoint = ENDPOINT_USER_PUBLIC_PROFILE
else:
payload = {}
endpoint = ENDPOINT_USER_GET_INFO
client = create_http_client()
try:
result = await flock_api_call(client, endpoint, account.bot_token, payload)
return result
except Exception as e:
logger.error("Flock get_user_info failed: %s", e)
return None
finally:
await client.aclose()