from __future__ import annotations from yuxi.channels.base import BaseChannelAdapter _BUILTIN_ADAPTERS: dict[str, type[BaseChannelAdapter]] = {} _BUILTIN_ADAPTER_ALIASES: dict[str, str] = {} def register_builtin_adapter(cls: type[BaseChannelAdapter] | None = None, *, aliases: list[str] | None = None): def _decorator(cls_inner: type[BaseChannelAdapter]) -> type[BaseChannelAdapter]: _BUILTIN_ADAPTERS[cls_inner.channel_id] = cls_inner if aliases: for alias in aliases: _BUILTIN_ADAPTER_ALIASES[alias] = cls_inner.channel_id return cls_inner if cls is None: return _decorator return _decorator(cls) def _load_builtin_adapters(): if _BUILTIN_ADAPTERS: return try: from yuxi.channels.adapters.webchat import WebChatAdapter _BUILTIN_ADAPTERS["webchat"] = WebChatAdapter except ImportError: pass try: from yuxi.channels.adapters.telegram import TelegramAdapter _BUILTIN_ADAPTERS["telegram"] = TelegramAdapter except ImportError: pass try: from yuxi.channels.adapters.slack import SlackAdapter _BUILTIN_ADAPTERS["slack"] = SlackAdapter except ImportError: pass try: from yuxi.channels.adapters.matrix import MatrixAdapter _BUILTIN_ADAPTERS["matrix"] = MatrixAdapter except ImportError: pass try: from yuxi.channels.adapters.mattermost import MattermostAdapter _BUILTIN_ADAPTERS["mattermost"] = MattermostAdapter except ImportError: pass try: from yuxi.channels.adapters.nostr import NostrAdapter _BUILTIN_ADAPTERS["nostr"] = NostrAdapter except ImportError: pass try: from yuxi.channels.twitch import TwitchAdapter _BUILTIN_ADAPTERS["twitch"] = TwitchAdapter except ImportError: pass try: from yuxi.channels.adapters.imessage import IMessageAdapter _BUILTIN_ADAPTERS["imessage"] = IMessageAdapter except ImportError: pass try: from yuxi.channels.adapters.whatsapp import WhatsAppAdapter _BUILTIN_ADAPTERS["whatsapp"] = WhatsAppAdapter except ImportError: pass try: from yuxi.channels.adapters.discord import DiscordAdapter _BUILTIN_ADAPTERS["discord"] = DiscordAdapter except ImportError: pass try: from yuxi.channels.adapters.irc import IRCAdapter _BUILTIN_ADAPTERS["irc"] = IRCAdapter except ImportError: pass try: from yuxi.channels.adapters.dingding import DingDingChannelAdapter _BUILTIN_ADAPTERS["dingding"] = DingDingChannelAdapter except ImportError: pass try: from yuxi.channels.adapters.feishu import FeishuAdapter _BUILTIN_ADAPTERS["feishu"] = FeishuAdapter except ImportError: pass try: from yuxi.channels.adapters.msteams import MSTeamsAdapter _BUILTIN_ADAPTERS["msteams"] = MSTeamsAdapter except ImportError: pass try: from yuxi.channels.adapters.bluebubbles import BlueBubblesAdapter _BUILTIN_ADAPTERS["bluebubbles"] = BlueBubblesAdapter except ImportError: pass try: from yuxi.channels.adapters.synologychat import SynologyChatAdapter _BUILTIN_ADAPTERS["synologychat"] = SynologyChatAdapter except ImportError: pass try: from yuxi.channels.adapters.nextcloudtalk import NextcloudTalkAdapter _BUILTIN_ADAPTERS["nextcloud-talk"] = NextcloudTalkAdapter except ImportError: pass try: from yuxi.channels.adapters.googlechat import GoogleChatAdapter _BUILTIN_ADAPTERS["googlechat"] = GoogleChatAdapter except ImportError: pass try: from yuxi.channels.adapters.line import LINEAdapter _BUILTIN_ADAPTERS["line"] = LINEAdapter except ImportError: pass try: from yuxi.channels.adapters.qqbot import QQBotAdapter _BUILTIN_ADAPTERS["qqbot"] = QQBotAdapter except ImportError: pass try: from yuxi.channels.signal.channel import SignalChannel _BUILTIN_ADAPTERS["signal"] = SignalChannel except ImportError: pass try: from yuxi.channels.adapters.zalo_user import ZaloUserAdapter _BUILTIN_ADAPTERS["zalo_user"] = ZaloUserAdapter except ImportError: pass try: from yuxi.channels.adapters.urbit import UrbitAdapter _BUILTIN_ADAPTERS["urbit"] = UrbitAdapter except ImportError: pass try: from yuxi.channels.adapters.zalo_oa import ZaloOAAdapter _BUILTIN_ADAPTERS["zalo_oa"] = ZaloOAAdapter except ImportError: pass try: from yuxi.channels.adapters.wechat import WeChatAdapter _BUILTIN_ADAPTERS["wechat"] = WeChatAdapter except ImportError: pass class ChannelRegistry: def __init__(self): self._adapters: dict[str, type[BaseChannelAdapter]] = {} self._alias_map: dict[str, str] = {} def _build_alias_map(self) -> None: for alias, channel_id in _BUILTIN_ADAPTER_ALIASES.items(): self._alias_map[alias] = channel_id for channel_id, adapter_cls in {**_BUILTIN_ADAPTERS, **self._adapters}.items(): meta = getattr(adapter_cls, "meta", None) if meta and meta.aliases: for alias in meta.aliases: self._alias_map[alias] = channel_id def get(self, channel_id: str) -> type[BaseChannelAdapter] | None: if channel_id in self._adapters: return self._adapters[channel_id] if channel_id in _BUILTIN_ADAPTERS: return _BUILTIN_ADAPTERS[channel_id] if not self._alias_map: self._build_alias_map() resolved = self._alias_map.get(channel_id) if resolved: return self._adapters.get(resolved) or _BUILTIN_ADAPTERS.get(resolved) return None def register(self, channel_id: str, adapter_cls: type[BaseChannelAdapter]) -> None: self._adapters[channel_id] = adapter_cls def list_channels(self) -> list[str]: return list({*self._adapters.keys(), *_BUILTIN_ADAPTERS.keys()}) def unregister(self, channel_id: str) -> None: self._adapters.pop(channel_id, None) BUILTIN_ADAPTERS = _BUILTIN_ADAPTERS