55import logging
66from pathlib import Path
77import ssl
8- from libp2p .transport .quic .utils import is_quic_multiaddr
98from typing import Any
109from cryptography .hazmat .primitives .asymmetric import ed25519
1110from cryptography .hazmat .primitives import serialization
1211
13- from libp2p .transport .quic .transport import QUICTransport
14- from libp2p .transport .quic .config import QUICTransportConfig
12+ try :
13+ from libp2p .transport .quic .utils import is_quic_multiaddr
14+ from libp2p .transport .quic .transport import QUICTransport
15+ from libp2p .transport .quic .config import QUICTransportConfig
16+
17+ _HAS_QUIC = True
18+ except ImportError :
19+ _HAS_QUIC = False
20+ QUICTransport = None
21+ QUICTransportConfig = None
22+
23+ def is_quic_multiaddr (maddr : Any ) -> bool :
24+ return False
1525from collections .abc import (
1626 Mapping ,
1727 Sequence ,
8696 PLAINTEXT_PROTOCOL_ID ,
8797 InsecureTransport ,
8898)
89- from libp2p .security .noise .transport import (
90- PROTOCOL_ID as NOISE_PROTOCOL_ID ,
91- Transport as NoiseTransport ,
92- )
93- from libp2p .security .tls .transport import (
94- PROTOCOL_ID as TLS_PROTOCOL_ID ,
95- TLSTransport
96- )
9799
98- import libp2p .security .secio .transport as secio
99- from libp2p .stream_muxer .mplex .mplex import (
100- MPLEX_PROTOCOL_ID ,
101- Mplex ,
102- )
103- from libp2p .stream_muxer .yamux .yamux import (
104- PROTOCOL_ID as YAMUX_PROTOCOL_ID ,
105- Yamux ,
106- )
100+ try :
101+ from libp2p .security .noise .transport import (
102+ PROTOCOL_ID as NOISE_PROTOCOL_ID ,
103+ Transport as NoiseTransport ,
104+ )
105+ _HAS_NOISE = True
106+ except ImportError :
107+ _HAS_NOISE = False
108+ NOISE_PROTOCOL_ID = None
109+ NoiseTransport = None
110+
111+ try :
112+ from libp2p .security .tls .transport import (
113+ PROTOCOL_ID as TLS_PROTOCOL_ID ,
114+ TLSTransport ,
115+ )
116+ _HAS_TLS = True
117+ except ImportError :
118+ _HAS_TLS = False
119+ TLS_PROTOCOL_ID = None
120+ TLSTransport = None
121+
122+ try :
123+ import libp2p .security .secio .transport as secio
124+ _HAS_SECIO = True
125+ except ImportError :
126+ _HAS_SECIO = False
127+ secio = None
128+
129+ try :
130+ from libp2p .stream_muxer .mplex .mplex import (
131+ MPLEX_PROTOCOL_ID ,
132+ Mplex ,
133+ )
134+ _HAS_MPLEX = True
135+ except ImportError :
136+ _HAS_MPLEX = False
137+ MPLEX_PROTOCOL_ID = None
138+ Mplex = None
139+
140+ try :
141+ from libp2p .stream_muxer .yamux .yamux import (
142+ PROTOCOL_ID as YAMUX_PROTOCOL_ID ,
143+ Yamux ,
144+ )
145+ _HAS_YAMUX = True
146+ except ImportError :
147+ _HAS_YAMUX = False
148+ YAMUX_PROTOCOL_ID = None
149+ Yamux = None
150+
107151from libp2p .transport .tcp .tcp import (
108152 TCP ,
109153)
113157from libp2p .transport .transport_registry import (
114158 create_transport_for_multiaddr ,
115159 get_supported_transport_protocols ,
160+ transport_needs_muxer ,
161+ transport_needs_security ,
162+ )
163+ from libp2p .capabilities import (
164+ ConnectionCapabilities ,
165+ NeedsSetup ,
166+ TransportCapabilities ,
167+ )
168+ from libp2p .requirements import (
169+ ConnectionRequirementError ,
170+ after_connection ,
171+ check_connection_requirements ,
172+ get_after_connections ,
173+ get_required_connections ,
174+ requires_connection ,
175+ )
176+ from libp2p .providers import (
177+ MuxerProvider ,
178+ ProvidesConnection ,
179+ ProvidesTransport ,
180+ ProviderRegistry ,
181+ SecurityProvider ,
182+ TransportProvider ,
183+ )
184+ from libp2p .network .resolver import (
185+ AllPathsFailedError ,
186+ ConnectionResolver ,
187+ NoTransportError ,
188+ ResolutionError ,
189+ ResolvedStack ,
190+ )
191+ from libp2p .entrypoints import (
192+ EP_GROUP_MUXERS ,
193+ EP_GROUP_SECURITY ,
194+ EP_GROUP_TRANSPORTS ,
195+ discover_and_register ,
196+ discover_muxers ,
197+ discover_security ,
198+ discover_transports ,
116199)
117200import libp2p .utils
118201from libp2p .utils .logging import (
@@ -229,24 +312,32 @@ def create_yamux_muxer_option() -> TMuxerOptions:
229312 """
230313 Returns muxer options with Yamux as the primary choice.
231314
315+ Only includes muxers whose extras are installed.
316+
232317 :return: Muxer options with Yamux first
233318 """
234- return {
235- TProtocol (YAMUX_PROTOCOL_ID ): Yamux , # Primary choice
236- TProtocol (MPLEX_PROTOCOL_ID ): Mplex , # Fallback for compatibility
237- }
319+ opts : dict [TProtocol , Any ] = {}
320+ if _HAS_YAMUX and Yamux is not None and YAMUX_PROTOCOL_ID is not None :
321+ opts [TProtocol (YAMUX_PROTOCOL_ID )] = Yamux
322+ if _HAS_MPLEX and Mplex is not None and MPLEX_PROTOCOL_ID is not None :
323+ opts [TProtocol (MPLEX_PROTOCOL_ID )] = Mplex
324+ return opts
238325
239326
240327def create_mplex_muxer_option () -> TMuxerOptions :
241328 """
242329 Returns muxer options with Mplex as the primary choice.
243330
331+ Only includes muxers whose extras are installed.
332+
244333 :return: Muxer options with Mplex first
245334 """
246- return {
247- TProtocol (MPLEX_PROTOCOL_ID ): Mplex , # Primary choice
248- TProtocol (YAMUX_PROTOCOL_ID ): Yamux , # Fallback
249- }
335+ opts : dict [TProtocol , Any ] = {}
336+ if _HAS_MPLEX and Mplex is not None and MPLEX_PROTOCOL_ID is not None :
337+ opts [TProtocol (MPLEX_PROTOCOL_ID )] = Mplex
338+ if _HAS_YAMUX and Yamux is not None and YAMUX_PROTOCOL_ID is not None :
339+ opts [TProtocol (YAMUX_PROTOCOL_ID )] = Yamux
340+ return opts
250341
251342
252343def generate_new_rsa_identity () -> KeyPair :
@@ -289,7 +380,7 @@ def new_swarm(
289380 enable_quic : bool = False ,
290381 enable_autotls : bool = False ,
291382 retry_config : RetryConfig | None = None ,
292- connection_config : ConnectionConfig | QUICTransportConfig | None = None ,
383+ connection_config : ConnectionConfig | Any | None = None ,
293384 tls_client_config : ssl .SSLContext | None = None ,
294385 tls_server_config : ssl .SSLContext | None = None ,
295386 resource_manager : ResourceManager | None = None ,
@@ -328,11 +419,21 @@ def new_swarm(
328419
329420 id_opt = generate_peer_id_from (key_pair )
330421
331- transport : TCP | QUICTransport | ITransport
332- quic_transport_opt = connection_config if isinstance (connection_config , QUICTransportConfig ) else None
422+ transport : TCP | ITransport
423+ quic_transport_opt = (
424+ connection_config
425+ if _HAS_QUIC and QUICTransportConfig is not None
426+ and isinstance (connection_config , QUICTransportConfig )
427+ else None
428+ )
333429
334430 if listen_addrs is None :
335431 if enable_quic :
432+ if not _HAS_QUIC or QUICTransport is None :
433+ raise ImportError (
434+ "QUIC transport is not available. "
435+ "Install the 'quic' extra: pip install libp2p[quic]"
436+ )
336437 transport = QUICTransport (key_pair .private_key , config = quic_transport_opt )
337438 else :
338439 transport = TCP ()
@@ -365,9 +466,13 @@ def new_swarm(
365466 logger .debug (f"new_swarm: Created transport: { type (transport )} " )
366467
367468 # If enable_quic is True but we didn't get a QUIC transport, force QUIC
368- if enable_quic and not isinstance (transport , QUICTransport ):
369- logger .debug (f"new_swarm: Forcing QUIC transport (enable_quic=True but got { type (transport )} )" )
370- transport = QUICTransport (key_pair .private_key , config = quic_transport_opt )
469+ if enable_quic and _HAS_QUIC and QUICTransport is not None :
470+ if not isinstance (transport , QUICTransport ):
471+ logger .debug (
472+ f"new_swarm: Forcing QUIC transport (enable_quic=True "
473+ f"but got { type (transport )} )"
474+ )
475+ transport = QUICTransport (key_pair .private_key , config = quic_transport_opt )
371476
372477 logger .debug (f"new_swarm: Final transport type: { type (transport )} " )
373478
@@ -378,19 +483,25 @@ def new_swarm(
378483 # NOTE: Using Noise as primary for now because Python's ssl module has limitations
379484 # with mutual TLS authentication. See TLS_ANALYSIS.md for details.
380485 # TLS is still offered as a fallback option.
381- secure_transports_by_protocol : Mapping [TProtocol , ISecureTransport ] = sec_opt or {
382- # TLS_PROTOCOL_ID: TLSTransport(key_pair),
383- NOISE_PROTOCOL_ID : NoiseTransport (
384- key_pair , noise_privkey = noise_key_pair .private_key
385- ),
386- TLS_PROTOCOL_ID : TLSTransport (
387- key_pair , enable_autotls = enable_autotls
388- ),
389- TProtocol (secio .ID ): secio .Transport (key_pair ),
390- TProtocol (PLAINTEXT_PROTOCOL_ID ): InsecureTransport (
486+ # Only include transports whose optional extras are installed.
487+ if sec_opt is not None :
488+ secure_transports_by_protocol : Mapping [TProtocol , ISecureTransport ] = sec_opt
489+ else :
490+ _sec_map : dict [TProtocol , ISecureTransport ] = {}
491+ if _HAS_NOISE and NoiseTransport is not None :
492+ _sec_map [NOISE_PROTOCOL_ID ] = NoiseTransport (
493+ key_pair , noise_privkey = noise_key_pair .private_key
494+ )
495+ if _HAS_TLS and TLSTransport is not None :
496+ _sec_map [TLS_PROTOCOL_ID ] = TLSTransport (
497+ key_pair , enable_autotls = enable_autotls
498+ )
499+ if _HAS_SECIO and secio is not None :
500+ _sec_map [TProtocol (secio .ID )] = secio .Transport (key_pair )
501+ _sec_map [TProtocol (PLAINTEXT_PROTOCOL_ID )] = InsecureTransport (
391502 key_pair , peerstore = peerstore_opt
392- ),
393- }
503+ )
504+ secure_transports_by_protocol = _sec_map
394505
395506 # Use given muxer preference if provided, otherwise use global default
396507 if muxer_preference is not None :
@@ -477,7 +588,7 @@ def new_host(
477588 bootstrap : list [str ] | None = None ,
478589 negotiate_timeout : int = DEFAULT_NEGOTIATE_TIMEOUT ,
479590 enable_quic : bool = False ,
480- quic_transport_opt : QUICTransportConfig | None = None ,
591+ quic_transport_opt : Any | None = None ,
481592 tls_client_config : ssl .SSLContext | None = None ,
482593 tls_server_config : ssl .SSLContext | None = None ,
483594 resource_manager : ResourceManager | None = None ,
@@ -524,7 +635,7 @@ def new_host(
524635
525636 # Determine the connection config to use
526637 # QUIC transport config takes precedence if QUIC is enabled
527- effective_config : ConnectionConfig | QUICTransportConfig | None
638+ effective_config : ConnectionConfig | Any | None
528639 if enable_quic and quic_transport_opt is not None :
529640 effective_config = quic_transport_opt
530641 else :
0 commit comments