From: Christian Heller Date: Tue, 10 Jun 2025 06:29:29 +0000 (+0200) Subject: Move more server interaction logic into former SocketRecvLoop, now ConnectionLoop. X-Git-Url: https://plomlompom.com/repos/%22https:/validator.w3.org/%7B%7Bdb.prefix%7D%7D/%7B%7Btodo.comment%7D%7D?a=commitdiff_plain;p=ircplom Move more server interaction logic into former SocketRecvLoop, now ConnectionLoop. --- diff --git a/ircplom.py b/ircplom.py index f85b62b..930b887 100755 --- a/ircplom.py +++ b/ircplom.py @@ -61,6 +61,7 @@ class EventType(Enum): CONN_ALERT = auto() CONNECTED = auto() CONN_WINDOW = auto() + DISCONNECTED = auto() EXCEPTION = auto() INIT_CONNECT = auto() INIT_RECONNECT = auto() @@ -227,7 +228,7 @@ class IrcConnection: self._login = login self._socket: Optional[socket] = None self._assumed_open = False - self._recv_loop: Optional[SocketRecvLoop] = None + self._loop: Optional[ConnectionLoop] = None self._broadcast(EventType.CONN_WINDOW, self._idx) self._start_connecting() @@ -245,18 +246,18 @@ class IrcConnection: return self._socket.settimeout(TIMEOUT_LOOP) self._assumed_open = True - self._broadcast(EventType.CONNECTED) - self._recv_loop = SocketRecvLoop(self._idx, self._q_to_main, - self._read_lines()) + self._loop = ConnectionLoop(self._idx, self._q_to_main, + self._read_lines()) + self._broadcast(EventType.CONNECTED, self._login) Thread(target=connect, daemon=True, args=(self,)).start() def close(self): - 'Close both SocketRecvLoop and socket.' + 'Close both ConnectionLoop and socket.' self._assumed_open = False - if self._recv_loop: - self._recv_loop.stop() - self._recv_loop = None + if self._loop: + self._loop.stop() + self._loop = None if self._socket: self._socket.close() self._socket = None @@ -306,13 +307,6 @@ class IrcConnection: def handle(self, event: Event) -> None: 'Process connection-directed Event into further steps.' - if event.type_ == EventType.CONNECTED: - self._broadcast(EventType.SEND, - IrcMessage('USER', [self._login[0], '0', '*', - self._login[2]])) - self._broadcast(EventType.SEND, - IrcMessage('NICK', [self._login[1]])) - return if event.type_ == EventType.INIT_RECONNECT: if self._assumed_open: self._broadcast(EventType.CONN_ALERT, @@ -320,17 +314,14 @@ class IrcConnection: 'so nothing to do.') else: self._start_connecting() - return - msg: IrcMessage = event.payload[1] - if event.type_ == EventType.SEND: + elif event.type_ == EventType.CONNECTED: + assert self._loop is not None + self._loop.put(event) + elif event.type_ == EventType.DISCONNECTED: + self.close() + elif event.type_ == EventType.SEND: + msg: IrcMessage = event.payload[1] self._write_line(msg.raw) - elif event.type_ == EventType.RECV: - if msg.verb == 'PING': - self._broadcast(EventType.SEND, - IrcMessage('PONG', [msg.parameters[0]])) - elif msg.verb == 'ERROR'\ - and msg.parameters[0].startswith('Closing link:'): - self._assumed_open = False class IrcMessage: @@ -339,12 +330,12 @@ class IrcMessage: def __init__(self, verb: str, - parameters: Optional[list[str]] = None, + parameters: Optional[tuple[str, ...]] = None, source: str = '', tags: Optional[dict[str, str]] = None ) -> None: self.verb: str = verb - self.parameters: list[str] = parameters or [] + self.parameters: tuple[str, ...] = parameters or tuple() self.source: str = source self.tags: dict[str, str] = tags or {} @@ -372,7 +363,7 @@ class IrcMessage: tags[key] = val return tags - def _split_params(str_params: str) -> list[str]: + def _split_params(str_params: str) -> tuple[str, ...]: params = [] params_stage = 0 # 0: gap, 1: non-trailing, 2: trailing for char in str_params: @@ -386,7 +377,7 @@ class IrcMessage: params_stage += 1 continue params[-1] += char - return params + return tuple(p for p in params) stages = [_Stage('tags', '@', _parse_tags), _Stage('source', ':'), @@ -744,7 +735,7 @@ class ConnectionWindow(Window): def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None: 'Send QUIT command to server.' self._broadcast(EventType.SEND, - (self._conn_idx, IrcMessage('QUIT', [quit_msg]))) + (self._conn_idx, IrcMessage('QUIT', (quit_msg, )))) def cmd__reconnect(self) -> None: 'Attempt reconnection.' @@ -898,16 +889,34 @@ class TuiLoop(Loop): return None -class SocketRecvLoop(Loop): +class ConnectionLoop(Loop): 'Loop receiving and translating socket messages towards main loop.' def __init__(self, connection_idx: int, *args, **kwargs) -> None: self._conn_idx = connection_idx super().__init__(*args, **kwargs) + def _send(self, verb: str, parameters: tuple[str, ...]) -> None: + self.broadcast(EventType.SEND, (self._conn_idx, + IrcMessage(verb, parameters))) + + def process_main(self, event: Event) -> bool: + if not super().process_main(event): + return False + if event.type_ == EventType.CONNECTED: + login = event.payload[1] + self._send('USER', (login[0], '0', '*', login[2])) + self._send('NICK', (login[1],)) + return True + def process_bonus(self, yielded: str) -> None: - self.broadcast(EventType.RECV, (self._conn_idx, - IrcMessage.from_raw(yielded))) + msg = IrcMessage.from_raw(yielded) + self.broadcast(EventType.RECV, (self._conn_idx, msg)) + if msg.verb == 'PING': + self._send('PONG', (msg.parameters[0],)) + if msg.verb == 'ERROR'\ + and msg.parameters[0].startswith('Closing link:'): + self.broadcast(EventType.DISCONNECTED, (self._conn_idx,)) class KeyboardLoop(Loop): @@ -953,8 +962,12 @@ def run() -> None: connections += [IrcConnection(q_to_main, len(connections), *event.payload)] elif event.type_ in { - EventType.CONNECTED, EventType.INIT_RECONNECT, - EventType.RECV, EventType.SEND}: + EventType.CONNECTED, + EventType.DISCONNECTED, + EventType.INIT_RECONNECT, + EventType.RECV, + EventType.SEND, + }: connections[event.payload[0]].handle(event) finally: for conn in connections: