95 lines
3.3 KiB
Python
95 lines
3.3 KiB
Python
from yuxi.channel.plugins.protocol import ChannelMeta
|
|
from yuxi.channel.ports import MetaPort
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
|
|
class ChannelRegistry:
|
|
"""渠道插件注册表,支持别名解析。"""
|
|
|
|
def __init__(self) -> None:
|
|
self._plugins: dict[str, MetaPort] = {}
|
|
self._alias_to_primary: dict[str, str] = {}
|
|
|
|
def register(self, plugin: MetaPort) -> None:
|
|
meta = plugin.get_meta()
|
|
existing = self._plugins.get(meta.channel_type)
|
|
if existing is not None and existing is not plugin:
|
|
logger.warning(
|
|
"Channel type '%s' is already registered, overwriting with new plugin",
|
|
meta.channel_type,
|
|
)
|
|
self._plugins[meta.channel_type] = plugin
|
|
for alias in meta.aliases:
|
|
existing_primary = self._alias_to_primary.get(alias)
|
|
if existing_primary is not None and existing_primary != meta.channel_type:
|
|
logger.warning(
|
|
"Channel alias '%s' already registered to '%s', skipping registration for '%s'",
|
|
alias,
|
|
existing_primary,
|
|
meta.channel_type,
|
|
)
|
|
continue
|
|
self._plugins[alias] = plugin
|
|
self._alias_to_primary[alias] = meta.channel_type
|
|
|
|
def register_primary(self, plugin: MetaPort) -> None:
|
|
meta = plugin.get_meta()
|
|
existing = self._plugins.get(meta.channel_type)
|
|
if existing is not None and existing is not plugin:
|
|
logger.warning(
|
|
"Channel type '%s' is already registered, overwriting with new plugin",
|
|
meta.channel_type,
|
|
)
|
|
self._plugins[meta.channel_type] = plugin
|
|
|
|
def unregister(self, channel_type: str) -> None:
|
|
plugin = self._plugins.pop(channel_type, None)
|
|
if plugin is None:
|
|
return
|
|
meta = plugin.get_meta()
|
|
primary = meta.channel_type
|
|
for alias in meta.aliases:
|
|
if self._alias_to_primary.get(alias) == primary:
|
|
self._plugins.pop(alias, None)
|
|
self._alias_to_primary.pop(alias, None)
|
|
|
|
def get_plugin(self, channel_type: str) -> MetaPort | None:
|
|
return self._plugins.get(channel_type)
|
|
|
|
def get_plugins_by_port(self, port: type) -> list[MetaPort]:
|
|
seen: set[int] = set()
|
|
result: list[MetaPort] = []
|
|
for plugin in self._plugins.values():
|
|
pid = id(plugin)
|
|
if pid in seen:
|
|
continue
|
|
seen.add(pid)
|
|
if isinstance(plugin, port):
|
|
result.append(plugin)
|
|
return result
|
|
|
|
def has_port(self, channel_type: str, port: type) -> bool:
|
|
plugin = self._plugins.get(channel_type)
|
|
return plugin is not None and isinstance(plugin, port)
|
|
|
|
def list_plugins(self) -> list[ChannelMeta]:
|
|
seen: set[int] = set()
|
|
result: list[ChannelMeta] = []
|
|
for plugin in self._plugins.values():
|
|
pid = id(plugin)
|
|
if pid in seen:
|
|
continue
|
|
seen.add(pid)
|
|
result.append(plugin.get_meta())
|
|
return result
|
|
|
|
|
|
_GLOBAL_REGISTRY: ChannelRegistry | None = None
|
|
|
|
|
|
def get_registry() -> ChannelRegistry:
|
|
global _GLOBAL_REGISTRY
|
|
if _GLOBAL_REGISTRY is None:
|
|
_GLOBAL_REGISTRY = ChannelRegistry()
|
|
return _GLOBAL_REGISTRY
|