Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
dca354e
feat(webrtc): add protobuf schema, constants and exception hierarchy
yashksaini-coder Apr 11, 2026
cfc73ab
feat(webrtc): add certificate utilities and multiaddr support
yashksaini-coder Apr 11, 2026
d2d9177
feat(webrtc): add trio-asyncio bridge for aiortc integration
yashksaini-coder Apr 11, 2026
5a33166
feat(webrtc): add SDP builder and transport config
yashksaini-coder Apr 11, 2026
652e873
feat(webrtc): add data-channel stream and connection
yashksaini-coder Apr 11, 2026
5dd7ad2
feat(webrtc): add Noise XX handshake with DTLS prologue binding
yashksaini-coder Apr 11, 2026
cc32590
feat(webrtc): add WebRTC Direct transport and listener
yashksaini-coder Apr 11, 2026
af11614
refactor(swarm): generalize native-mux transport handling
yashksaini-coder Apr 11, 2026
aff06d7
feat(webrtc): add signaling protocol for private-to-private connections
yashksaini-coder Apr 11, 2026
e72410e
test(webrtc): add foundation tests for protobuf, certs and multiaddr
yashksaini-coder Apr 11, 2026
6b1c089
test(webrtc): add bridge and stream tests
yashksaini-coder Apr 11, 2026
86333a7
test(webrtc): add connection, SDP, noise and signaling tests
yashksaini-coder Apr 11, 2026
49cc1db
Merge remote-tracking branch 'upstream/main' into webrtc
yashksaini-coder Apr 11, 2026
494a90d
Merge remote-tracking branch 'upstream/main' into webrtc
yashksaini-coder Apr 13, 2026
072c729
docs(news): add WebRTC feature changelog entry for #546
yashksaini-coder Apr 13, 2026
69e8479
fix(webrtc): make dial() raise NotImplementedError until aiortc is wired
yashksaini-coder Apr 13, 2026
f235265
fix(webrtc): route asyncio-bridge callbacks through TrioToken safely
yashksaini-coder Apr 13, 2026
b97c6cc
fix(webrtc): correctness, robustness and protocol routing
yashksaini-coder Apr 13, 2026
7ca01ec
fix(webrtc): clean up imports, types and lint findings
yashksaini-coder Apr 13, 2026
c668ab8
test(webrtc): remove unused imports and shorten over-long literals
yashksaini-coder Apr 13, 2026
aa2ea93
fix: resolve CI blockers from acul71 review (#1309)
yashksaini-coder Apr 16, 2026
89c0a74
style(webrtc): move generic types from typing to collections.abc
yashksaini-coder Apr 16, 2026
7254672
docs(webrtc): add sphinx autodoc pages for webrtc transport
yashksaini-coder Apr 16, 2026
2af4b0b
fix(lint): resolve pyrefly typecheck errors for CI
yashksaini-coder Apr 16, 2026
c9f70eb
feat(webrtc): wire aiortc into WebRTC Direct transport
yashksaini-coder Apr 16, 2026
3c7c54b
feat(webrtc): add enable_webrtc parameter and integration tests
yashksaini-coder Apr 16, 2026
dd64481
feat(webrtc): add webrtc-direct to interop test infrastructure
yashksaini-coder Apr 16, 2026
918ce7a
fix(lint): remove unused imports and apply ruff format
yashksaini-coder Apr 16, 2026
5e60a30
fix(lint): add new aiortc files to pyrefly excludes
yashksaini-coder Apr 16, 2026
826ae34
fix(webrtc): address code review findings in aiortc wiring
yashksaini-coder Apr 16, 2026
b109aed
fix(lint): resolve mypy and pyrefly errors in aiortc wiring
yashksaini-coder Apr 16, 2026
7df4db9
fix: resolve CI lint and docs failures
yashksaini-coder Apr 16, 2026
eae622f
Merge remote-tracking branch 'origin/main' into webrtc
yashksaini-coder Apr 22, 2026
7ea7172
refactor(webrtc): drop nursery arg from listener.listen after #1308
yashksaini-coder Apr 22, 2026
297a1c1
Merge branch 'main' into webrtc
acul71 May 14, 2026
0b3cb62
Merge branch 'main' into webrtc
yashksaini-coder May 21, 2026
18608a4
Merge branch 'main' into webrtc
acul71 May 28, 2026
a0dd62e
Merge remote-tracking branch 'upstream/main' into webrtc
yashksaini-coder Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,11 @@
# Mocked ONLY for Sphinx/autodoc: this module does not exist in the codebase
# but some doc tools may try to import it. No real code references this import.
"libp2p.relay.circuit_v2.lib",
# aiortc is an optional dependency (install via libp2p[webrtc]).
# RTD doesn't have libsrtp2-dev so aiortc can't be installed there.
"aiortc",
"aiortc.rtcdtlstransport",
"aiortc.rtcconfiguration",
]

