選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

117 行
4.3 KiB

  1. from dataclasses import dataclass, field
  2. from typing import Any, Callable, Mapping
  3. from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead
  4. from ..abc import AnyByteReceiveStream, ByteReceiveStream
  5. @dataclass(eq=False)
  6. class BufferedByteReceiveStream(ByteReceiveStream):
  7. """
  8. Wraps any bytes-based receive stream and uses a buffer to provide sophisticated receiving
  9. capabilities in the form of a byte stream.
  10. """
  11. receive_stream: AnyByteReceiveStream
  12. _buffer: bytearray = field(init=False, default_factory=bytearray)
  13. _closed: bool = field(init=False, default=False)
  14. async def aclose(self) -> None:
  15. await self.receive_stream.aclose()
  16. self._closed = True
  17. @property
  18. def buffer(self) -> bytes:
  19. """The bytes currently in the buffer."""
  20. return bytes(self._buffer)
  21. @property
  22. def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
  23. return self.receive_stream.extra_attributes
  24. async def receive(self, max_bytes: int = 65536) -> bytes:
  25. if self._closed:
  26. raise ClosedResourceError
  27. if self._buffer:
  28. chunk = bytes(self._buffer[:max_bytes])
  29. del self._buffer[:max_bytes]
  30. return chunk
  31. elif isinstance(self.receive_stream, ByteReceiveStream):
  32. return await self.receive_stream.receive(max_bytes)
  33. else:
  34. # With a bytes-oriented object stream, we need to handle any surplus bytes we get from
  35. # the receive() call
  36. chunk = await self.receive_stream.receive()
  37. if len(chunk) > max_bytes:
  38. # Save the surplus bytes in the buffer
  39. self._buffer.extend(chunk[max_bytes:])
  40. return chunk[:max_bytes]
  41. else:
  42. return chunk
  43. async def receive_exactly(self, nbytes: int) -> bytes:
  44. """
  45. Read exactly the given amount of bytes from the stream.
  46. :param nbytes: the number of bytes to read
  47. :return: the bytes read
  48. :raises ~anyio.IncompleteRead: if the stream was closed before the requested
  49. amount of bytes could be read from the stream
  50. """
  51. while True:
  52. remaining = nbytes - len(self._buffer)
  53. if remaining <= 0:
  54. retval = self._buffer[:nbytes]
  55. del self._buffer[:nbytes]
  56. return bytes(retval)
  57. try:
  58. if isinstance(self.receive_stream, ByteReceiveStream):
  59. chunk = await self.receive_stream.receive(remaining)
  60. else:
  61. chunk = await self.receive_stream.receive()
  62. except EndOfStream as exc:
  63. raise IncompleteRead from exc
  64. self._buffer.extend(chunk)
  65. async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes:
  66. """
  67. Read from the stream until the delimiter is found or max_bytes have been read.
  68. :param delimiter: the marker to look for in the stream
  69. :param max_bytes: maximum number of bytes that will be read before raising
  70. :exc:`~anyio.DelimiterNotFound`
  71. :return: the bytes read (not including the delimiter)
  72. :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter
  73. was found
  74. :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the
  75. bytes read up to the maximum allowed
  76. """
  77. delimiter_size = len(delimiter)
  78. offset = 0
  79. while True:
  80. # Check if the delimiter can be found in the current buffer
  81. index = self._buffer.find(delimiter, offset)
  82. if index >= 0:
  83. found = self._buffer[:index]
  84. del self._buffer[:index + len(delimiter):]
  85. return bytes(found)
  86. # Check if the buffer is already at or over the limit
  87. if len(self._buffer) >= max_bytes:
  88. raise DelimiterNotFound(max_bytes)
  89. # Read more data into the buffer from the socket
  90. try:
  91. data = await self.receive_stream.receive()
  92. except EndOfStream as exc:
  93. raise IncompleteRead from exc
  94. # Move the offset forward and add the new data to the buffer
  95. offset = max(len(self._buffer) - delimiter_size + 1, 0)
  96. self._buffer.extend(data)