Skip to content

Connection

connection

Connection — owns the WebSocket lifecycle and the state-priming pipeline.

The connection is the single place that knows the order in which the core services must be brought up: subscribe to events first (with buffering enabled), then prime the state cache from REST, then drain the buffered events. The same sequence runs on reconnect so the cache stays consistent.

Disconnect / reconnect listeners live here as a thin pass-through to the underlying WebSocketPort.

Connection

Lifecycle facade for the transport layer.

Parameters:

Name Type Description Default
ws WebSocketPort

Underlying WebSocket adapter.

required
rest RestPort

Underlying REST adapter.

required
events EventBus

Event bus to bring up.

required
state StateStore

State store to prime.

required
Source code in src/haclient/core/connection.py
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
class Connection:
    """Lifecycle facade for the transport layer.

    Parameters
    ----------
    ws : WebSocketPort
        Underlying WebSocket adapter.
    rest : RestPort
        Underlying REST adapter.
    events : EventBus
        Event bus to bring up.
    state : StateStore
        State store to prime.
    """

    def __init__(
        self,
        ws: WebSocketPort,
        rest: RestPort,
        events: EventBus,
        state: StateStore,
    ) -> None:
        self._ws = ws
        self._rest = rest
        self._events = events
        self._state = state
        self._connected = False
        # Wire post-reconnect refresh.
        self._ws.on_reconnect(self._on_reconnect)

    @property
    def ws(self) -> WebSocketPort:
        """Return the underlying WebSocket adapter."""
        return self._ws

    @property
    def rest(self) -> RestPort:
        """Return the underlying REST adapter."""
        return self._rest

    @property
    def is_connected(self) -> bool:
        """Return ``True`` once `open` has completed successfully."""
        return self._connected

    async def open(self) -> None:
        """Connect, subscribe to events, and prime the state cache.

        Idempotent: a second call while already connected is a no-op.
        """
        if self._connected:
            return
        await self._ws.connect()
        await self._state.prime()
        self._connected = True

    async def close(self) -> None:
        """Tear down the connection and release infrastructure resources."""
        self._connected = False
        await self._ws.close()
        await self._rest.close()

    def on_disconnect(self, handler: DisconnectListener) -> DisconnectListener:
        """Register a disconnect listener (forwarded to the WS adapter).

        Parameters
        ----------
        handler : DisconnectListener
            Sync or async zero-argument callable invoked when the
            underlying WebSocket connection drops.

        Returns
        -------
        DisconnectListener
            The same *handler*, returned so the method can be used as a
            decorator.
        """
        return self._ws.on_disconnect(handler)

    def on_reconnect(self, handler: ReconnectListener) -> ReconnectListener:
        """Register a reconnect listener (forwarded to the WS adapter).

        Parameters
        ----------
        handler : ReconnectListener
            Sync or async zero-argument callable invoked after the
            underlying WebSocket reconnects.

        Returns
        -------
        ReconnectListener
            The same *handler*, returned so the method can be used as a
            decorator.
        """
        return self._ws.on_reconnect(handler)

    async def _on_reconnect(self) -> None:
        """Re-prime the state store after a successful reconnection."""
        try:
            await self._state.refresh_all()
        except Exception:  # noqa: BLE001
            _LOGGER.warning("Post-reconnect refresh failed", exc_info=True)

ws property

ws: WebSocketPort

Return the underlying WebSocket adapter.

rest property

rest: RestPort

Return the underlying REST adapter.

is_connected property

is_connected: bool

Return True once open has completed successfully.

open async

open() -> None

Connect, subscribe to events, and prime the state cache.

Idempotent: a second call while already connected is a no-op.

Source code in src/haclient/core/connection.py
72
73
74
75
76
77
78
79
80
81
async def open(self) -> None:
    """Connect, subscribe to events, and prime the state cache.

    Idempotent: a second call while already connected is a no-op.
    """
    if self._connected:
        return
    await self._ws.connect()
    await self._state.prime()
    self._connected = True

close async

close() -> None

Tear down the connection and release infrastructure resources.

Source code in src/haclient/core/connection.py
83
84
85
86
87
async def close(self) -> None:
    """Tear down the connection and release infrastructure resources."""
    self._connected = False
    await self._ws.close()
    await self._rest.close()

on_disconnect

on_disconnect(handler: DisconnectListener) -> DisconnectListener

Register a disconnect listener (forwarded to the WS adapter).

Parameters:

Name Type Description Default
handler DisconnectListener

Sync or async zero-argument callable invoked when the underlying WebSocket connection drops.

required

Returns:

Type Description
DisconnectListener

The same handler, returned so the method can be used as a decorator.

Source code in src/haclient/core/connection.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def on_disconnect(self, handler: DisconnectListener) -> DisconnectListener:
    """Register a disconnect listener (forwarded to the WS adapter).

    Parameters
    ----------
    handler : DisconnectListener
        Sync or async zero-argument callable invoked when the
        underlying WebSocket connection drops.

    Returns
    -------
    DisconnectListener
        The same *handler*, returned so the method can be used as a
        decorator.
    """
    return self._ws.on_disconnect(handler)

on_reconnect

on_reconnect(handler: ReconnectListener) -> ReconnectListener

Register a reconnect listener (forwarded to the WS adapter).

Parameters:

Name Type Description Default
handler ReconnectListener

Sync or async zero-argument callable invoked after the underlying WebSocket reconnects.

required

Returns:

Type Description
ReconnectListener

The same handler, returned so the method can be used as a decorator.

Source code in src/haclient/core/connection.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def on_reconnect(self, handler: ReconnectListener) -> ReconnectListener:
    """Register a reconnect listener (forwarded to the WS adapter).

    Parameters
    ----------
    handler : ReconnectListener
        Sync or async zero-argument callable invoked after the
        underlying WebSocket reconnects.

    Returns
    -------
    ReconnectListener
        The same *handler*, returned so the method can be used as a
        decorator.
    """
    return self._ws.on_reconnect(handler)