# Documents to append as an appendix to all manuals.
Expand Down
5 changes: 5 additions & 0 deletions docs/libp2p.transport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ Subpackages

libp2p.transport.websocket

.. toctree::
:maxdepth: 4

libp2p.transport.webrtc

Submodules
----------

Expand Down
21 changes: 21 additions & 0 deletions docs/libp2p.transport.webrtc.pb.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
libp2p.transport.webrtc.pb package
==================================

Submodules
----------

libp2p.transport.webrtc.pb.webrtc\_pb2 module
---------------------------------------------

.. automodule:: libp2p.transport.webrtc.pb.webrtc_pb2
:members:
:show-inheritance:
:undoc-members:

Module contents
---------------

.. automodule:: libp2p.transport.webrtc.pb
:members:
:show-inheritance:
:undoc-members:
134 changes: 134 additions & 0 deletions docs/libp2p.transport.webrtc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
libp2p.transport.webrtc package
===============================

Subpackages
-----------

.. toctree::
:maxdepth: 4

libp2p.transport.webrtc.pb
libp2p.transport.webrtc.signaling_pb

Submodules
----------

libp2p.transport.webrtc.certificate module
------------------------------------------

.. automodule:: libp2p.transport.webrtc.certificate
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.config module
-------------------------------------

.. automodule:: libp2p.transport.webrtc.config
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.connection module
-----------------------------------------

.. automodule:: libp2p.transport.webrtc.connection
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.constants module
----------------------------------------

.. automodule:: libp2p.transport.webrtc.constants
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.exceptions module
-----------------------------------------

.. automodule:: libp2p.transport.webrtc.exceptions
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.listener module
---------------------------------------

.. automodule:: libp2p.transport.webrtc.listener
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.multiaddr\_utils module
-----------------------------------------------

.. automodule:: libp2p.transport.webrtc.multiaddr_utils
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.noise\_handshake module
-----------------------------------------------

.. automodule:: libp2p.transport.webrtc.noise_handshake
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.private\_listener module
------------------------------------------------

.. automodule:: libp2p.transport.webrtc.private_listener
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.private\_transport module
-------------------------------------------------

.. automodule:: libp2p.transport.webrtc.private_transport
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.sdp module
----------------------------------

.. automodule:: libp2p.transport.webrtc.sdp
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.signaling module
----------------------------------------

.. automodule:: libp2p.transport.webrtc.signaling
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.stream module
-------------------------------------

.. automodule:: libp2p.transport.webrtc.stream
:members:
:show-inheritance:
:undoc-members:

libp2p.transport.webrtc.transport module
----------------------------------------

.. automodule:: libp2p.transport.webrtc.transport
:members:
:show-inheritance:
:undoc-members:

Module contents
---------------

.. automodule:: libp2p.transport.webrtc
:members:
:show-inheritance:
:undoc-members:
21 changes: 21 additions & 0 deletions docs/libp2p.transport.webrtc.signaling_pb.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
libp2p.transport.webrtc.signaling\_pb package
=============================================

Submodules
----------

libp2p.transport.webrtc.signaling\_pb.signaling\_pb2 module
-----------------------------------------------------------

.. automodule:: libp2p.transport.webrtc.signaling_pb.signaling_pb2
:members:
:show-inheritance:
:undoc-members:

Module contents
---------------

.. automodule:: libp2p.transport.webrtc.signaling_pb
:members:
:show-inheritance:
:undoc-members:
3 changes: 2 additions & 1 deletion interop/transport/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ FROM python:3.13-slim

