Skip to content

Commit f69098d

Browse files
committed
complete all phases
1 parent ed41dd3 commit f69098d

22 files changed

Lines changed: 3059 additions & 104 deletions

libp2p/__init__.py

Lines changed: 159 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,23 @@
55
import logging
66
from pathlib import Path
77
import ssl
8-
from libp2p.transport.quic.utils import is_quic_multiaddr
98
from typing import Any
109
from cryptography.hazmat.primitives.asymmetric import ed25519
1110
from 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
1525
from collections.abc import (
1626
Mapping,
1727
Sequence,
@@ -86,24 +96,58 @@
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+
107151
from libp2p.transport.tcp.tcp import (
108152
TCP,
109153
)
@@ -113,6 +157,45 @@
113157
from 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
)
117200
import libp2p.utils
118201
from 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

240327
def 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

252343
def 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:

libp2p/custom_types.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,6 @@
55
)
66
from typing import TYPE_CHECKING, NewType, Union, cast
77

8-
from libp2p.transport.quic.stream import QUICStream
9-
10-
if TYPE_CHECKING:
11-
from libp2p.abc import IMuxedConn, IMuxedStream, INetStream, ISecureTransport
12-
from libp2p.transport.quic.connection import QUICConnection
13-
else:
14-
IMuxedConn = cast(type, object)
15-
INetStream = cast(type, object)
16-
ISecureTransport = cast(type, object)
17-
IMuxedStream = cast(type, object)
18-
QUICConnection = cast(type, object)
19-
20-
from libp2p.io.abc import (
21-
ReadWriteCloser,
22-
)
23-
from collections.abc import (
24-
Awaitable,
25-
Callable,
26-
Mapping,
27-
)
28-
from typing import TYPE_CHECKING, NewType, Union, cast
29-
308
if TYPE_CHECKING:
319
from libp2p.abc import IMuxedConn, IMuxedStream, INetStream, ISecureTransport
3210
else:

0 commit comments

Comments
 (0)