home · contact · privacy
Communicate user exits via User.exit_msg rather than client-side logging.
authorChristian Heller <c.heller@plomlompom.de>
Sat, 6 Sep 2025 04:42:56 +0000 (06:42 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 6 Sep 2025 04:42:56 +0000 (06:42 +0200)
ircplom/client.py
ircplom/client_tui.py

index c61ece46e5aebf19382294dc6decebc0191ec3a4..f8e4c1db1897b54fe09bdd38c522b8953cecc74a 100644 (file)
@@ -263,7 +263,7 @@ class LogScope(Enum):
     SERVER = auto()
     RAW = auto()
     CHAT = auto()
-    NICKNAME = auto()
+    USER = auto()
     SAME = auto()
 
 
@@ -407,6 +407,7 @@ class _NickUserHost(NickUserHost):
 
 class _User(_NickUserHost):
     modes: str = '?'
+    exit_msg: str = ''
 
     @property
     def id_(self) -> str:
@@ -784,21 +785,18 @@ class Client(ABC, ClientQueueMixin):
                                   else ret['channel'])}
             self._log(ret['message'], out=False, **kw)
         elif ret['_verb'] == 'PART':
+            ret['parter'].exit_msg = 'P' + ret.get('message', '')
+            ret['parter'].exit_msg = ''
             self.db.channels[ret['channel']].remove_user(ret['parter'])
-            if 'message' in ret:
-                self._log(f'{ret["parter"]} parts: {ret["message"]}',
-                          LogScope.CHAT, target=ret['channel'])
             if ret['parter'] is self.db.users['me']:
                 del self.db.channels[ret['channel']]
                 self.db.purge_users()
         elif ret['_verb'] == 'PING':
             self.send(IrcMessage(verb='PONG', params=(ret['reply'],)))
         elif ret['_verb'] == 'QUIT':
-            for ch_name, ch in self.db.chans_of_user(ret['quitter'].id_
-                                                     ).items():
-                ch.remove_user(ret['quitter'])
-                self._log(f'{ret["quitter"]} quits: {ret["message"]}',
-                          LogScope.CHAT, target=ch_name)
+            ret['quitter'].exit_msg = 'Q' + ret['message']
+            for channel in self.db.chans_of_user(ret['quitter'].id_).values():
+                channel.remove_user(ret['quitter'])
 
 
 ClientsDb = dict[str, Client]
index dea90f53b3127b5f259a984d62e749ef4e0980bc..54005e2548bc00ef051d2fe21dd119e9970293ca 100644 (file)
@@ -213,8 +213,6 @@ class _UpdatingChannel(_UpdatingNode):
             else:
                 msg['nuhs:joining'] = tuple(id_ for id_ in update.value
                                             if id_ not in self.user_ids)
-                msg['nuhs:parting'] = tuple(id_ for id_ in self.user_ids
-                                            if id_ not in update.value)
         if super().set_and_check_for_change(update):
             if update.path == ('topic',):
                 msg = f'raw:{self.topic.who} set topic to: {self.topic.what}'
@@ -223,9 +221,24 @@ class _UpdatingChannel(_UpdatingNode):
 
 
 class _UpdatingUser(_UpdatingNode, NickUserHost):
-    log_scopes = {('nick',): LogScope.NICKNAME}
+    log_scopes = {('nick',): LogScope.USER,
+                  ('exit_msg',): LogScope.USER}
     prev_nick = '?'
     modes = '?'
+    exit_msg = ''
+
+    def set_and_check_for_change(self, update: _Update
+                                 ) -> Optional[tuple[LogScope, Any]]:
+        if update.path == ('exit_msg',):
+            assert isinstance(update.value, str)
+            if super().set_and_check_for_change(update) and update.value:
+                return self._scope(update.path), {
+                    'user': str(self),
+                    'msg': (f': {update.value[1:]}' if len(update.value) > 1
+                            else ''),
+                    'verb': 'quits' if update.value[0] == 'Q' else 'parts'}
+            return None
+        return super().set_and_check_for_change(update)
 
     @property
     def prev(self) -> str:
@@ -330,13 +343,16 @@ class _ClientWindowsManager:
         scope, value = result
         log_path = ':'.join(update.path)
         log_kwargs: dict[str, Any] = {'scope': scope}
-        if scope in {LogScope.CHAT, LogScope.NICKNAME}:
+        if scope in {LogScope.CHAT, LogScope.USER}:
             log_kwargs |= {'target': update.path[1]}
         if value is None:
             self.log(f'{log_path} cleared', **log_kwargs)
-        elif scope is LogScope.NICKNAME:
-            self.log(f'{self.db.users[update.path[1]].prev} renames {value}',
-                     **log_kwargs)
+        elif scope is LogScope.USER:
+            if update.path[-1] == 'nick':
+                msg = f'{self.db.users[update.path[1]].prev} renames {value}'
+            elif update.path[-1] == 'exit_msg':
+                msg = f'{value["user"]} {value["verb"]}{value["msg"]}'
+            self.log(msg, **log_kwargs)
         elif isinstance(value, dict):
             for verb, item in [(k, v) for k, v in value.items() if v]:
                 toks = verb.split(':', maxsplit=1)
@@ -383,7 +399,7 @@ class ClientTui(BaseTui):
                             if kwargs['target'] != m.db.users['me'].nick
                             else kwargs['sender'])
                 return [m.window(LogScope.CHAT, chatname=chatname)]
-            if scope == LogScope.NICKNAME:
+            if scope == LogScope.USER:
                 return m.windows_for_userid(kwargs['target'])
             return [m.window(scope)]
         return super()._log_target_wins(**kwargs)