WORKDIR /app

# Install system dependencies
# Install system dependencies (includes libsrtp2-dev for aiortc/WebRTC)
RUN apt-get update && apt-get install -y \
redis-tools \
build-essential \
cmake \
pkg-config \
libgmp-dev \
libsrtp2-dev \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
Expand Down
50 changes: 43 additions & 7 deletions interop/transport/ping_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def __init__(self, test_plans: bool = False) -> None:
if not self.transport:
raise ValueError("TRANSPORT environment variable is required")

standalone_transports = ["quic-v1"]
standalone_transports = ["quic-v1", "webrtc-direct"]

self.muxer: str | None = None
self.security: str | None = None
Expand Down Expand Up @@ -242,11 +242,11 @@ def __init__(self, test_plans: bool = False) -> None:

def validate_configuration(self) -> None:
"""Validate configuration parameters."""
valid_transports = ["tcp", "ws", "wss", "quic-v1"]
valid_transports = ["tcp", "ws", "wss", "quic-v1", "webrtc-direct"]
valid_security = ["noise", "plaintext", "tls"]
valid_muxers = ["mplex", "yamux"]
# Standalone transports don't use separate security/muxer
standalone_transports = ["quic-v1"]
# Standalone transports have security + muxing built-in
standalone_transports = ["quic-v1", "webrtc-direct"]

