Source code for ezmsg.dashboard.backend.external_sources

"""Discover live, typed publishers without importing names advertised by peers."""

import asyncio

from ezmsg.core import GraphContext
from ezmsg.core.graphmeta import OutputStreamMetadata, OutputTopicMetadata
from ezmsg.core.netprotocol import Address


[docs] async def external_sources(graph_address: str, managed_root: str) -> list[dict]: async with GraphContext(Address.from_string(graph_address), auto_start=False) as context: snapshot, profiles = await asyncio.gather(context.snapshot(), context.profiling_snapshot_all()) # Topic aliases have no publisher of their own. They are usable when a # live publisher reaches them through the graph's directed wiring. live = { p.topic for profile in profiles.values() for p in profile.publishers.values() if not p.topic.startswith(managed_root + "/") } pending = list(live) while pending: for target in snapshot.graph.get(pending.pop(), []): if target not in live and not target.startswith(managed_root + "/"): live.add(target) pending.append(target) types: dict[str, set[str]] = {} for session in snapshot.sessions.values(): if session.metadata is None: continue for component in session.metadata.components.values(): endpoints = { **getattr(component, "streams", {}), **getattr(component, "topics", {}), **getattr(component, "relays", {}), } for stream in endpoints.values(): if isinstance(stream, (OutputStreamMetadata, OutputTopicMetadata)) and stream.address in live: if not stream.address.startswith(managed_root + "/"): types.setdefault(stream.address, set()).add(stream.msg_type) return [ {"topic": topic, "message_type": next(iter(labels))} for topic, labels in sorted(types.items()) if len(labels) == 1 ]