diff --git a/libp2p/transport/webrtc/_varint.py b/libp2p/transport/webrtc/_varint.py deleted file mode 100644 index 677aef3c9..000000000 --- a/libp2p/transport/webrtc/_varint.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Unsigned varint encoding for WebRTC data-channel and signaling framing. - -Both stream-level data-channel framing and signaling stream framing use the -same unsigned-varint length-prefix encoding documented in the libp2p -WebRTC spec. These sync helpers are shared between modules; for streaming -async reads see :func:`libp2p.transport.webrtc.signaling._read_uvarint`. -""" - -from __future__ import annotations - -# Spec ceiling: a varint encodes at most uint64, which fits in 10 bytes. -_MAX_VARINT_BYTES = 10 - - -def encode_uvarint(value: int) -> bytes: - """Encode a non-negative integer as an unsigned varint.""" - if value < 0: - raise ValueError("uvarint cannot encode negative values") - buf = bytearray() - while value > 0x7F: - buf.append((value & 0x7F) | 0x80) - value >>= 7 - buf.append(value & 0x7F) - return bytes(buf) - - -def decode_uvarint(data: bytes | bytearray, offset: int = 0) -> tuple[int, int]: - """ - Decode an unsigned varint from *data* starting at *offset*. - - :returns: ``(value, bytes_consumed)``. - :raises ValueError: If the varint is truncated or exceeds 10 bytes. - """ - result = 0 - shift = 0 - for i in range(_MAX_VARINT_BYTES): - pos = offset + i - if pos >= len(data): - raise ValueError("truncated uvarint") - byte = data[pos] - result |= (byte & 0x7F) << shift - if not (byte & 0x80): - return result, i + 1 - shift += 7 - raise ValueError(f"uvarint exceeds {_MAX_VARINT_BYTES} bytes") diff --git a/libp2p/transport/webrtc/signaling.py b/libp2p/transport/webrtc/signaling.py index f96073739..cab15c78d 100644 --- a/libp2p/transport/webrtc/signaling.py +++ b/libp2p/transport/webrtc/signaling.py @@ -32,8 +32,8 @@ import trio from libp2p.abc import INetStream +from libp2p.utils.varint import decode_uvarint_from_stream, encode_uvarint -from ._varint import encode_uvarint from .exceptions import WebRTCSignalingError from .signaling_pb.signaling_pb2 import SignalingMessage @@ -74,7 +74,7 @@ async def read_signaling_message(stream: INetStream) -> SignalingMessage: :raises WebRTCSignalingError: If reading or parsing fails. """ try: - length = await _read_uvarint(stream) + length = await decode_uvarint_from_stream(stream) if length > _MAX_SIGNALING_MSG_SIZE: raise WebRTCSignalingError( f"Signaling message too large: {length} bytes " @@ -261,24 +261,3 @@ async def _receive_expected(self, expected_type: int) -> SignalingMessage: f"Expected signaling message type {expected_type}, got {msg.type}" ) return msg - - -# ------------------------------------------------------------------ -# Streaming varint read (sync encoder/decoder live in ._varint) -# ------------------------------------------------------------------ - - -async def _read_uvarint(stream: INetStream) -> int: - """Read an unsigned varint from a libp2p :class:`INetStream`.""" - result = 0 - shift = 0 - for _ in range(10): # Max 10 bytes for uint64 varint - byte_data = await stream.read(1) - if not byte_data: - raise WebRTCSignalingError("Stream closed while reading varint") - byte = byte_data[0] - result |= (byte & 0x7F) << shift - if not (byte & 0x80): - return result - shift += 7 - raise WebRTCSignalingError("Varint too long (> 10 bytes)") diff --git a/libp2p/transport/webrtc/stream.py b/libp2p/transport/webrtc/stream.py index e1349f705..61bd3c7e5 100644 --- a/libp2p/transport/webrtc/stream.py +++ b/libp2p/transport/webrtc/stream.py @@ -19,8 +19,8 @@ import trio from libp2p.abc import IMuxedStream +from libp2p.utils.varint import decode_varint_with_size, encode_uvarint -from ._varint import decode_uvarint, encode_uvarint from .constants import MAX_MESSAGE_SIZE, MAX_PAYLOAD_SIZE from .exceptions import WebRTCStreamError from .pb.webrtc_pb2 import Message @@ -301,7 +301,7 @@ def on_data(self, raw: bytes) -> None: the mutations inline. """ try: - length, consumed = decode_uvarint(raw) + length, consumed = decode_varint_with_size(raw) except ValueError as e: logger.warning( "WebRTCStream channel=%d: malformed varint prefix: %s", diff --git a/newsfragments/1355.internal.rst b/newsfragments/1355.internal.rst new file mode 100644 index 000000000..34b47497a --- /dev/null +++ b/newsfragments/1355.internal.rst @@ -0,0 +1 @@ +Removed ``libp2p/transport/webrtc/_varint.py`` and migrated WebRTC stream and signaling framing to use the shared ``libp2p.utils.varint`` utilities (``encode_uvarint``, ``decode_varint_with_size``, ``decode_uvarint_from_stream``), eliminating a duplicate in-tree varint implementation. diff --git a/tests/core/transport/webrtc/test_connection.py b/tests/core/transport/webrtc/test_connection.py index d158d7e6a..d7e71cf37 100644 --- a/tests/core/transport/webrtc/test_connection.py +++ b/tests/core/transport/webrtc/test_connection.py @@ -124,8 +124,8 @@ class TestMessageRouting: async def test_on_channel_message_routes_to_stream(self): conn = _make_connection() stream = await conn.open_stream() - from libp2p.transport.webrtc._varint import encode_uvarint from libp2p.transport.webrtc.pb.webrtc_pb2 import Message + from libp2p.utils.varint import encode_uvarint proto = Message(message=b"test-data").SerializeToString() framed = encode_uvarint(len(proto)) + proto diff --git a/tests/core/transport/webrtc/test_signaling.py b/tests/core/transport/webrtc/test_signaling.py index ee1df1e3f..3f7962be7 100644 --- a/tests/core/transport/webrtc/test_signaling.py +++ b/tests/core/transport/webrtc/test_signaling.py @@ -13,14 +13,16 @@ import pytest import trio -from libp2p.transport.webrtc._varint import encode_uvarint as _encode_uvarint from libp2p.transport.webrtc.signaling import ( SignalingSession, - _read_uvarint, read_signaling_message, write_signaling_message, ) from libp2p.transport.webrtc.signaling_pb.signaling_pb2 import SignalingMessage +from libp2p.utils.varint import ( + decode_uvarint_from_stream as _read_uvarint, + encode_uvarint as _encode_uvarint, +) class MockStream: diff --git a/tests/core/transport/webrtc/test_stream.py b/tests/core/transport/webrtc/test_stream.py index 40657596f..bb58a89b2 100644 --- a/tests/core/transport/webrtc/test_stream.py +++ b/tests/core/transport/webrtc/test_stream.py @@ -9,10 +9,10 @@ import pytest -from libp2p.transport.webrtc._varint import decode_uvarint, encode_uvarint from libp2p.transport.webrtc.constants import MAX_PAYLOAD_SIZE from libp2p.transport.webrtc.pb.webrtc_pb2 import Message from libp2p.transport.webrtc.stream import StreamState, WebRTCStream +from libp2p.utils.varint import decode_varint_with_size, encode_uvarint def _framed(msg: Message) -> bytes: @@ -23,7 +23,7 @@ def _framed(msg: Message) -> bytes: def _parse_framed(raw: bytes) -> Message: """Inverse of :func:`_framed` — decode the wire format back to a Message.""" - length, consumed = decode_uvarint(raw) + length, consumed = decode_varint_with_size(raw) msg = Message() msg.ParseFromString(raw[consumed : consumed + length]) return msg