Source code for FIREQ_CLIENT.network.send_worker

"""Threaded sender worker."""

import queue
import socket
import threading

from .protocol import Message


# ─── Threaded sender ──────────────────────────────────────────────
[docs] class SendWorker: """Sends framed messages via a socket using a background thread and a queue.""" def __init__(self, sock: socket.socket) -> None: """Initialize the sender with the socket and a background thread. :param sock: the socket used to send messages. :type sock: socket.socket """ self._sock = sock self._queue = queue.Queue() self._stop_event = threading.Event() self._thread = threading.Thread(target=self._sender_loop, daemon=True)
[docs] def start(self) -> None: """Start the background sending thread.""" self._thread.start()
[docs] def stop(self, timeout: float | None = None) -> None: """Stop the sending thread and close the socket. :param timeout: how long to wait for the thread to stop. :type timeout: float | None """ self._stop_event.set() # Unblock the queue by pushing a sentinel (optional) or close socket try: self._sock.shutdown(1) # SHUT_WR except OSError: pass self._sock.close() self._thread.join(timeout)
[docs] def send(self, message: Message) -> None: """Enqueue a message to be sent by the background thread. :param message: the message to enqueue. :type message: Message """ self._queue.put(message)
def _sender_loop(self) -> None: """Loop sending queued messages until the worker is stopped.""" try: while not self._stop_event.is_set(): try: msg = self._queue.get(timeout=0.5) # periodically check stop flag except queue.Empty: continue # send the message on the socket self._sock.sendmsg(msg.to_buffers()) self._queue.task_done() except (OSError, BrokenPipeError): if not self._stop_event.is_set(): raise