class BaseIrcConnection(QueueMixin, ABC):
'Collects low-level server-client connection management.'
+ _recv_bytes_total: bytes
+ _recv_buffer_linesep: bytes
+ _recv_last_ping_check: datetime
def __init__(self, hostname: str, port: int, **kwargs) -> None:
super().__init__(**kwargs)
pass
def _read_lines(self) -> Iterator[Optional[Event]]:
- assert self._socket is not None
- bytes_total = b''
- buffer_linesep = b''
- time_last_ping_check = datetime.now()
+ self._recv_bytes_total = b''
+ self._recv_buffer_linesep = b''
+ self._recv_last_ping_check = datetime.now()
try:
- while True:
- try:
- bytes_new = self._socket.recv(_CONN_RECV_BUFSIZE)
- except TimeoutError:
- if (datetime.now() - time_last_ping_check).seconds\
- > _TIMEOUT_PING:
- time_last_ping_check = datetime.now()
- yield self._on_handled_loop_exception(
- IrcConnException(ERR_STR_TIMEOUT, abort=False))
- else:
- yield None
- continue
- except ConnectionResetError as e:
- raise IrcConnException(retry=True) from e
- except socket_gaierror as e:
- raise IrcConnException(retry=e.errno == EAI_AGAIN) from e
- except OSError as e:
- if e.errno == EBADF:
- raise IrcConnException(retry=True) from e
- raise e
- if not bytes_new:
- break
- time_last_ping_check = datetime.now()
- for c in bytes_new:
- c_byted = c.to_bytes()
- if c not in _IRCSPEC_LINE_SEPARATOR:
- bytes_total += c_byted
- buffer_linesep = b''
- elif c == _IRCSPEC_LINE_SEPARATOR[0]:
- buffer_linesep = c_byted
- else:
- buffer_linesep += c_byted
- if buffer_linesep == _IRCSPEC_LINE_SEPARATOR:
- buffer_linesep = b''
- yield self._make_recv_event(
- IrcMessage.from_raw(bytes_total.decode('utf-8')))
- bytes_total = b''
+ yield from self._process_recv()
except IrcConnException as e:
yield self._on_handled_loop_exception(e)
+
+ def _process_recv(self) -> Iterator[Optional[Event]]:
+ while True:
+ try:
+ bytes_new = self._socket.recv(_CONN_RECV_BUFSIZE)
+ except TimeoutError:
+ if (datetime.now() - self._recv_last_ping_check).seconds\
+ > _TIMEOUT_PING:
+ self._recv_last_ping_check = datetime.now()
+ yield self._on_handled_loop_exception(
+ IrcConnException(ERR_STR_TIMEOUT, abort=False))
+ else:
+ yield None
+ continue
+ except ConnectionResetError as e:
+ raise IrcConnException(retry=True) from e
+ except socket_gaierror as e:
+ raise IrcConnException(retry=e.errno == EAI_AGAIN) from e
+ except OSError as e:
+ if e.errno == EBADF:
+ raise IrcConnException(retry=True) from e
+ raise e
+ if not bytes_new:
+ break
+ self._recv_last_ping_check = datetime.now()
+ for c in bytes_new:
+ c_byted = c.to_bytes()
+ if c not in _IRCSPEC_LINE_SEPARATOR:
+ self._recv_bytes_total += c_byted
+ self._recv_buffer_linesep = b''
+ elif c == _IRCSPEC_LINE_SEPARATOR[0]:
+ self._recv_buffer_linesep = c_byted
+ else:
+ self._recv_buffer_linesep += c_byted
+ if self._recv_buffer_linesep == _IRCSPEC_LINE_SEPARATOR:
+ self._recv_buffer_linesep = b''
+ yield self._make_recv_event(
+ IrcMessage.from_raw(
+ self._recv_bytes_total.decode('utf-8')))
+ self._recv_bytes_total = b''
def send(self, msg: IrcMessage) -> None:
self._make_sendable(msg)
- def _read_lines(self) -> Iterator[Optional[Event]]:
- try:
- while True:
- try:
- msg = self._q_server_msgs.get(timeout=0.1)
- except QueueEmpty:
- yield None
- continue
- if msg == ERR_STR_TIMEOUT:
- yield self._on_handled_loop_exception(
- IrcConnException(msg, abort=False))
- continue
- if msg == 'FAKE_IRC_CONN_ABORT_EXCEPTION':
- raise IrcConnException(msg, retry=True)
- yield self._make_recv_event(IrcMessage.from_raw(msg))
- except IrcConnException as e:
- yield self._on_handled_loop_exception(e)
+ def _process_recv(self) -> Iterator[Optional[Event]]:
+ while True:
+ try:
+ msg = self._q_server_msgs.get(timeout=0.1)
+ except QueueEmpty:
+ yield None
+ continue
+ if msg == ERR_STR_TIMEOUT:
+ yield self._on_handled_loop_exception(
+ IrcConnException(msg, abort=False))
+ continue
+ if msg == 'FAKE_IRC_CONN_ABORT_EXCEPTION':
+ raise IrcConnException(msg, retry=True)
+ yield self._make_recv_event(IrcMessage.from_raw(msg))
class _TestClientKnowingTui(ClientKnowingTui):