home · contact · privacy
Overhaul chat= message targeting into explicitly named streams. master
authorChristian Heller <c.heller@plomlompom.de>
Wed, 6 Aug 2025 17:40:54 +0000 (19:40 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 6 Aug 2025 17:40:54 +0000 (19:40 +0200)
ircplom/client.py
ircplom/client_tui.py

index e55f148be9ae39bd92b044a00bc18e3517798bcb..71cf2e5ad1f37f1f5ab8a256c2f208122c050cfe 100644 (file)
@@ -12,7 +12,10 @@ from ircplom.irc_conn import (BaseIrcConnection, IrcConnAbortException,
                               IrcMessage, PORT_SSL)
 
 ClientsDb = dict[str, 'Client']
-CHAT_GLOB = '*'
+STREAM_GLOB = '*'
+STREAM_PREFIX_META = ':'
+STREAM_SERVER = f'{STREAM_PREFIX_META}server'
+STREAM_RAW = f'{STREAM_PREFIX_META}raw'
 
 _LOG_PREFIX_PRIVMSG = ''
 _LOG_PREFIX_SEND_RAW = '=>|'
@@ -210,7 +213,8 @@ class Client(ABC, ClientQueueMixin):
         'Steps to perform right after connection.'
         assert self.conn is not None
         self.log.add('connected to server (SSL: '
-                     f'{"yes" if self.conn.ssl else "no"})', chat=CHAT_GLOB)
+                     f'{"yes" if self.conn.ssl else "no"})',
+                     stream=STREAM_GLOB)
         self._caps.challenge('LS', '302')
         self.send(IrcMessage(verb='USER',
                              params=(getuser(), '0', '*',
@@ -218,22 +222,22 @@ class Client(ABC, ClientQueueMixin):
         self.send(IrcMessage(verb='NICK', params=(self.conn_setup.nickname,)))
 
     @abstractmethod
-    def _log(self, msg: str, chat: str = '') -> None:
-        '''Write msg into log of chat, whatever shape that may have.
-
-        Messages to chat=CHAT_GLOB are meant to appear in all widgets mapped to
-        the client, those to chat="" only in the initial connection window.
-        '''
-
-    def send(self, msg: IrcMessage, chat: str = '', to_log: str = '') -> None:
+    def _log(self, msg: str, stream: str = STREAM_SERVER) -> None:
+        'Write msg into log of stream, whatever shape that may have.'
+
+    def send(self,
+             msg: IrcMessage,
+             stream: str = STREAM_SERVER,
+             to_log: str = ''
+             ) -> None:
         'Send line-separator-delimited message over socket.'
         if not self.conn:
             self.log.alert('cannot send, connection seems closed')
             return
         self.conn.send(msg)
         if to_log:
-            self.log.add(to_log, prefix='', chat=chat)
-        self.log.add(msg.raw, prefix=_LOG_PREFIX_SEND_RAW, chat=':raw')
+            self.log.add(to_log, prefix='', stream=stream)
+        self.log.add(msg.raw, prefix=_LOG_PREFIX_SEND_RAW, stream=STREAM_RAW)
 
     def update_login(self, nick_confirmed: bool, nickname: str = '') -> None:
         '''Manage conn_setup.nickname, .nick_confirmed.
@@ -246,7 +250,8 @@ class Client(ABC, ClientQueueMixin):
             verb = ('set' if first_run
                     else f'changed from "{self.conn_setup.nickname}"')
             self.conn_setup.nickname = nickname
-            self.log.add(f'{prefix} {verb} to "{nickname}"', chat=CHAT_GLOB)
+            self.log.add(f'{prefix} {verb} to "{nickname}"',
+                         stream=STREAM_GLOB)
         if first_run or nick_confirmed != self.nick_confirmed:
             self.nick_confirmed = nick_confirmed
             if not first_run:
@@ -255,7 +260,7 @@ class Client(ABC, ClientQueueMixin):
 
     def close(self) -> None:
         'Close both recv Loop and socket.'
-        self.log.add(msg='disconnecting from server', chat=CHAT_GLOB)
+        self.log.add(msg='disconnecting from server', stream=STREAM_GLOB)
         self._caps.clear()
         if self.conn:
             self.conn.close()
@@ -264,7 +269,7 @@ class Client(ABC, ClientQueueMixin):
 
     def handle_msg(self, msg: IrcMessage) -> None:
         'Process incoming msg towards appropriate client steps.'
-        self.log.add(msg.raw, prefix=_LOG_PREFIX_RECV_RAW, chat=':raw')
+        self.log.add(msg.raw, prefix=_LOG_PREFIX_RECV_RAW, stream=STREAM_RAW)
         match msg.verb:
             case 'PING':
                 self.send(IrcMessage(verb='PONG', params=(msg.params[0],)))
@@ -274,7 +279,8 @@ class Client(ABC, ClientQueueMixin):
                 self.update_login(nickname=msg.params[0], nick_confirmed=True)
             case 'PRIVMSG':
                 nickname = msg.source.split('!')[0]
-                self.log.add(f'<[{nickname}] {msg.params[-1]}', chat=nickname,
+                self.log.add(f'<[{nickname}] {msg.params[-1]}',
+                             stream=nickname,
                              prefix=_LOG_PREFIX_PRIVMSG)
             case 'CAP':
                 for to_log in self._caps.process_msg(msg.params[1:]):
index 13a0dc64f48a6dfcc77a49fbd8970dceae506efa..14557ea0dda02ed0645412b23b44d951c10af8e1 100644 (file)
@@ -7,8 +7,9 @@ from typing import Any, Optional
 from ircplom.tui_base import (BaseTui, PromptWidget, TuiEvent, Window,
                               CMD_SHORTCUTS)
 from ircplom.irc_conn import IrcMessage
-from ircplom.client import (CHAT_GLOB, IrcConnSetup, Client, ClientIdMixin,
-                            ClientQueueMixin, NewClientEvent)
+from ircplom.client import (
+        STREAM_GLOB, STREAM_PREFIX_META, STREAM_RAW, STREAM_SERVER,
+        IrcConnSetup, Client, ClientIdMixin, ClientQueueMixin, NewClientEvent)
 
 CMD_SHORTCUTS['disconnect'] = 'window.disconnect'
 CMD_SHORTCUTS['nick'] = 'window.nick'
@@ -20,13 +21,13 @@ _PROMPT_UPDATE_TRIGGER_KEYS = {'nick_confirmed', 'nickname'}
 
 class _ClientWindow(Window, ClientQueueMixin):
 
-    def __init__(self, chat: str = '', **kwargs) -> None:
-        self.chat = chat
+    def __init__(self, stream: str, **kwargs) -> None:
+        self.stream = stream
         super().__init__(**kwargs)
 
     @property
     def _status_title(self) -> str:
-        return f'{super()._status_title}|{self.client_id}|{self.chat}'
+        return f'{super()._status_title}|{self.client_id}|{self.stream}'
 
     def _send_msg(self, verb: str, params: tuple[str, ...], **kwargs) -> None:
         self._cputs('send', msg=IrcMessage(verb=verb, params=params), **kwargs)
@@ -46,7 +47,7 @@ class _ClientWindow(Window, ClientQueueMixin):
     def cmd__privmsg(self, target: str, msg: str) -> None:
         'Send chat message msg to target.'
         self._send_msg('PRIVMSG', (target, msg),
-                       chat=target, to_log=f'>[MYSELF] {msg}')
+                       stream=target, to_log=f'>[MYSELF] {msg}')
 
 
 class _PrivmsgPromptWidget(PromptWidget):
@@ -72,8 +73,8 @@ class _PrivmsgWindow(_ClientWindow):
     prompt: _PrivmsgPromptWidget
 
     def cmd__chat(self, msg: str) -> None:
-        'PRIVMSG to .chat.'
-        self.cmd__privmsg(self.chat, msg)
+        'PRIVMSG to target identified by .stream.'
+        self.cmd__privmsg(self.stream, msg)
 
 
 class ClientTui(BaseTui):
@@ -83,13 +84,12 @@ class ClientTui(BaseTui):
         super().__init__(**kwargs)
         self.clients_data: dict[str, dict[str, Any]] = {}
 
-    def _new_client_window(self, client_id: str, chat: str = ''
-                           ) -> _ClientWindow:
+    def _new_client_window(self, client_id: str, stream: str) -> _ClientWindow:
         new_idx = len(self._windows)
-        win_class = (_PrivmsgWindow if (chat and chat[0].isalpha())
+        win_class = (_PrivmsgWindow if stream[0:1] != STREAM_PREFIX_META
                      else _ClientWindow)
         win = win_class(idx=new_idx, term=self._term, _q_out=self._q_out,
-                        client_id=client_id, chat=chat)
+                        client_id=client_id, stream=stream)
         if isinstance(win, _PrivmsgWindow):
             win.prompt.update_prefix(**{k: self.clients_data[client_id][k]
                                         for k in _PROMPT_UPDATE_TRIGGER_KEYS})
@@ -102,19 +102,20 @@ class ClientTui(BaseTui):
         return [win for win in self._windows if isinstance(win, _ClientWindow)]
 
     def client_wins(self, client_id: str = '') -> list[_ClientWindow]:
-        'All _ClientWindows matching client_id; if none, create one.'
+        'All _ClientWindows matching client_id; if none, create basics.'
         wins = [w for w in self._all_client_wins if client_id == w.client_id]
         if not wins:
-            wins = [self._new_client_window(client_id=client_id)]
+            for stream in (STREAM_SERVER, STREAM_RAW):
+                wins += [self._new_client_window(client_id, stream)]
         return wins
 
-    def client_win(self, client_id: str, chat: str = '') -> _ClientWindow:
-        'That _ClientWindow matching client_id and chat; if none, create one.'
+    def client_win(self, client_id: str, stream: str) -> _ClientWindow:
+        'That _ClientWindow matching client_id and stream; if none, create.'
         client_wins = self.client_wins(client_id)
-        candidates = [win for win in client_wins if win.chat == chat]
+        candidates = [win for win in client_wins if win.stream == stream]
         if candidates:
             return candidates[0]
-        win = self._new_client_window(client_id=client_id, chat=chat)
+        win = self._new_client_window(client_id=client_id, stream=stream)
         return win
 
     def cmd__connect(self,
@@ -149,15 +150,16 @@ class ClientTui(BaseTui):
 
 @dataclass
 class _ClientLogEvent(TuiEvent, ClientIdMixin):
-    chat: str
+    stream: str
     msg: str
 
     def affect(self, target: ClientTui) -> None:
-        if self.chat == CHAT_GLOB:
+        if self.stream == STREAM_GLOB:
             for win in target.client_wins(self.client_id):
                 win.log.append(self.msg)
         else:
-            target.client_win(self.client_id, self.chat).log.append(self.msg)
+            target.client_win(self.client_id, self.stream
+                              ).log.append(self.msg)
         target.redraw_affected()
 
 
@@ -182,8 +184,8 @@ class _ClientDataEvent(TuiEvent, ClientIdMixin):
 
 class _ClientKnowingTui(Client):
 
-    def _log(self, msg: str, chat: str = '') -> None:
-        self._cput(_ClientLogEvent, chat=chat, msg=msg)
+    def _log(self, msg: str, stream: str = STREAM_SERVER) -> None:
+        self._cput(_ClientLogEvent, stream=stream, msg=msg)
 
     def update_login(self, nick_confirmed: bool, nickname: str = '') -> None:
         super().update_login(nick_confirmed, nickname)