Coverage for zenmqtt/connection/__init__.py: 100%
24 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
1from ssl import SSLContext
2from typing import Awaitable, Callable, Optional
3from urllib.parse import ParseResult, urlparse
5from .base import ConnectionOptions, MQTTConnection, MQTTConnectionTransport
6from .tcp import build_tcp_connection_transport, build_tls_connection_transport
8__all__ = [
9 "ConnectionOptions",
10 "MQTTConnection",
11 "MQTTConnectionTransport",
12 "create_connection",
13 "register_implementation",
14]
16ConnectionFactory = Callable[
17 [ParseResult, ConnectionOptions], Awaitable[MQTTConnectionTransport]
18]
20_CONNECTION_IMPLEMENTATION_MAP: dict[str, ConnectionFactory] = {
21 "tcp": build_tcp_connection_transport,
22 "mqtt": build_tcp_connection_transport,
23 "mqtts": build_tls_connection_transport,
24 "ssl": build_tls_connection_transport,
25}
27# schemes which encrypt the connection, the only ones accepting an SSL context
28_TLS_SCHEMES = {"mqtts", "ssl"}
31def register_implementation(scheme: str, factory: ConnectionFactory) -> None:
32 _CONNECTION_IMPLEMENTATION_MAP[scheme] = factory
35async def create_connection(
36 url: str, ssl: Optional[SSLContext] = None
37) -> MQTTConnection:
38 """
39 :param url: e.g. tcp://localhost:1883 or mqtts://broker:8883, the port is
40 optional: 1883 for tcp:// and mqtt://, 8883 for mqtts:// and ssl://
41 :param ssl: context for mqtts:// and ssl://, the default one verifies the
42 server certificate with the system CA certificates
43 """
44 parsed_url = urlparse(url)
46 if not parsed_url.hostname:
47 raise ValueError(f"Invalid URL, host is missing: {url}")
49 if not (factory := _CONNECTION_IMPLEMENTATION_MAP.get(parsed_url.scheme)):
50 raise ValueError(f"Unsupported URL scheme: {parsed_url.scheme}")
52 options: ConnectionOptions = {}
54 if ssl is not None:
55 # a context with plain tcp:// would silently send data unencrypted
56 if parsed_url.scheme not in _TLS_SCHEMES:
57 raise ValueError(
58 f"SSL context requires mqtts:// or ssl:// URL, got {parsed_url.scheme}"
59 )
61 options["ssl"] = ssl
63 transport = await factory(parsed_url, options)
65 return MQTTConnection(transport)