Coverage for zenmqtt/mqtt/protocol/context.py: 100%
41 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 21:55 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 21:55 +0000
1import asyncio
2from typing import Optional
4from zenmqtt.connection import MQTTConnection
5from zenmqtt.exceptions import NotConnectedError
6from zenmqtt.instrumentation.metrics import MetricsCollector
7from zenmqtt.mqtt.limits import DEFAULT_SERVER_LIMITS, ServerLimits
8from zenmqtt.mqtt.packet import PacketType
11class ProtocolContext:
12 """
13 State shared by the parts of the protocol: the current connection, limits
14 of the server and metrics.
16 The state is changed only by MQTTProtocol, with the methods below; the
17 parts read it through the read-only properties.
18 """
20 def __init__(self, metrics: MetricsCollector) -> None:
21 self.metrics = metrics
23 self._connection: Optional[MQTTConnection] = None
24 self._connected = False
25 self._server_limits: ServerLimits = DEFAULT_SERVER_LIMITS
27 @property
28 def connection(self) -> Optional[MQTTConnection]:
29 """The current connection, also before CONNACK and after its loss."""
30 return self._connection
32 @property
33 def connected(self) -> bool:
34 """True only between successful CONNACK and loss of the connection."""
35 return self._connected
37 @property
38 def server_limits(self) -> ServerLimits:
39 """Limits of the server from the last CONNACK."""
40 return self._server_limits
42 # called by MQTTProtocol only
44 def set_connection(self, connection: MQTTConnection) -> None:
45 self._connection = connection
47 def set_server_limits(self, server_limits: ServerLimits) -> None:
48 self._server_limits = server_limits
50 def mark_connected(self) -> None:
51 self._connected = True
53 def mark_disconnected(self) -> None:
54 self._connected = False
56 def ensure_connected(self) -> MQTTConnection:
57 connection = self._connection
59 if not self._connected or not connection or connection.is_closing():
60 raise NotConnectedError()
62 return connection
64 async def write(self, connection: MQTTConnection, packet: bytes) -> None:
65 await connection.write(packet)
67 self.metrics.on_packet_sent(PacketType(packet[0] >> 4), len(packet))
69 @staticmethod
70 def now() -> float:
71 return asyncio.get_running_loop().time()