if self.transport not in valid_transports:
raise ValueError(
Expand All @@ -271,7 +271,7 @@ def create_security_options(
"""Create security options based on configuration."""
# Standalone transports (like quic-v1) have security built-in,
# no separate security needed
standalone_transports = ["quic-v1"]
standalone_transports = ["quic-v1", "webrtc-direct"]
if self.transport in standalone_transports:
# For standalone transports, return empty security options
# The security is handled by the transport itself
Expand Down Expand Up @@ -310,7 +310,7 @@ def create_muxer_options(self) -> Any:
"""Create muxer options based on configuration."""
# Standalone transports (like quic-v1) have muxing built-in,
# no separate muxer needed
standalone_transports = ["quic-v1"]
standalone_transports = ["quic-v1", "webrtc-direct"]
if self.transport in standalone_transports:
# For standalone transports, return None (no separate muxer)
# The muxing is handled by the transport itself
Expand Down Expand Up @@ -479,6 +479,17 @@ def _encapsulate_with_p2p(
return addr.encapsulate(multiaddr.Multiaddr(f"/p2p/{p2p_value}"))
return addr

def _build_webrtc_direct_addr(
self, ip_value: str, port: int
) -> multiaddr.Multiaddr:
"""Build WebRTC Direct address: /ip4|ip6/{ip}/udp/{port}/webrtc-direct."""
is_ipv6 = ":" in ip_value
if is_ipv6:
base = multiaddr.Multiaddr(f"/ip6/{ip_value}/udp/{port}")
else:
base = multiaddr.Multiaddr(f"/ip4/{ip_value}/udp/{port}")
return base.encapsulate(multiaddr.Multiaddr("/webrtc-direct"))

def _build_quic_addr(self, ip_value: str, port: int) -> multiaddr.Multiaddr:
"""
Build QUIC address from IP and port.
Expand Down Expand Up @@ -528,6 +539,27 @@ def create_listen_addresses(self, port: int = 0) -> list[multiaddr.Multiaddr]:
return quic_addrs
return [self._build_quic_addr("0.0.0.0", port)]

elif self.transport == "webrtc-direct":
# WebRTC Direct uses UDP like QUIC
webrtc_addrs = []
for addr in base_addrs:
try:
ip_value = self._get_ip_value(addr)
tcp_port = addr.value_for_protocol("tcp") or port
if ip_value:
wrtc_addr = self._build_webrtc_direct_addr(ip_value, tcp_port)
_, p2p_value = self._extract_and_preserve_p2p(addr)
wrtc_addr = self._encapsulate_with_p2p(wrtc_addr, p2p_value)
webrtc_addrs.append(wrtc_addr)
except Exception as e:
print(
f"Error building webrtc-direct addr from {addr}: {e}",
file=sys.stderr,
)
if webrtc_addrs:
return webrtc_addrs
return [self._build_webrtc_direct_addr("0.0.0.0", port)]

elif self.transport == "ws":
# Add /ws protocol to TCP addresses
# WebSocket addresses are used for both WS and WSS transports
Expand Down Expand Up @@ -737,8 +769,10 @@ def _filter_addresses_by_transport(
filtered.append(addr)
elif self.transport == "quic-v1" and "quic-v1" in protocols:
filtered.append(addr)
elif self.transport == "webrtc-direct" and "webrtc-direct" in protocols:
filtered.append(addr)
elif self.transport == "tcp" and not any(
p in protocols for p in ["ws", "wss", "quic-v1"]
p in protocols for p in ["ws", "wss", "quic-v1", "webrtc-direct"]
):
filtered.append(addr)
return filtered if filtered else addresses
Expand Down Expand Up @@ -859,6 +893,7 @@ async def run_listener(self) -> None:
muxer_opt=muxer_opt,
listen_addrs=listen_addrs,
enable_quic=(self.transport == "quic-v1"),
enable_webrtc=(self.transport == "webrtc-direct"),
tls_client_config=tls_client_config,
tls_server_config=tls_server_config,
)
Expand Down Expand Up @@ -1191,6 +1226,7 @@ async def run_dialer(self) -> None:
"sec_opt": sec_opt,
"muxer_opt": muxer_opt,
"enable_quic": (self.transport == "quic-v1"),
"enable_webrtc": (self.transport == "webrtc-direct"),
"tls_client_config": tls_client_config,
"tls_server_config": tls_server_config,
}
Expand Down
2 changes: 1 addition & 1 deletion interop/transport/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ authors = [
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"libp2p @ file:///app/py-libp2p", # local libp2p dependency is a snapshot based on ${commitSha} in Makefile
"libp2p[webrtc] @ file:///app/py-libp2p", # local libp2p with WebRTC extra
"redis>=4.0.0",
"typing-extensions>=4.0.0",
"cryptography>=41.0.0", # Required for TLS/WSS support
Expand Down
10 changes: 10 additions & 0 deletions libp2p/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ def new_swarm(
muxer_preference: Literal["YAMUX", "MPLEX"] | None = None,
listen_addrs: Sequence[multiaddr.Multiaddr] | None = None,
enable_quic: bool = False,
enable_webrtc: bool = False,
enable_autotls: bool = False,
retry_config: RetryConfig | None = None,
connection_config: ConnectionConfig | QUICTransportConfig | None = None,
Expand Down Expand Up @@ -378,6 +379,13 @@ def new_swarm(
enable_autotls=enable_autotls,
)

# If enable_webrtc is True, force WebRTC Direct transport
if enable_webrtc:
from libp2p.transport.webrtc.transport import WebRTCDirectTransport

logger.debug("new_swarm: Creating WebRTC Direct transport")
transport = WebRTCDirectTransport(private_key=key_pair.private_key)

logger.debug(f"new_swarm: Final transport type: {type(transport)}")

# Generate X25519 keypair for Noise
Expand Down Expand Up @@ -471,6 +479,7 @@ def new_host(
bootstrap: list[str] | None = None,
negotiate_timeout: int = DEFAULT_NEGOTIATE_TIMEOUT,
enable_quic: bool = False,
enable_webrtc: bool = False,
quic_transport_opt: QUICTransportConfig | None = None,
tls_client_config: ssl.SSLContext | None = None,
tls_server_config: ssl.SSLContext | None = None,
Expand Down Expand Up @@ -534,6 +543,7 @@ def new_host(

swarm = new_swarm(
enable_quic=enable_quic,
enable_webrtc=enable_webrtc,
key_pair=key_pair,
muxer_opt=muxer_opt,
sec_opt=sec_opt,
Expand Down
5 changes: 5 additions & 0 deletions libp2p/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3002,6 +3002,11 @@ class ITransport(ABC):

"""

# Transports that provide their own stream multiplexing (QUIC, WebRTC)
# override this to True. The swarm skips the TransportUpgrader for
# these transports and passes the connection directly to add_conn().
provides_native_muxing: bool = False

@abstractmethod
async def dial(self, maddr: Multiaddr) -> IRawConnection:
"""
Expand Down
Loading
Loading