From: Christian Heller Date: Sun, 10 Aug 2025 09:46:19 +0000 (+0200) Subject: Handle more gracefully expected exceptions in BaseIrcConnection._read_lines. X-Git-Url: https://plomlompom.com/repos/booking/%7B%7B%20web_path%20%7D%7D/error?a=commitdiff_plain;h=9739f01d870c9116aaf2fd7c99222fd8abff4bad;p=ircplom Handle more gracefully expected exceptions in BaseIrcConnection._read_lines. --- diff --git a/ircplom/client.py b/ircplom/client.py index 1c23695..dff7db4 100644 --- a/ircplom/client.py +++ b/ircplom/client.py @@ -48,6 +48,11 @@ class _IrcConnection(BaseIrcConnection, ClientIdMixin): return ClientEvent.affector('handle_msg', client_id=self.client_id ).kw(msg=msg) + def _on_handled_loop_exception(self, e: IrcConnAbortException + ) -> ClientEvent: + return ClientEvent.affector('on_handled_loop_exception', + client_id=self.client_id).kw(e=e) + @dataclass class ClientQueueMixin(QueueMixin, ClientIdMixin): @@ -265,6 +270,11 @@ class Client(ABC, ClientQueueMixin): self.conn = None self.update_login(nick_confirmed=False) + def on_handled_loop_exception(self, e: IrcConnAbortException) -> None: + 'Gracefully handle broken connection.' + self._log.alert(f'connection broken: {e}') + self.close() + def handle_msg(self, msg: IrcMessage) -> None: 'Process incoming msg towards appropriate client steps.' self._log.add(msg.raw, prefix=_LOG_PREFIX_RECV_RAW, stream=STREAM_RAW) diff --git a/ircplom/irc_conn.py b/ircplom/irc_conn.py index 13af291..0dcd113 100644 --- a/ircplom/irc_conn.py +++ b/ircplom/irc_conn.py @@ -156,35 +156,46 @@ class BaseIrcConnection(QueueMixin, ABC): def _make_recv_event(self, msg: IrcMessage) -> Event: pass + @abstractmethod + def _on_handled_loop_exception(self, _: IrcConnAbortException) -> Event: + pass + def _read_lines(self) -> Iterator[Optional[Event]]: assert self._socket is not None bytes_total = b'' buffer_linesep = b'' - while True: - try: - bytes_new = self._socket.recv(_CONN_RECV_BUFSIZE) - except TimeoutError: - yield None - continue - except ConnectionResetError as e: - raise e - except OSError as e: - if e.errno == 9: + i = 0 + try: + while True: + i += 1 + try: + bytes_new = self._socket.recv(_CONN_RECV_BUFSIZE) + if i >= 10: + raise IrcConnAbortException("DEBUG") + except TimeoutError: + yield None + continue + except ConnectionResetError as e: + raise IrcConnAbortException(e) from e + except OSError as e: + if e.errno == 9: + raise IrcConnAbortException(e) from e + raise e + if not bytes_new: break - raise e - if not bytes_new: - break - 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( + 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'' + bytes_total = b'' + except IrcConnAbortException as e: + yield self._on_handled_loop_exception(e)