home · contact · privacy
Implement on-timeout reconnect-wait only hinted at in previous commit.
authorChristian Heller <c.heller@plomlompom.de>
Thu, 2 Oct 2025 18:03:51 +0000 (20:03 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 2 Oct 2025 18:03:51 +0000 (20:03 +0200)
src/ircplom/client.py
src/tests/pingpong.txt

index b27f72fa77082e739c1e91114df800c51ebe1664..bf8c28b763c753e415e9f97c683344f3d8c5dc0f 100644 (file)
@@ -5,8 +5,10 @@ from base64 import b64encode
 from dataclasses import dataclass, InitVar
 from getpass import getuser
 from threading import Thread
+from time import sleep
 from typing import (Any, Callable, Collection, Generic, Iterable, Iterator,
                     Optional, Self, Set, TypeVar)
+from uuid import UUID, uuid4
 # ourselves
 from ircplom.events import (
     AffectiveEvent, CrashingException, ExceptionEvent, QueueMixin)
@@ -818,7 +820,8 @@ class Client(ABC, ClientQueueMixin):
     conn: Optional[IrcConnection] = None
     _cls_conn: type[IrcConnection] = IrcConnection
     _expected_pong: str
-    _retry_in_s: int
+    _retry_connect_in_s: int
+    _retry_connect_id: Optional[UUID] = None
 
     def __init__(self, conn_setup: IrcConnSetup, channels: set[str], **kwargs
                  ) -> None:
@@ -838,6 +841,7 @@ class Client(ABC, ClientQueueMixin):
 
     def connect(self) -> None:
         'Attempt to open connection, on success perform session init steps.'
+        self._retry_connect_id = None
         self.db.connection_state = 'connecting'
 
         def connect(self) -> None:
@@ -851,7 +855,7 @@ class Client(ABC, ClientQueueMixin):
                 self._put(ExceptionEvent(CrashingException(e)))
             else:
                 self._expected_pong = ''
-                self._retry_in_s = -1
+                self._retry_connect_in_s = -1
                 self.db.connection_state = 'connected'
                 self.caps.start_negotation()
                 self.send('USER', self.db.user_wanted,
@@ -870,9 +874,21 @@ class Client(ABC, ClientQueueMixin):
         if self.conn:
             self.conn.close()
         self.conn = None
-        if self._retry_in_s > 0:
-            self._retry_in_s *= 2
-            self.connect()
+        if self._retry_connect_in_s > 0:
+            def delayed_connect(self, wait_s: int, retry_connect_id: UUID
+                                ) -> None:
+                sleep(wait_s)
+                if self._retry_connect_id == retry_connect_id:
+                    self._client_trigger('connect')
+
+            self._retry_connect_id = uuid4()
+            self._alert(
+                f'will retry connecting in {self._retry_connect_in_s} seconds')
+            Thread(target=delayed_connect, daemon=True,
+                   args=(self, self._retry_connect_in_s,
+                         self._retry_connect_id)
+                   ).start()
+            self._retry_connect_in_s *= 2
 
     def on_handled_loop_exception(self, e: IrcConnException) -> None:
         'On …AbortException, call .close(), on …Timeout… first (!) try PING.'
@@ -881,7 +897,7 @@ class Client(ABC, ClientQueueMixin):
             self.close()
         elif isinstance(e, IrcConnTimeoutException):
             if self._expected_pong:
-                self._retry_in_s = 1
+                self._retry_connect_in_s = 1
                 self.on_handled_loop_exception(
                         IrcConnAbortException('no timely PONG from server'))
             else:
index 1811cd45f9ca0b7ee929f40786c9e31e7e892616..a468f57d8cd261f72a96895658593b66e5e4b3b1 100644 (file)
@@ -52,6 +52,7 @@ repeat isupport-clear-in isupport-clear-out
 
 # on (automatic!) re-connect, ensure timer cleared, so won't trigger already on 1st timeout
 | conn2-in
+1 .!$ will retry connecting in 1 seconds
 repeat conn0-in conn0-out
 2 .$ CONNECTED
 repeat conn1-in conn1-out