summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/websockets/sync
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/websockets/sync')
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/__init__.cpython-311.pycbin199 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/client.cpython-311.pycbin13185 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/connection.cpython-311.pycbin31271 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/messages.cpython-311.pycbin10271 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/server.cpython-311.pycbin21370 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/__pycache__/utils.cpython-311.pycbin1898 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/client.py328
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/connection.py773
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/messages.py281
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/server.py530
-rw-r--r--venv/lib/python3.11/site-packages/websockets/sync/utils.py46
12 files changed, 0 insertions, 1958 deletions
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__init__.py b/venv/lib/python3.11/site-packages/websockets/sync/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 7d70e67..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/client.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/client.cpython-311.pyc
deleted file mode 100644
index 79bd716..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/client.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/connection.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/connection.cpython-311.pyc
deleted file mode 100644
index ae821c1..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/connection.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/messages.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/messages.cpython-311.pyc
deleted file mode 100644
index e9aadf8..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/messages.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/server.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/server.cpython-311.pyc
deleted file mode 100644
index 4d8d13f..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/server.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/utils.cpython-311.pyc b/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/utils.cpython-311.pyc
deleted file mode 100644
index 683704e..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/__pycache__/utils.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/client.py b/venv/lib/python3.11/site-packages/websockets/sync/client.py
deleted file mode 100644
index 087ff5f..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/client.py
+++ /dev/null
@@ -1,328 +0,0 @@
-from __future__ import annotations
-
-import socket
-import ssl
-import threading
-from typing import Any, Optional, Sequence, Type
-
-from ..client import ClientProtocol
-from ..datastructures import HeadersLike
-from ..extensions.base import ClientExtensionFactory
-from ..extensions.permessage_deflate import enable_client_permessage_deflate
-from ..headers import validate_subprotocols
-from ..http import USER_AGENT
-from ..http11 import Response
-from ..protocol import CONNECTING, OPEN, Event
-from ..typing import LoggerLike, Origin, Subprotocol
-from ..uri import parse_uri
-from .connection import Connection
-from .utils import Deadline
-
-
-__all__ = ["connect", "unix_connect", "ClientConnection"]
-
-
-class ClientConnection(Connection):
- """
- Threaded implementation of a WebSocket client connection.
-
- :class:`ClientConnection` provides :meth:`recv` and :meth:`send` methods for
- receiving and sending messages.
-
- It supports iteration to receive messages::
-
- for message in websocket:
- process(message)
-
- The iterator exits normally when the connection is closed with close code
- 1000 (OK) or 1001 (going away) or without a close code. It raises a
- :exc:`~websockets.exceptions.ConnectionClosedError` when the connection is
- closed with any other code.
-
- Args:
- socket: Socket connected to a WebSocket server.
- protocol: Sans-I/O connection.
- close_timeout: Timeout for closing the connection in seconds.
-
- """
-
- def __init__(
- self,
- socket: socket.socket,
- protocol: ClientProtocol,
- *,
- close_timeout: Optional[float] = 10,
- ) -> None:
- self.protocol: ClientProtocol
- self.response_rcvd = threading.Event()
- super().__init__(
- socket,
- protocol,
- close_timeout=close_timeout,
- )
-
- def handshake(
- self,
- additional_headers: Optional[HeadersLike] = None,
- user_agent_header: Optional[str] = USER_AGENT,
- timeout: Optional[float] = None,
- ) -> None:
- """
- Perform the opening handshake.
-
- """
- with self.send_context(expected_state=CONNECTING):
- self.request = self.protocol.connect()
- if additional_headers is not None:
- self.request.headers.update(additional_headers)
- if user_agent_header is not None:
- self.request.headers["User-Agent"] = user_agent_header
- self.protocol.send_request(self.request)
-
- if not self.response_rcvd.wait(timeout):
- self.close_socket()
- self.recv_events_thread.join()
- raise TimeoutError("timed out during handshake")
-
- if self.response is None:
- self.close_socket()
- self.recv_events_thread.join()
- raise ConnectionError("connection closed during handshake")
-
- if self.protocol.state is not OPEN:
- self.recv_events_thread.join(self.close_timeout)
- self.close_socket()
- self.recv_events_thread.join()
-
- if self.protocol.handshake_exc is not None:
- raise self.protocol.handshake_exc
-
- def process_event(self, event: Event) -> None:
- """
- Process one incoming event.
-
- """
- # First event - handshake response.
- if self.response is None:
- assert isinstance(event, Response)
- self.response = event
- self.response_rcvd.set()
- # Later events - frames.
- else:
- super().process_event(event)
-
- def recv_events(self) -> None:
- """
- Read incoming data from the socket and process events.
-
- """
- try:
- super().recv_events()
- finally:
- # If the connection is closed during the handshake, unblock it.
- self.response_rcvd.set()
-
-
-def connect(
- uri: str,
- *,
- # TCP/TLS — unix and path are only for unix_connect()
- sock: Optional[socket.socket] = None,
- ssl_context: Optional[ssl.SSLContext] = None,
- server_hostname: Optional[str] = None,
- unix: bool = False,
- path: Optional[str] = None,
- # WebSocket
- origin: Optional[Origin] = None,
- extensions: Optional[Sequence[ClientExtensionFactory]] = None,
- subprotocols: Optional[Sequence[Subprotocol]] = None,
- additional_headers: Optional[HeadersLike] = None,
- user_agent_header: Optional[str] = USER_AGENT,
- compression: Optional[str] = "deflate",
- # Timeouts
- open_timeout: Optional[float] = 10,
- close_timeout: Optional[float] = 10,
- # Limits
- max_size: Optional[int] = 2**20,
- # Logging
- logger: Optional[LoggerLike] = None,
- # Escape hatch for advanced customization
- create_connection: Optional[Type[ClientConnection]] = None,
-) -> ClientConnection:
- """
- Connect to the WebSocket server at ``uri``.
-
- This function returns a :class:`ClientConnection` instance, which you can
- use to send and receive messages.
-
- :func:`connect` may be used as a context manager::
-
- async with websockets.sync.client.connect(...) as websocket:
- ...
-
- The connection is closed automatically when exiting the context.
-
- Args:
- uri: URI of the WebSocket server.
- sock: Preexisting TCP socket. ``sock`` overrides the host and port
- from ``uri``. You may call :func:`socket.create_connection` to
- create a suitable TCP socket.
- ssl_context: Configuration for enabling TLS on the connection.
- server_hostname: Host name for the TLS handshake. ``server_hostname``
- overrides the host name from ``uri``.
- origin: Value of the ``Origin`` header, for servers that require it.
- extensions: List of supported extensions, in order in which they
- should be negotiated and run.
- subprotocols: List of supported subprotocols, in order of decreasing
- preference.
- additional_headers (HeadersLike | None): Arbitrary HTTP headers to add
- to the handshake request.
- user_agent_header: Value of the ``User-Agent`` request header.
- It defaults to ``"Python/x.y.z websockets/X.Y"``.
- Setting it to :obj:`None` removes the header.
- compression: The "permessage-deflate" extension is enabled by default.
- Set ``compression`` to :obj:`None` to disable it. See the
- :doc:`compression guide <../../topics/compression>` for details.
- open_timeout: Timeout for opening the connection in seconds.
- :obj:`None` disables the timeout.
- close_timeout: Timeout for closing the connection in seconds.
- :obj:`None` disables the timeout.
- max_size: Maximum size of incoming messages in bytes.
- :obj:`None` disables the limit.
- logger: Logger for this client.
- It defaults to ``logging.getLogger("websockets.client")``.
- See the :doc:`logging guide <../../topics/logging>` for details.
- create_connection: Factory for the :class:`ClientConnection` managing
- the connection. Set it to a wrapper or a subclass to customize
- connection handling.
-
- Raises:
- InvalidURI: If ``uri`` isn't a valid WebSocket URI.
- OSError: If the TCP connection fails.
- InvalidHandshake: If the opening handshake fails.
- TimeoutError: If the opening handshake times out.
-
- """
-
- # Process parameters
-
- wsuri = parse_uri(uri)
- if not wsuri.secure and ssl_context is not None:
- raise TypeError("ssl_context argument is incompatible with a ws:// URI")
-
- if unix:
- if path is None and sock is None:
- raise TypeError("missing path argument")
- elif path is not None and sock is not None:
- raise TypeError("path and sock arguments are incompatible")
- else:
- assert path is None # private argument, only set by unix_connect()
-
- if subprotocols is not None:
- validate_subprotocols(subprotocols)
-
- if compression == "deflate":
- extensions = enable_client_permessage_deflate(extensions)
- elif compression is not None:
- raise ValueError(f"unsupported compression: {compression}")
-
- # Calculate timeouts on the TCP, TLS, and WebSocket handshakes.
- # The TCP and TLS timeouts must be set on the socket, then removed
- # to avoid conflicting with the WebSocket timeout in handshake().
- deadline = Deadline(open_timeout)
-
- if create_connection is None:
- create_connection = ClientConnection
-
- try:
- # Connect socket
-
- if sock is None:
- if unix:
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.settimeout(deadline.timeout())
- assert path is not None # validated above -- this is for mpypy
- sock.connect(path)
- else:
- sock = socket.create_connection(
- (wsuri.host, wsuri.port),
- deadline.timeout(),
- )
- sock.settimeout(None)
-
- # Disable Nagle algorithm
-
- if not unix:
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
-
- # Initialize TLS wrapper and perform TLS handshake
-
- if wsuri.secure:
- if ssl_context is None:
- ssl_context = ssl.create_default_context()
- if server_hostname is None:
- server_hostname = wsuri.host
- sock.settimeout(deadline.timeout())
- sock = ssl_context.wrap_socket(sock, server_hostname=server_hostname)
- sock.settimeout(None)
-
- # Initialize WebSocket connection
-
- protocol = ClientProtocol(
- wsuri,
- origin=origin,
- extensions=extensions,
- subprotocols=subprotocols,
- state=CONNECTING,
- max_size=max_size,
- logger=logger,
- )
-
- # Initialize WebSocket protocol
-
- connection = create_connection(
- sock,
- protocol,
- close_timeout=close_timeout,
- )
- # On failure, handshake() closes the socket and raises an exception.
- connection.handshake(
- additional_headers,
- user_agent_header,
- deadline.timeout(),
- )
-
- except Exception:
- if sock is not None:
- sock.close()
- raise
-
- return connection
-
-
-def unix_connect(
- path: Optional[str] = None,
- uri: Optional[str] = None,
- **kwargs: Any,
-) -> ClientConnection:
- """
- Connect to a WebSocket server listening on a Unix socket.
-
- This function is identical to :func:`connect`, except for the additional
- ``path`` argument. It's only available on Unix.
-
- It's mainly useful for debugging servers listening on Unix sockets.
-
- Args:
- path: File system path to the Unix socket.
- uri: URI of the WebSocket server. ``uri`` defaults to
- ``ws://localhost/`` or, when a ``ssl_context`` is provided, to
- ``wss://localhost/``.
-
- """
- if uri is None:
- if kwargs.get("ssl_context") is None:
- uri = "ws://localhost/"
- else:
- uri = "wss://localhost/"
- return connect(uri=uri, unix=True, path=path, **kwargs)
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/connection.py b/venv/lib/python3.11/site-packages/websockets/sync/connection.py
deleted file mode 100644
index 4a8879e..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/connection.py
+++ /dev/null
@@ -1,773 +0,0 @@
-from __future__ import annotations
-
-import contextlib
-import logging
-import random
-import socket
-import struct
-import threading
-import uuid
-from types import TracebackType
-from typing import Any, Dict, Iterable, Iterator, Mapping, Optional, Type, Union
-
-from ..exceptions import ConnectionClosed, ConnectionClosedOK, ProtocolError
-from ..frames import DATA_OPCODES, BytesLike, CloseCode, Frame, Opcode, prepare_ctrl
-from ..http11 import Request, Response
-from ..protocol import CLOSED, OPEN, Event, Protocol, State
-from ..typing import Data, LoggerLike, Subprotocol
-from .messages import Assembler
-from .utils import Deadline
-
-
-__all__ = ["Connection"]
-
-logger = logging.getLogger(__name__)
-
-
-class Connection:
- """
- Threaded implementation of a WebSocket connection.
-
- :class:`Connection` provides APIs shared between WebSocket servers and
- clients.
-
- You shouldn't use it directly. Instead, use
- :class:`~websockets.sync.client.ClientConnection` or
- :class:`~websockets.sync.server.ServerConnection`.
-
- """
-
- recv_bufsize = 65536
-
- def __init__(
- self,
- socket: socket.socket,
- protocol: Protocol,
- *,
- close_timeout: Optional[float] = 10,
- ) -> None:
- self.socket = socket
- self.protocol = protocol
- self.close_timeout = close_timeout
-
- # Inject reference to this instance in the protocol's logger.
- self.protocol.logger = logging.LoggerAdapter(
- self.protocol.logger,
- {"websocket": self},
- )
-
- # Copy attributes from the protocol for convenience.
- self.id: uuid.UUID = self.protocol.id
- """Unique identifier of the connection. Useful in logs."""
- self.logger: LoggerLike = self.protocol.logger
- """Logger for this connection."""
- self.debug = self.protocol.debug
-
- # HTTP handshake request and response.
- self.request: Optional[Request] = None
- """Opening handshake request."""
- self.response: Optional[Response] = None
- """Opening handshake response."""
-
- # Mutex serializing interactions with the protocol.
- self.protocol_mutex = threading.Lock()
-
- # Assembler turning frames into messages and serializing reads.
- self.recv_messages = Assembler()
-
- # Whether we are busy sending a fragmented message.
- self.send_in_progress = False
-
- # Deadline for the closing handshake.
- self.close_deadline: Optional[Deadline] = None
-
- # Mapping of ping IDs to pong waiters, in chronological order.
- self.pings: Dict[bytes, threading.Event] = {}
-
- # Receiving events from the socket.
- self.recv_events_thread = threading.Thread(target=self.recv_events)
- self.recv_events_thread.start()
-
- # Exception raised in recv_events, to be chained to ConnectionClosed
- # in the user thread in order to show why the TCP connection dropped.
- self.recv_events_exc: Optional[BaseException] = None
-
- # Public attributes
-
- @property
- def local_address(self) -> Any:
- """
- Local address of the connection.
-
- For IPv4 connections, this is a ``(host, port)`` tuple.
-
- The format of the address depends on the address family.
- See :meth:`~socket.socket.getsockname`.
-
- """
- return self.socket.getsockname()
-
- @property
- def remote_address(self) -> Any:
- """
- Remote address of the connection.
-
- For IPv4 connections, this is a ``(host, port)`` tuple.
-
- The format of the address depends on the address family.
- See :meth:`~socket.socket.getpeername`.
-
- """
- return self.socket.getpeername()
-
- @property
- def subprotocol(self) -> Optional[Subprotocol]:
- """
- Subprotocol negotiated during the opening handshake.
-
- :obj:`None` if no subprotocol was negotiated.
-
- """
- return self.protocol.subprotocol
-
- # Public methods
-
- def __enter__(self) -> Connection:
- return self
-
- def __exit__(
- self,
- exc_type: Optional[Type[BaseException]],
- exc_value: Optional[BaseException],
- traceback: Optional[TracebackType],
- ) -> None:
- if exc_type is None:
- self.close()
- else:
- self.close(CloseCode.INTERNAL_ERROR)
-
- def __iter__(self) -> Iterator[Data]:
- """
- Iterate on incoming messages.
-
- The iterator calls :meth:`recv` and yields messages in an infinite loop.
-
- It exits when the connection is closed normally. It raises a
- :exc:`~websockets.exceptions.ConnectionClosedError` exception after a
- protocol error or a network failure.
-
- """
- try:
- while True:
- yield self.recv()
- except ConnectionClosedOK:
- return
-
- def recv(self, timeout: Optional[float] = None) -> Data:
- """
- Receive the next message.
-
- When the connection is closed, :meth:`recv` raises
- :exc:`~websockets.exceptions.ConnectionClosed`. Specifically, it raises
- :exc:`~websockets.exceptions.ConnectionClosedOK` after a normal closure
- and :exc:`~websockets.exceptions.ConnectionClosedError` after a protocol
- error or a network failure. This is how you detect the end of the
- message stream.
-
- If ``timeout`` is :obj:`None`, block until a message is received. If
- ``timeout`` is set and no message is received within ``timeout``
- seconds, raise :exc:`TimeoutError`. Set ``timeout`` to ``0`` to check if
- a message was already received.
-
- If the message is fragmented, wait until all fragments are received,
- reassemble them, and return the whole message.
-
- Returns:
- A string (:class:`str`) for a Text_ frame or a bytestring
- (:class:`bytes`) for a Binary_ frame.
-
- .. _Text: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
- .. _Binary: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
-
- Raises:
- ConnectionClosed: When the connection is closed.
- RuntimeError: If two threads call :meth:`recv` or
- :meth:`recv_streaming` concurrently.
-
- """
- try:
- return self.recv_messages.get(timeout)
- except EOFError:
- raise self.protocol.close_exc from self.recv_events_exc
- except RuntimeError:
- raise RuntimeError(
- "cannot call recv while another thread "
- "is already running recv or recv_streaming"
- ) from None
-
- def recv_streaming(self) -> Iterator[Data]:
- """
- Receive the next message frame by frame.
-
- If the message is fragmented, yield each fragment as it is received.
- The iterator must be fully consumed, or else the connection will become
- unusable.
-
- :meth:`recv_streaming` raises the same exceptions as :meth:`recv`.
-
- Returns:
- An iterator of strings (:class:`str`) for a Text_ frame or
- bytestrings (:class:`bytes`) for a Binary_ frame.
-
- .. _Text: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
- .. _Binary: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
-
- Raises:
- ConnectionClosed: When the connection is closed.
- RuntimeError: If two threads call :meth:`recv` or
- :meth:`recv_streaming` concurrently.
-
- """
- try:
- yield from self.recv_messages.get_iter()
- except EOFError:
- raise self.protocol.close_exc from self.recv_events_exc
- except RuntimeError:
- raise RuntimeError(
- "cannot call recv_streaming while another thread "
- "is already running recv or recv_streaming"
- ) from None
-
- def send(self, message: Union[Data, Iterable[Data]]) -> None:
- """
- Send a message.
-
- A string (:class:`str`) is sent as a Text_ frame. A bytestring or
- bytes-like object (:class:`bytes`, :class:`bytearray`, or
- :class:`memoryview`) is sent as a Binary_ frame.
-
- .. _Text: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
- .. _Binary: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
-
- :meth:`send` also accepts an iterable of strings, bytestrings, or
- bytes-like objects to enable fragmentation_. Each item is treated as a
- message fragment and sent in its own frame. All items must be of the
- same type, or else :meth:`send` will raise a :exc:`TypeError` and the
- connection will be closed.
-
- .. _fragmentation: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.4
-
- :meth:`send` rejects dict-like objects because this is often an error.
- (If you really want to send the keys of a dict-like object as fragments,
- call its :meth:`~dict.keys` method and pass the result to :meth:`send`.)
-
- When the connection is closed, :meth:`send` raises
- :exc:`~websockets.exceptions.ConnectionClosed`. Specifically, it
- raises :exc:`~websockets.exceptions.ConnectionClosedOK` after a normal
- connection closure and
- :exc:`~websockets.exceptions.ConnectionClosedError` after a protocol
- error or a network failure.
-
- Args:
- message: Message to send.
-
- Raises:
- ConnectionClosed: When the connection is closed.
- RuntimeError: If a connection is busy sending a fragmented message.
- TypeError: If ``message`` doesn't have a supported type.
-
- """
- # Unfragmented message -- this case must be handled first because
- # strings and bytes-like objects are iterable.
-
- if isinstance(message, str):
- with self.send_context():
- if self.send_in_progress:
- raise RuntimeError(
- "cannot call send while another thread "
- "is already running send"
- )
- self.protocol.send_text(message.encode("utf-8"))
-
- elif isinstance(message, BytesLike):
- with self.send_context():
- if self.send_in_progress:
- raise RuntimeError(
- "cannot call send while another thread "
- "is already running send"
- )
- self.protocol.send_binary(message)
-
- # Catch a common mistake -- passing a dict to send().
-
- elif isinstance(message, Mapping):
- raise TypeError("data is a dict-like object")
-
- # Fragmented message -- regular iterator.
-
- elif isinstance(message, Iterable):
- chunks = iter(message)
- try:
- chunk = next(chunks)
- except StopIteration:
- return
-
- try:
- # First fragment.
- if isinstance(chunk, str):
- text = True
- with self.send_context():
- if self.send_in_progress:
- raise RuntimeError(
- "cannot call send while another thread "
- "is already running send"
- )
- self.send_in_progress = True
- self.protocol.send_text(
- chunk.encode("utf-8"),
- fin=False,
- )
- elif isinstance(chunk, BytesLike):
- text = False
- with self.send_context():
- if self.send_in_progress:
- raise RuntimeError(
- "cannot call send while another thread "
- "is already running send"
- )
- self.send_in_progress = True
- self.protocol.send_binary(
- chunk,
- fin=False,
- )
- else:
- raise TypeError("data iterable must contain bytes or str")
-
- # Other fragments
- for chunk in chunks:
- if isinstance(chunk, str) and text:
- with self.send_context():
- assert self.send_in_progress
- self.protocol.send_continuation(
- chunk.encode("utf-8"),
- fin=False,
- )
- elif isinstance(chunk, BytesLike) and not text:
- with self.send_context():
- assert self.send_in_progress
- self.protocol.send_continuation(
- chunk,
- fin=False,
- )
- else:
- raise TypeError("data iterable must contain uniform types")
-
- # Final fragment.
- with self.send_context():
- self.protocol.send_continuation(b"", fin=True)
- self.send_in_progress = False
-
- except RuntimeError:
- # We didn't start sending a fragmented message.
- raise
-
- except Exception:
- # We're half-way through a fragmented message and we can't
- # complete it. This makes the connection unusable.
- with self.send_context():
- self.protocol.fail(
- CloseCode.INTERNAL_ERROR,
- "error in fragmented message",
- )
- raise
-
- else:
- raise TypeError("data must be bytes, str, or iterable")
-
- def close(self, code: int = CloseCode.NORMAL_CLOSURE, reason: str = "") -> None:
- """
- Perform the closing handshake.
-
- :meth:`close` waits for the other end to complete the handshake, for the
- TCP connection to terminate, and for all incoming messages to be read
- with :meth:`recv`.
-
- :meth:`close` is idempotent: it doesn't do anything once the
- connection is closed.
-
- Args:
- code: WebSocket close code.
- reason: WebSocket close reason.
-
- """
- try:
- # The context manager takes care of waiting for the TCP connection
- # to terminate after calling a method that sends a close frame.
- with self.send_context():
- if self.send_in_progress:
- self.protocol.fail(
- CloseCode.INTERNAL_ERROR,
- "close during fragmented message",
- )
- else:
- self.protocol.send_close(code, reason)
- except ConnectionClosed:
- # Ignore ConnectionClosed exceptions raised from send_context().
- # They mean that the connection is closed, which was the goal.
- pass
-
- def ping(self, data: Optional[Data] = None) -> threading.Event:
- """
- Send a Ping_.
-
- .. _Ping: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.2
-
- A ping may serve as a keepalive or as a check that the remote endpoint
- received all messages up to this point
-
- Args:
- data: Payload of the ping. A :class:`str` will be encoded to UTF-8.
- If ``data`` is :obj:`None`, the payload is four random bytes.
-
- Returns:
- An event that will be set when the corresponding pong is received.
- You can ignore it if you don't intend to wait.
-
- ::
-
- pong_event = ws.ping()
- pong_event.wait() # only if you want to wait for the pong
-
- Raises:
- ConnectionClosed: When the connection is closed.
- RuntimeError: If another ping was sent with the same data and
- the corresponding pong wasn't received yet.
-
- """
- if data is not None:
- data = prepare_ctrl(data)
-
- with self.send_context():
- # Protect against duplicates if a payload is explicitly set.
- if data in self.pings:
- raise RuntimeError("already waiting for a pong with the same data")
-
- # Generate a unique random payload otherwise.
- while data is None or data in self.pings:
- data = struct.pack("!I", random.getrandbits(32))
-
- pong_waiter = threading.Event()
- self.pings[data] = pong_waiter
- self.protocol.send_ping(data)
- return pong_waiter
-
- def pong(self, data: Data = b"") -> None:
- """
- Send a Pong_.
-
- .. _Pong: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.5.3
-
- An unsolicited pong may serve as a unidirectional heartbeat.
-
- Args:
- data: Payload of the pong. A :class:`str` will be encoded to UTF-8.
-
- Raises:
- ConnectionClosed: When the connection is closed.
-
- """
- data = prepare_ctrl(data)
-
- with self.send_context():
- self.protocol.send_pong(data)
-
- # Private methods
-
- def process_event(self, event: Event) -> None:
- """
- Process one incoming event.
-
- This method is overridden in subclasses to handle the handshake.
-
- """
- assert isinstance(event, Frame)
- if event.opcode in DATA_OPCODES:
- self.recv_messages.put(event)
-
- if event.opcode is Opcode.PONG:
- self.acknowledge_pings(bytes(event.data))
-
- def acknowledge_pings(self, data: bytes) -> None:
- """
- Acknowledge pings when receiving a pong.
-
- """
- with self.protocol_mutex:
- # Ignore unsolicited pong.
- if data not in self.pings:
- return
- # Sending a pong for only the most recent ping is legal.
- # Acknowledge all previous pings too in that case.
- ping_id = None
- ping_ids = []
- for ping_id, ping in self.pings.items():
- ping_ids.append(ping_id)
- ping.set()
- if ping_id == data:
- break
- else:
- raise AssertionError("solicited pong not found in pings")
- # Remove acknowledged pings from self.pings.
- for ping_id in ping_ids:
- del self.pings[ping_id]
-
- def recv_events(self) -> None:
- """
- Read incoming data from the socket and process events.
-
- Run this method in a thread as long as the connection is alive.
-
- ``recv_events()`` exits immediately when the ``self.socket`` is closed.
-
- """
- try:
- while True:
- try:
- if self.close_deadline is not None:
- self.socket.settimeout(self.close_deadline.timeout())
- data = self.socket.recv(self.recv_bufsize)
- except Exception as exc:
- if self.debug:
- self.logger.debug("error while receiving data", exc_info=True)
- # When the closing handshake is initiated by our side,
- # recv() may block until send_context() closes the socket.
- # In that case, send_context() already set recv_events_exc.
- # Calling set_recv_events_exc() avoids overwriting it.
- with self.protocol_mutex:
- self.set_recv_events_exc(exc)
- break
-
- if data == b"":
- break
-
- # Acquire the connection lock.
- with self.protocol_mutex:
- # Feed incoming data to the connection.
- self.protocol.receive_data(data)
-
- # This isn't expected to raise an exception.
- events = self.protocol.events_received()
-
- # Write outgoing data to the socket.
- try:
- self.send_data()
- except Exception as exc:
- if self.debug:
- self.logger.debug("error while sending data", exc_info=True)
- # Similarly to the above, avoid overriding an exception
- # set by send_context(), in case of a race condition
- # i.e. send_context() closes the socket after recv()
- # returns above but before send_data() calls send().
- self.set_recv_events_exc(exc)
- break
-
- if self.protocol.close_expected():
- # If the connection is expected to close soon, set the
- # close deadline based on the close timeout.
- if self.close_deadline is None:
- self.close_deadline = Deadline(self.close_timeout)
-
- # Unlock conn_mutex before processing events. Else, the
- # application can't send messages in response to events.
-
- # If self.send_data raised an exception, then events are lost.
- # Given that automatic responses write small amounts of data,
- # this should be uncommon, so we don't handle the edge case.
-
- try:
- for event in events:
- # This may raise EOFError if the closing handshake
- # times out while a message is waiting to be read.
- self.process_event(event)
- except EOFError:
- break
-
- # Breaking out of the while True: ... loop means that we believe
- # that the socket doesn't work anymore.
- with self.protocol_mutex:
- # Feed the end of the data stream to the connection.
- self.protocol.receive_eof()
-
- # This isn't expected to generate events.
- assert not self.protocol.events_received()
-
- # There is no error handling because send_data() can only write
- # the end of the data stream here and it handles errors itself.
- self.send_data()
-
- except Exception as exc:
- # This branch should never run. It's a safety net in case of bugs.
- self.logger.error("unexpected internal error", exc_info=True)
- with self.protocol_mutex:
- self.set_recv_events_exc(exc)
- # We don't know where we crashed. Force protocol state to CLOSED.
- self.protocol.state = CLOSED
- finally:
- # This isn't expected to raise an exception.
- self.close_socket()
-
- @contextlib.contextmanager
- def send_context(
- self,
- *,
- expected_state: State = OPEN, # CONNECTING during the opening handshake
- ) -> Iterator[None]:
- """
- Create a context for writing to the connection from user code.
-
- On entry, :meth:`send_context` acquires the connection lock and checks
- that the connection is open; on exit, it writes outgoing data to the
- socket::
-
- with self.send_context():
- self.protocol.send_text(message.encode("utf-8"))
-
- When the connection isn't open on entry, when the connection is expected
- to close on exit, or when an unexpected error happens, terminating the
- connection, :meth:`send_context` waits until the connection is closed
- then raises :exc:`~websockets.exceptions.ConnectionClosed`.
-
- """
- # Should we wait until the connection is closed?
- wait_for_close = False
- # Should we close the socket and raise ConnectionClosed?
- raise_close_exc = False
- # What exception should we chain ConnectionClosed to?
- original_exc: Optional[BaseException] = None
-
- # Acquire the protocol lock.
- with self.protocol_mutex:
- if self.protocol.state is expected_state:
- # Let the caller interact with the protocol.
- try:
- yield
- except (ProtocolError, RuntimeError):
- # The protocol state wasn't changed. Exit immediately.
- raise
- except Exception as exc:
- self.logger.error("unexpected internal error", exc_info=True)
- # This branch should never run. It's a safety net in case of
- # bugs. Since we don't know what happened, we will close the
- # connection and raise the exception to the caller.
- wait_for_close = False
- raise_close_exc = True
- original_exc = exc
- else:
- # Check if the connection is expected to close soon.
- if self.protocol.close_expected():
- wait_for_close = True
- # If the connection is expected to close soon, set the
- # close deadline based on the close timeout.
-
- # Since we tested earlier that protocol.state was OPEN
- # (or CONNECTING) and we didn't release protocol_mutex,
- # it is certain that self.close_deadline is still None.
- assert self.close_deadline is None
- self.close_deadline = Deadline(self.close_timeout)
- # Write outgoing data to the socket.
- try:
- self.send_data()
- except Exception as exc:
- if self.debug:
- self.logger.debug("error while sending data", exc_info=True)
- # While the only expected exception here is OSError,
- # other exceptions would be treated identically.
- wait_for_close = False
- raise_close_exc = True
- original_exc = exc
-
- else: # self.protocol.state is not expected_state
- # Minor layering violation: we assume that the connection
- # will be closing soon if it isn't in the expected state.
- wait_for_close = True
- raise_close_exc = True
-
- # To avoid a deadlock, release the connection lock by exiting the
- # context manager before waiting for recv_events() to terminate.
-
- # If the connection is expected to close soon and the close timeout
- # elapses, close the socket to terminate the connection.
- if wait_for_close:
- if self.close_deadline is None:
- timeout = self.close_timeout
- else:
- # Thread.join() returns immediately if timeout is negative.
- timeout = self.close_deadline.timeout(raise_if_elapsed=False)
- self.recv_events_thread.join(timeout)
-
- if self.recv_events_thread.is_alive():
- # There's no risk to overwrite another error because
- # original_exc is never set when wait_for_close is True.
- assert original_exc is None
- original_exc = TimeoutError("timed out while closing connection")
- # Set recv_events_exc before closing the socket in order to get
- # proper exception reporting.
- raise_close_exc = True
- with self.protocol_mutex:
- self.set_recv_events_exc(original_exc)
-
- # If an error occurred, close the socket to terminate the connection and
- # raise an exception.
- if raise_close_exc:
- self.close_socket()
- self.recv_events_thread.join()
- raise self.protocol.close_exc from original_exc
-
- def send_data(self) -> None:
- """
- Send outgoing data.
-
- This method requires holding protocol_mutex.
-
- Raises:
- OSError: When a socket operations fails.
-
- """
- assert self.protocol_mutex.locked()
- for data in self.protocol.data_to_send():
- if data:
- if self.close_deadline is not None:
- self.socket.settimeout(self.close_deadline.timeout())
- self.socket.sendall(data)
- else:
- try:
- self.socket.shutdown(socket.SHUT_WR)
- except OSError: # socket already closed
- pass
-
- def set_recv_events_exc(self, exc: Optional[BaseException]) -> None:
- """
- Set recv_events_exc, if not set yet.
-
- This method requires holding protocol_mutex.
-
- """
- assert self.protocol_mutex.locked()
- if self.recv_events_exc is None:
- self.recv_events_exc = exc
-
- def close_socket(self) -> None:
- """
- Shutdown and close socket. Close message assembler.
-
- Calling close_socket() guarantees that recv_events() terminates. Indeed,
- recv_events() may block only on socket.recv() or on recv_messages.put().
-
- """
- # shutdown() is required to interrupt recv() on Linux.
- try:
- self.socket.shutdown(socket.SHUT_RDWR)
- except OSError:
- pass # socket is already closed
- self.socket.close()
- self.recv_messages.close()
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/messages.py b/venv/lib/python3.11/site-packages/websockets/sync/messages.py
deleted file mode 100644
index 67a2231..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/messages.py
+++ /dev/null
@@ -1,281 +0,0 @@
-from __future__ import annotations
-
-import codecs
-import queue
-import threading
-from typing import Iterator, List, Optional, cast
-
-from ..frames import Frame, Opcode
-from ..typing import Data
-
-
-__all__ = ["Assembler"]
-
-UTF8Decoder = codecs.getincrementaldecoder("utf-8")
-
-
-class Assembler:
- """
- Assemble messages from frames.
-
- """
-
- def __init__(self) -> None:
- # Serialize reads and writes -- except for reads via synchronization
- # primitives provided by the threading and queue modules.
- self.mutex = threading.Lock()
-
- # We create a latch with two events to ensure proper interleaving of
- # writing and reading messages.
- # put() sets this event to tell get() that a message can be fetched.
- self.message_complete = threading.Event()
- # get() sets this event to let put() that the message was fetched.
- self.message_fetched = threading.Event()
-
- # This flag prevents concurrent calls to get() by user code.
- self.get_in_progress = False
- # This flag prevents concurrent calls to put() by library code.
- self.put_in_progress = False
-
- # Decoder for text frames, None for binary frames.
- self.decoder: Optional[codecs.IncrementalDecoder] = None
-
- # Buffer of frames belonging to the same message.
- self.chunks: List[Data] = []
-
- # When switching from "buffering" to "streaming", we use a thread-safe
- # queue for transferring frames from the writing thread (library code)
- # to the reading thread (user code). We're buffering when chunks_queue
- # is None and streaming when it's a SimpleQueue. None is a sentinel
- # value marking the end of the stream, superseding message_complete.
-
- # Stream data from frames belonging to the same message.
- # Remove quotes around type when dropping Python < 3.9.
- self.chunks_queue: Optional["queue.SimpleQueue[Optional[Data]]"] = None
-
- # This flag marks the end of the stream.
- self.closed = False
-
- def get(self, timeout: Optional[float] = None) -> Data:
- """
- Read the next message.
-
- :meth:`get` returns a single :class:`str` or :class:`bytes`.
-
- If the message is fragmented, :meth:`get` waits until the last frame is
- received, then it reassembles the message and returns it. To receive
- messages frame by frame, use :meth:`get_iter` instead.
-
- Args:
- timeout: If a timeout is provided and elapses before a complete
- message is received, :meth:`get` raises :exc:`TimeoutError`.
-
- Raises:
- EOFError: If the stream of frames has ended.
- RuntimeError: If two threads run :meth:`get` or :meth:``get_iter`
- concurrently.
-
- """
- with self.mutex:
- if self.closed:
- raise EOFError("stream of frames ended")
-
- if self.get_in_progress:
- raise RuntimeError("get or get_iter is already running")
-
- self.get_in_progress = True
-
- # If the message_complete event isn't set yet, release the lock to
- # allow put() to run and eventually set it.
- # Locking with get_in_progress ensures only one thread can get here.
- completed = self.message_complete.wait(timeout)
-
- with self.mutex:
- self.get_in_progress = False
-
- # Waiting for a complete message timed out.
- if not completed:
- raise TimeoutError(f"timed out in {timeout:.1f}s")
-
- # get() was unblocked by close() rather than put().
- if self.closed:
- raise EOFError("stream of frames ended")
-
- assert self.message_complete.is_set()
- self.message_complete.clear()
-
- joiner: Data = b"" if self.decoder is None else ""
- # mypy cannot figure out that chunks have the proper type.
- message: Data = joiner.join(self.chunks) # type: ignore
-
- assert not self.message_fetched.is_set()
- self.message_fetched.set()
-
- self.chunks = []
- assert self.chunks_queue is None
-
- return message
-
- def get_iter(self) -> Iterator[Data]:
- """
- Stream the next message.
-
- Iterating the return value of :meth:`get_iter` yields a :class:`str` or
- :class:`bytes` for each frame in the message.
-
- The iterator must be fully consumed before calling :meth:`get_iter` or
- :meth:`get` again. Else, :exc:`RuntimeError` is raised.
-
- This method only makes sense for fragmented messages. If messages aren't
- fragmented, use :meth:`get` instead.
-
- Raises:
- EOFError: If the stream of frames has ended.
- RuntimeError: If two threads run :meth:`get` or :meth:``get_iter`
- concurrently.
-
- """
- with self.mutex:
- if self.closed:
- raise EOFError("stream of frames ended")
-
- if self.get_in_progress:
- raise RuntimeError("get or get_iter is already running")
-
- chunks = self.chunks
- self.chunks = []
- self.chunks_queue = cast(
- # Remove quotes around type when dropping Python < 3.9.
- "queue.SimpleQueue[Optional[Data]]",
- queue.SimpleQueue(),
- )
-
- # Sending None in chunk_queue supersedes setting message_complete
- # when switching to "streaming". If message is already complete
- # when the switch happens, put() didn't send None, so we have to.
- if self.message_complete.is_set():
- self.chunks_queue.put(None)
-
- self.get_in_progress = True
-
- # Locking with get_in_progress ensures only one thread can get here.
- yield from chunks
- while True:
- chunk = self.chunks_queue.get()
- if chunk is None:
- break
- yield chunk
-
- with self.mutex:
- self.get_in_progress = False
-
- assert self.message_complete.is_set()
- self.message_complete.clear()
-
- # get_iter() was unblocked by close() rather than put().
- if self.closed:
- raise EOFError("stream of frames ended")
-
- assert not self.message_fetched.is_set()
- self.message_fetched.set()
-
- assert self.chunks == []
- self.chunks_queue = None
-
- def put(self, frame: Frame) -> None:
- """
- Add ``frame`` to the next message.
-
- When ``frame`` is the final frame in a message, :meth:`put` waits until
- the message is fetched, either by calling :meth:`get` or by fully
- consuming the return value of :meth:`get_iter`.
-
- :meth:`put` assumes that the stream of frames respects the protocol. If
- it doesn't, the behavior is undefined.
-
- Raises:
- EOFError: If the stream of frames has ended.
- RuntimeError: If two threads run :meth:`put` concurrently.
-
- """
- with self.mutex:
- if self.closed:
- raise EOFError("stream of frames ended")
-
- if self.put_in_progress:
- raise RuntimeError("put is already running")
-
- if frame.opcode is Opcode.TEXT:
- self.decoder = UTF8Decoder(errors="strict")
- elif frame.opcode is Opcode.BINARY:
- self.decoder = None
- elif frame.opcode is Opcode.CONT:
- pass
- else:
- # Ignore control frames.
- return
-
- data: Data
- if self.decoder is not None:
- data = self.decoder.decode(frame.data, frame.fin)
- else:
- data = frame.data
-
- if self.chunks_queue is None:
- self.chunks.append(data)
- else:
- self.chunks_queue.put(data)
-
- if not frame.fin:
- return
-
- # Message is complete. Wait until it's fetched to return.
-
- assert not self.message_complete.is_set()
- self.message_complete.set()
-
- if self.chunks_queue is not None:
- self.chunks_queue.put(None)
-
- assert not self.message_fetched.is_set()
-
- self.put_in_progress = True
-
- # Release the lock to allow get() to run and eventually set the event.
- self.message_fetched.wait()
-
- with self.mutex:
- self.put_in_progress = False
-
- assert self.message_fetched.is_set()
- self.message_fetched.clear()
-
- # put() was unblocked by close() rather than get() or get_iter().
- if self.closed:
- raise EOFError("stream of frames ended")
-
- self.decoder = None
-
- def close(self) -> None:
- """
- End the stream of frames.
-
- Callling :meth:`close` concurrently with :meth:`get`, :meth:`get_iter`,
- or :meth:`put` is safe. They will raise :exc:`EOFError`.
-
- """
- with self.mutex:
- if self.closed:
- return
-
- self.closed = True
-
- # Unblock get or get_iter.
- if self.get_in_progress:
- self.message_complete.set()
- if self.chunks_queue is not None:
- self.chunks_queue.put(None)
-
- # Unblock put().
- if self.put_in_progress:
- self.message_fetched.set()
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/server.py b/venv/lib/python3.11/site-packages/websockets/sync/server.py
deleted file mode 100644
index 1476796..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/server.py
+++ /dev/null
@@ -1,530 +0,0 @@
-from __future__ import annotations
-
-import http
-import logging
-import os
-import selectors
-import socket
-import ssl
-import sys
-import threading
-from types import TracebackType
-from typing import Any, Callable, Optional, Sequence, Type
-
-from websockets.frames import CloseCode
-
-from ..extensions.base import ServerExtensionFactory
-from ..extensions.permessage_deflate import enable_server_permessage_deflate
-from ..headers import validate_subprotocols
-from ..http import USER_AGENT
-from ..http11 import Request, Response
-from ..protocol import CONNECTING, OPEN, Event
-from ..server import ServerProtocol
-from ..typing import LoggerLike, Origin, Subprotocol
-from .connection import Connection
-from .utils import Deadline
-
-
-__all__ = ["serve", "unix_serve", "ServerConnection", "WebSocketServer"]
-
-
-class ServerConnection(Connection):
- """
- Threaded implementation of a WebSocket server connection.
-
- :class:`ServerConnection` provides :meth:`recv` and :meth:`send` methods for
- receiving and sending messages.
-
- It supports iteration to receive messages::
-
- for message in websocket:
- process(message)
-
- The iterator exits normally when the connection is closed with close code
- 1000 (OK) or 1001 (going away) or without a close code. It raises a
- :exc:`~websockets.exceptions.ConnectionClosedError` when the connection is
- closed with any other code.
-
- Args:
- socket: Socket connected to a WebSocket client.
- protocol: Sans-I/O connection.
- close_timeout: Timeout for closing the connection in seconds.
-
- """
-
- def __init__(
- self,
- socket: socket.socket,
- protocol: ServerProtocol,
- *,
- close_timeout: Optional[float] = 10,
- ) -> None:
- self.protocol: ServerProtocol
- self.request_rcvd = threading.Event()
- super().__init__(
- socket,
- protocol,
- close_timeout=close_timeout,
- )
-
- def handshake(
- self,
- process_request: Optional[
- Callable[
- [ServerConnection, Request],
- Optional[Response],
- ]
- ] = None,
- process_response: Optional[
- Callable[
- [ServerConnection, Request, Response],
- Optional[Response],
- ]
- ] = None,
- server_header: Optional[str] = USER_AGENT,
- timeout: Optional[float] = None,
- ) -> None:
- """
- Perform the opening handshake.
-
- """
- if not self.request_rcvd.wait(timeout):
- self.close_socket()
- self.recv_events_thread.join()
- raise TimeoutError("timed out during handshake")
-
- if self.request is None:
- self.close_socket()
- self.recv_events_thread.join()
- raise ConnectionError("connection closed during handshake")
-
- with self.send_context(expected_state=CONNECTING):
- self.response = None
-
- if process_request is not None:
- try:
- self.response = process_request(self, self.request)
- except Exception as exc:
- self.protocol.handshake_exc = exc
- self.logger.error("opening handshake failed", exc_info=True)
- self.response = self.protocol.reject(
- http.HTTPStatus.INTERNAL_SERVER_ERROR,
- (
- "Failed to open a WebSocket connection.\n"
- "See server log for more information.\n"
- ),
- )
-
- if self.response is None:
- self.response = self.protocol.accept(self.request)
-
- if server_header is not None:
- self.response.headers["Server"] = server_header
-
- if process_response is not None:
- try:
- response = process_response(self, self.request, self.response)
- except Exception as exc:
- self.protocol.handshake_exc = exc
- self.logger.error("opening handshake failed", exc_info=True)
- self.response = self.protocol.reject(
- http.HTTPStatus.INTERNAL_SERVER_ERROR,
- (
- "Failed to open a WebSocket connection.\n"
- "See server log for more information.\n"
- ),
- )
- else:
- if response is not None:
- self.response = response
-
- self.protocol.send_response(self.response)
-
- if self.protocol.state is not OPEN:
- self.recv_events_thread.join(self.close_timeout)
- self.close_socket()
- self.recv_events_thread.join()
-
- if self.protocol.handshake_exc is not None:
- raise self.protocol.handshake_exc
-
- def process_event(self, event: Event) -> None:
- """
- Process one incoming event.
-
- """
- # First event - handshake request.
- if self.request is None:
- assert isinstance(event, Request)
- self.request = event
- self.request_rcvd.set()
- # Later events - frames.
- else:
- super().process_event(event)
-
- def recv_events(self) -> None:
- """
- Read incoming data from the socket and process events.
-
- """
- try:
- super().recv_events()
- finally:
- # If the connection is closed during the handshake, unblock it.
- self.request_rcvd.set()
-
-
-class WebSocketServer:
- """
- WebSocket server returned by :func:`serve`.
-
- This class mirrors the API of :class:`~socketserver.BaseServer`, notably the
- :meth:`~socketserver.BaseServer.serve_forever` and
- :meth:`~socketserver.BaseServer.shutdown` methods, as well as the context
- manager protocol.
-
- Args:
- socket: Server socket listening for new connections.
- handler: Handler for one connection. Receives the socket and address
- returned by :meth:`~socket.socket.accept`.
- logger: Logger for this server.
-
- """
-
- def __init__(
- self,
- socket: socket.socket,
- handler: Callable[[socket.socket, Any], None],
- logger: Optional[LoggerLike] = None,
- ):
- self.socket = socket
- self.handler = handler
- if logger is None:
- logger = logging.getLogger("websockets.server")
- self.logger = logger
- if sys.platform != "win32":
- self.shutdown_watcher, self.shutdown_notifier = os.pipe()
-
- def serve_forever(self) -> None:
- """
- See :meth:`socketserver.BaseServer.serve_forever`.
-
- This method doesn't return. Calling :meth:`shutdown` from another thread
- stops the server.
-
- Typical use::
-
- with serve(...) as server:
- server.serve_forever()
-
- """
- poller = selectors.DefaultSelector()
- poller.register(self.socket, selectors.EVENT_READ)
- if sys.platform != "win32":
- poller.register(self.shutdown_watcher, selectors.EVENT_READ)
-
- while True:
- poller.select()
- try:
- # If the socket is closed, this will raise an exception and exit
- # the loop. So we don't need to check the return value of select().
- sock, addr = self.socket.accept()
- except OSError:
- break
- thread = threading.Thread(target=self.handler, args=(sock, addr))
- thread.start()
-
- def shutdown(self) -> None:
- """
- See :meth:`socketserver.BaseServer.shutdown`.
-
- """
- self.socket.close()
- if sys.platform != "win32":
- os.write(self.shutdown_notifier, b"x")
-
- def fileno(self) -> int:
- """
- See :meth:`socketserver.BaseServer.fileno`.
-
- """
- return self.socket.fileno()
-
- def __enter__(self) -> WebSocketServer:
- return self
-
- def __exit__(
- self,
- exc_type: Optional[Type[BaseException]],
- exc_value: Optional[BaseException],
- traceback: Optional[TracebackType],
- ) -> None:
- self.shutdown()
-
-
-def serve(
- handler: Callable[[ServerConnection], None],
- host: Optional[str] = None,
- port: Optional[int] = None,
- *,
- # TCP/TLS — unix and path are only for unix_serve()
- sock: Optional[socket.socket] = None,
- ssl_context: Optional[ssl.SSLContext] = None,
- unix: bool = False,
- path: Optional[str] = None,
- # WebSocket
- origins: Optional[Sequence[Optional[Origin]]] = None,
- extensions: Optional[Sequence[ServerExtensionFactory]] = None,
- subprotocols: Optional[Sequence[Subprotocol]] = None,
- select_subprotocol: Optional[
- Callable[
- [ServerConnection, Sequence[Subprotocol]],
- Optional[Subprotocol],
- ]
- ] = None,
- process_request: Optional[
- Callable[
- [ServerConnection, Request],
- Optional[Response],
- ]
- ] = None,
- process_response: Optional[
- Callable[
- [ServerConnection, Request, Response],
- Optional[Response],
- ]
- ] = None,
- server_header: Optional[str] = USER_AGENT,
- compression: Optional[str] = "deflate",
- # Timeouts
- open_timeout: Optional[float] = 10,
- close_timeout: Optional[float] = 10,
- # Limits
- max_size: Optional[int] = 2**20,
- # Logging
- logger: Optional[LoggerLike] = None,
- # Escape hatch for advanced customization
- create_connection: Optional[Type[ServerConnection]] = None,
-) -> WebSocketServer:
- """
- Create a WebSocket server listening on ``host`` and ``port``.
-
- Whenever a client connects, the server creates a :class:`ServerConnection`,
- performs the opening handshake, and delegates to the ``handler``.
-
- The handler receives a :class:`ServerConnection` instance, which you can use
- to send and receive messages.
-
- Once the handler completes, either normally or with an exception, the server
- performs the closing handshake and closes the connection.
-
- :class:`WebSocketServer` mirrors the API of
- :class:`~socketserver.BaseServer`. Treat it as a context manager to ensure
- that it will be closed and call the :meth:`~WebSocketServer.serve_forever`
- method to serve requests::
-
- def handler(websocket):
- ...
-
- with websockets.sync.server.serve(handler, ...) as server:
- server.serve_forever()
-
- Args:
- handler: Connection handler. It receives the WebSocket connection,
- which is a :class:`ServerConnection`, in argument.
- host: Network interfaces the server binds to.
- See :func:`~socket.create_server` for details.
- port: TCP port the server listens on.
- See :func:`~socket.create_server` for details.
- sock: Preexisting TCP socket. ``sock`` replaces ``host`` and ``port``.
- You may call :func:`socket.create_server` to create a suitable TCP
- socket.
- ssl_context: Configuration for enabling TLS on the connection.
- origins: Acceptable values of the ``Origin`` header, for defending
- against Cross-Site WebSocket Hijacking attacks. Include :obj:`None`
- in the list if the lack of an origin is acceptable.
- extensions: List of supported extensions, in order in which they
- should be negotiated and run.
- subprotocols: List of supported subprotocols, in order of decreasing
- preference.
- select_subprotocol: Callback for selecting a subprotocol among
- those supported by the client and the server. It receives a
- :class:`ServerConnection` (not a
- :class:`~websockets.server.ServerProtocol`!) instance and a list of
- subprotocols offered by the client. Other than the first argument,
- it has the same behavior as the
- :meth:`ServerProtocol.select_subprotocol
- <websockets.server.ServerProtocol.select_subprotocol>` method.
- process_request: Intercept the request during the opening handshake.
- Return an HTTP response to force the response or :obj:`None` to
- continue normally. When you force an HTTP 101 Continue response,
- the handshake is successful. Else, the connection is aborted.
- process_response: Intercept the response during the opening handshake.
- Return an HTTP response to force the response or :obj:`None` to
- continue normally. When you force an HTTP 101 Continue response,
- the handshake is successful. Else, the connection is aborted.
- server_header: Value of the ``Server`` response header.
- It defaults to ``"Python/x.y.z websockets/X.Y"``. Setting it to
- :obj:`None` removes the header.
- compression: The "permessage-deflate" extension is enabled by default.
- Set ``compression`` to :obj:`None` to disable it. See the
- :doc:`compression guide <../../topics/compression>` for details.
- open_timeout: Timeout for opening connections in seconds.
- :obj:`None` disables the timeout.
- close_timeout: Timeout for closing connections in seconds.
- :obj:`None` disables the timeout.
- max_size: Maximum size of incoming messages in bytes.
- :obj:`None` disables the limit.
- logger: Logger for this server.
- It defaults to ``logging.getLogger("websockets.server")``. See the
- :doc:`logging guide <../../topics/logging>` for details.
- create_connection: Factory for the :class:`ServerConnection` managing
- the connection. Set it to a wrapper or a subclass to customize
- connection handling.
- """
-
- # Process parameters
-
- if subprotocols is not None:
- validate_subprotocols(subprotocols)
-
- if compression == "deflate":
- extensions = enable_server_permessage_deflate(extensions)
- elif compression is not None:
- raise ValueError(f"unsupported compression: {compression}")
-
- if create_connection is None:
- create_connection = ServerConnection
-
- # Bind socket and listen
-
- if sock is None:
- if unix:
- if path is None:
- raise TypeError("missing path argument")
- sock = socket.create_server(path, family=socket.AF_UNIX)
- else:
- sock = socket.create_server((host, port))
- else:
- if path is not None:
- raise TypeError("path and sock arguments are incompatible")
-
- # Initialize TLS wrapper
-
- if ssl_context is not None:
- sock = ssl_context.wrap_socket(
- sock,
- server_side=True,
- # Delay TLS handshake until after we set a timeout on the socket.
- do_handshake_on_connect=False,
- )
-
- # Define request handler
-
- def conn_handler(sock: socket.socket, addr: Any) -> None:
- # Calculate timeouts on the TLS and WebSocket handshakes.
- # The TLS timeout must be set on the socket, then removed
- # to avoid conflicting with the WebSocket timeout in handshake().
- deadline = Deadline(open_timeout)
-
- try:
- # Disable Nagle algorithm
-
- if not unix:
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
-
- # Perform TLS handshake
-
- if ssl_context is not None:
- sock.settimeout(deadline.timeout())
- assert isinstance(sock, ssl.SSLSocket) # mypy cannot figure this out
- sock.do_handshake()
- sock.settimeout(None)
-
- # Create a closure so that select_subprotocol has access to self.
-
- protocol_select_subprotocol: Optional[
- Callable[
- [ServerProtocol, Sequence[Subprotocol]],
- Optional[Subprotocol],
- ]
- ] = None
-
- if select_subprotocol is not None:
-
- def protocol_select_subprotocol(
- protocol: ServerProtocol,
- subprotocols: Sequence[Subprotocol],
- ) -> Optional[Subprotocol]:
- # mypy doesn't know that select_subprotocol is immutable.
- assert select_subprotocol is not None
- # Ensure this function is only used in the intended context.
- assert protocol is connection.protocol
- return select_subprotocol(connection, subprotocols)
-
- # Initialize WebSocket connection
-
- protocol = ServerProtocol(
- origins=origins,
- extensions=extensions,
- subprotocols=subprotocols,
- select_subprotocol=protocol_select_subprotocol,
- state=CONNECTING,
- max_size=max_size,
- logger=logger,
- )
-
- # Initialize WebSocket protocol
-
- assert create_connection is not None # help mypy
- connection = create_connection(
- sock,
- protocol,
- close_timeout=close_timeout,
- )
- # On failure, handshake() closes the socket, raises an exception, and
- # logs it.
- connection.handshake(
- process_request,
- process_response,
- server_header,
- deadline.timeout(),
- )
-
- except Exception:
- sock.close()
- return
-
- try:
- handler(connection)
- except Exception:
- protocol.logger.error("connection handler failed", exc_info=True)
- connection.close(CloseCode.INTERNAL_ERROR)
- else:
- connection.close()
-
- # Initialize server
-
- return WebSocketServer(sock, conn_handler, logger)
-
-
-def unix_serve(
- handler: Callable[[ServerConnection], Any],
- path: Optional[str] = None,
- **kwargs: Any,
-) -> WebSocketServer:
- """
- Create a WebSocket server listening on a Unix socket.
-
- This function is identical to :func:`serve`, except the ``host`` and
- ``port`` arguments are replaced by ``path``. It's only available on Unix.
-
- It's useful for deploying a server behind a reverse proxy such as nginx.
-
- Args:
- handler: Connection handler. It receives the WebSocket connection,
- which is a :class:`ServerConnection`, in argument.
- path: File system path to the Unix socket.
-
- """
- return serve(handler, path=path, unix=True, **kwargs)
diff --git a/venv/lib/python3.11/site-packages/websockets/sync/utils.py b/venv/lib/python3.11/site-packages/websockets/sync/utils.py
deleted file mode 100644
index 471f32e..0000000
--- a/venv/lib/python3.11/site-packages/websockets/sync/utils.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from __future__ import annotations
-
-import time
-from typing import Optional
-
-
-__all__ = ["Deadline"]
-
-
-class Deadline:
- """
- Manage timeouts across multiple steps.
-
- Args:
- timeout: Time available in seconds or :obj:`None` if there is no limit.
-
- """
-
- def __init__(self, timeout: Optional[float]) -> None:
- self.deadline: Optional[float]
- if timeout is None:
- self.deadline = None
- else:
- self.deadline = time.monotonic() + timeout
-
- def timeout(self, *, raise_if_elapsed: bool = True) -> Optional[float]:
- """
- Calculate a timeout from a deadline.
-
- Args:
- raise_if_elapsed (bool): Whether to raise :exc:`TimeoutError`
- if the deadline lapsed.
-
- Raises:
- TimeoutError: If the deadline lapsed.
-
- Returns:
- Time left in seconds or :obj:`None` if there is no limit.
-
- """
- if self.deadline is None:
- return None
- timeout = self.deadline - time.monotonic()
- if raise_if_elapsed and timeout <= 0:
- raise TimeoutError("timed out")
- return timeout