home · contact · privacy
Allow reconnecting.
authorChristian Heller <c.heller@plomlompom.de>
Sat, 7 Jun 2025 18:08:06 +0000 (20:08 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 7 Jun 2025 18:08:06 +0000 (20:08 +0200)
ircplom.py

index 186bd75db7c914cad1b40a49fb6e324788e39bc4..5b183242cda12bab7dc1460bd01cf570f4d4673f 100755 (executable)
@@ -147,7 +147,6 @@ class Terminal:
 
 class IrcConnection:
     'Abstracts socket connection, loop over it, and handling messages from it.'
-    _socket: socket
 
     def __init__(self,
                  q_to_main: EventQueue,
@@ -157,17 +156,23 @@ class IrcConnection:
                  ) -> None:
         self._idx = idx
         self._q_to_main = q_to_main
+        self._hostname = hostname
         self._login = login
+        self._socket: Optional[socket] = None
         self._assumed_open = False
         self._recv_loop: Optional[SocketRecvLoop] = None
-        self._socket = socket()
-        self._socket.settimeout(TIMEOUT_CONNECT)
         self._broadcast('CONNECTION_WINDOW', self._idx)
+        self._start_connecting()
+
+    def _start_connecting(self) -> None:
 
         def connect(self):
-            self._broadcast('CONN_ALERT', f'Connecting to {hostname} …')
+            self._socket = socket()
+            self._broadcast('CONN_ALERT',
+                            f'Connecting to {self._hostname} …')
+            self._socket.settimeout(TIMEOUT_CONNECT)
             try:
-                self._socket.connect((hostname, PORT))
+                self._socket.connect((self._hostname, PORT))
             except (TimeoutError, socket_gaierror) as e:
                 self._broadcast('CONN_ALERT', str(e))
                 return
@@ -184,7 +189,10 @@ class IrcConnection:
         self._assumed_open = False
         if self._recv_loop:
             self._recv_loop.stop()
-        self._socket.close()
+        self._recv_loop = None
+        if self._socket:
+            self._socket.close()
+        self._socket = None
 
     def _broadcast(self, type_: str, payload: Any = None) -> None:
         'Send event to main loop via queue, with connection index as 1st arg.'
@@ -192,6 +200,7 @@ class IrcConnection:
 
     def _read_lines(self) -> Iterator[Optional[str]]:
         'Receive line-separator-delimited messages from socket.'
+        assert self._socket is not None
         bytes_total = b''
         buffer_linesep = b''
         while True:
@@ -222,7 +231,7 @@ class IrcConnection:
 
     def _write_line(self, line: str) -> None:
         'Send line-separator-delimited message over socket.'
-        if not self._assumed_open:
+        if not (self._socket and self._assumed_open):
             self._broadcast('CONN_ALERT',
                             'cannot send, assuming connection closed')
             return
@@ -235,6 +244,13 @@ class IrcConnection:
                                                         '*', self._login[2]]))
             self._broadcast('SEND', IrcMessage('NICK', [self._login[1]]))
             return
+        if event.type_ == 'INIT_RECONNECTION':
+            if self._assumed_open:
+                self._broadcast('CONN_ALERT', 'Reconnect called, but still '
+                                'seem connected, so nothing to do.')
+            else:
+                self._start_connecting()
+            return
         msg: IrcMessage = event.payload[1]
         if event.type_ == 'SEND':
             self._write_line(msg.raw)
@@ -689,6 +705,14 @@ class TuiLoop(Loop):
         self._window_idx = idx
         self.window.draw()
 
+    def cmd__reconnect(self) -> Optional[str]:
+        'Send INIT_RECONNECTION to server if in connection window.'
+        if self.window not in self._conn_windows:
+            return 'can only reconnect from inside connection window.'
+        conn_idx = self._conn_windows.index(self.window)
+        self.broadcast('INIT_RECONNECTION', (conn_idx,))
+        return None
+
     def cmd__connect(self,
                      hostname: str,
                      username: str,
@@ -804,7 +828,8 @@ def run() -> None:
                 if event.type_ == 'INIT_CONNECTION':
                     connections += [IrcConnection(q_to_main, len(connections),
                                                   *event.payload)]
-                elif event.type_ in {'CONNECTED', 'RECV', 'SEND'}:
+                elif event.type_ in {
+                        'CONNECTED', 'INIT_RECONNECTION', 'RECV', 'SEND'}:
                     connections[event.payload[0]].handle(event)
     finally:
         for conn in connections: