"""Microsoft Teams 多账户管理。 支持 per-account 实例管理,startAccount/probeAccount hooks。 """ from __future__ import annotations import time from typing import Any from yuxi.utils.logging_config import logger TOKEN_URL = "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" BOT_SCOPE = "https://api.botframework.com/.default" class AccountManager: def __init__(self): self._accounts: dict[str, dict[str, Any]] = {} def register_account( self, account_id: str, app_id: str, app_password: str, tenant_id: str = "", label: str = "", ) -> None: self._accounts[account_id] = { "account_id": account_id, "app_id": app_id, "app_password": app_password, "tenant_id": tenant_id, "label": label or account_id, "registered_at": time.time(), "status": "registered", } logger.info(f"MSTeams account registered: {account_id}") def unregister_account(self, account_id: str) -> bool: return self._accounts.pop(account_id, None) is not None def get_account(self, account_id: str) -> dict[str, Any] | None: return self._accounts.get(account_id) def get_all_accounts(self) -> list[dict[str, Any]]: return list(self._accounts.values()) def list_account_ids(self) -> list[str]: return list(self._accounts.keys()) @property def account_count(self) -> int: return len(self._accounts) async def probe_account(self, account_id: str) -> dict[str, Any]: import aiohttp account = self._accounts.get(account_id) if not account: return {"status": "error", "message": f"Account not found: {account_id}"} data = { "client_id": account["app_id"], "client_secret": account["app_password"], "grant_type": "client_credentials", "scope": BOT_SCOPE, } try: async with aiohttp.ClientSession() as session: async with session.post(TOKEN_URL, data=data) as resp: if resp.status == 200: result = await resp.json() token = result.get("access_token") if token: account["status"] = "connected" account["last_probe_at"] = time.time() return { "status": "ok", "account_id": account_id, "connected": True, } except Exception as e: logger.error(f"MSTeams account probe failed: {account_id}: {e}") account["status"] = "error" return {"status": "error", "account_id": account_id, "connected": False} async def start_account(self, account_id: str, adapter: Any = None) -> bool: account = self._accounts.get(account_id) if not account: return False if adapter: adapter._app_id = account["app_id"] adapter._app_password = account["app_password"] adapter.config["app_id"] = account["app_id"] adapter.config["app_password"] = account["app_password"] if account.get("tenant_id"): adapter.config["tenant_id"] = account["tenant_id"] account["status"] = "started" account["started_at"] = time.time() logger.info(f"MSTeams account started: {account_id}") return True