From: Christian Heller Date: Sat, 22 Nov 2025 06:26:42 +0000 (+0100) Subject: Move more message handling into MSG_EXPECTATIONS/out of Client.handle_msg. X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/balance?a=commitdiff_plain;h=c174101c1effd9cead8a1289f6bfe85ec8719235;p=ircplom Move more message handling into MSG_EXPECTATIONS/out of Client.handle_msg. --- diff --git a/src/ircplom/client.py b/src/ircplom/client.py index 873b1f1..a273230 100644 --- a/src/ircplom/client.py +++ b/src/ircplom/client.py @@ -216,11 +216,13 @@ class _Channel(Channel): if prefix: self._add_membership_prefix(user_id, prefix) - def add_user(self, user: '_User') -> None: - 'To .user_ids add user.nickname, keep .user_ids declared complete.' - user_id = self._userid_for_nickuserhost(user, create_if_none=True, + def join_user(self, user: '_User') -> None: + 'Register non-"me" user joining channel.' + user_id = self._userid_for_nickuserhost(nickuserhost=user, + create_if_none=True, updating=True) - self.user_ids.completable_add(user_id, on_complete=True) + if user_id != 'me': # own JOIN would have added name via RPL_NAMREPLY + self.user_ids.completable_add(user_id, on_complete=True) def remove_user(self, user: '_User', msg: str) -> None: 'From .user_ids remove .nickname, keep .user_ids declared complete.' @@ -503,6 +505,15 @@ class _ClientDb(Clearable, UpdatingAttrsMixin, SharedClientDbFields): attr._preset_init_kwargs = {} return attr + def set_isupport_from_rpl(self, rpl: tuple[str, ...]) -> None: + 'Parse rpl for additions/deletions to .isupport dict.' + for item in rpl: + if item[0] == '-': + del self.isupport[item[1:]] + else: + key, data = _tuple_key_val_from_eq_str(item) + self.isupport[key] = data + def messaging(self, src: str | NickUserHost) -> ChatMessage: 'Start input chain for chat message data.' return _ChatMessage(sender=src, db=self) @@ -795,6 +806,35 @@ class Client(ABC, ClientQueueMixin): self.conn.send(msg) return msg + def autojoin(self) -> None: + 'Join all channels marked for auto-join, clear same auto-join list.' + for name in self._autojoins: + self.send('JOIN', name) + self._autojoins.clear() + + def send_authentication(self) -> None: + 'Send AUTHENTICATE with b64-encoded authentication data.' + auth = b64encode((self.db.nick_wanted + '\0' + + self.db.nick_wanted + '\0' + + self.db.password + ).encode('utf-8') + ).decode('utf-8') + self.send('AUTHENTICATE', auth) + + def increment_for_nicknameinuse(self, rejected_nick: str) -> None: + 'Note ERR_NICKNAMEINUSE and try incremented variant of rejected_nick.' + self._alert('nickname already in use, trying increment') + self.send('NICK', _NickUserHost(nick=rejected_nick).incremented) + + def check_pong(self, reply: str) -> None: + 'Check reply matching our PING, zero our PING expectations.' + assert self._expected_pong == reply + self._expected_pong = '' + + def pong(self, reply: str) -> None: + 'Reply PING with its expected reply.' + self.send('PONG', reply) + def handle_msg(self, msg: IrcMessage) -> None: 'Log msg.raw, then process incoming msg into appropriate client steps.' ret = {} @@ -837,32 +877,12 @@ class Client(ABC, ClientQueueMixin): node(ret[tok_name]) else: node() - if ret['_verb'] == '001': # RPL_WELCOME - for name in self._autojoins: - self.send('JOIN', name) - self._autojoins.clear() - elif ret['_verb'] == '005': # RPL_ISUPPORT - for item in ret['isupport']: - if item[0] == '-': - del self.db.isupport[item[1:]] - else: - key, data = _tuple_key_val_from_eq_str(item) - self.db.isupport[key] = data - elif ret['_verb'] == '401': # ERR_NOSUCHNICK + if ret['_verb'] == '401': # ERR_NOSUCHNICK raise TargetUserOffline(ret['missing']) - elif ret['_verb'] == '432': # ERR_ERRONEOUSNICKNAME + if ret['_verb'] == '432': # ERR_ERRONEOUSNICKNAME self._alert('nickname refused for bad format, ' + ('keeping current one' if 'nick' in ret else 'giving up')) - elif ret['_verb'] == '433': # ERR_NICKNAMEINUSE - self._alert('nickname already in use, trying increment') - self.send('NICK', _NickUserHost(nick=ret['used']).incremented) - elif ret['_verb'] == 'AUTHENTICATE': - auth = b64encode((self.db.nick_wanted + '\0' - + self.db.nick_wanted + '\0' - + self.db.password - ).encode('utf-8')).decode('utf-8') - self.send('AUTHENTICATE', auth) elif ret['_verb'] == 'CAP': if (self.caps.process_msg(verb=ret['subverb'], items=ret['items'], @@ -875,8 +895,6 @@ class Client(ABC, ClientQueueMixin): self.send('AUTHENTICATE', _SASL_PLAIN) else: self.caps.end_negotiation() - elif ret['_verb'] == 'JOIN' and ret['joiner'] != self.db.users['me']: - self.db.channels[ret['channel']].add_user(ret['joiner']) elif ret['_verb'] == 'MODE' and 'mode_on_nick' in ret: self.db.channels[ret['channel']].mode_on_nick( ret['nick'], ret['mode_on_nick']) @@ -892,11 +910,6 @@ class Client(ABC, ClientQueueMixin): if ret['parter'] is self.db.users['me']: del self.db.channels[ret['channel']] self.db.users.purge() - elif ret['_verb'] == 'PING': - self.send('PONG', ret['reply']) - elif ret['_verb'] == 'PONG': - assert self._expected_pong == ret['reply'] - self._expected_pong = '' ClientsDb = dict[str, Client] diff --git a/src/ircplom/msg_parse_expectations.py b/src/ircplom/msg_parse_expectations.py index 0feaa0f..26cf2e5 100644 --- a/src/ircplom/msg_parse_expectations.py +++ b/src/ircplom/msg_parse_expectations.py @@ -145,7 +145,8 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ '001', # RPL_WELCOME _MsgTok.SERVER, ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'), - _MsgTok.ANY)), + _MsgTok.ANY), + bonus_tasks=('do_autojoin:',)), _MsgParseExpectation( '002', # RPL_YOURHOST @@ -246,7 +247,7 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ '005', # RPL_ISUPPORT _MsgTok.SERVER, ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'), - (_MsgTok.ANY, ':isupport'), + (_MsgTok.ANY, 'do_db.set_isupport_from_rpl:isupport'), _MsgTok.ANY), # comment idx_into_list=1), @@ -297,7 +298,8 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ _MsgParseExpectation( 'AUTHENTICATE', _MsgTok.NONE, - ('+',)), + ('+',), + bonus_tasks=('do_send_authentication:',)), # capability negotation @@ -415,13 +417,13 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ '433', # ERR_NICKNAMEINUSE _MsgTok.SERVER, ('*', - (_MsgTok.NICKNAME, ':used'), + (_MsgTok.NICKNAME, 'do_increment_for_nicknameinuse:rejected'), _MsgTok.ANY)), # comment _MsgParseExpectation( '433', # ERR_NICKNAMEINUSE _MsgTok.SERVER, (_MsgTok.NICKNAME, # we rather go for incrementation - (_MsgTok.NICKNAME, ':used'), + (_MsgTok.NICKNAME, 'do_increment_for_nicknameinuse:rejected'), _MsgTok.ANY)), # comment _MsgParseExpectation( @@ -473,8 +475,8 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ _MsgParseExpectation( 'JOIN', - (_MsgTok.NICK_USER_HOST, ':joiner'), - ((_MsgTok.CHANNEL, ':channel'),)), + (_MsgTok.NICK_USER_HOST, 'do_db.channels.CHANNEL.join_user:user'), + ((_MsgTok.CHANNEL, ':CHANNEL'),)), _MsgParseExpectation( 'PART', @@ -546,13 +548,13 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [ _MsgParseExpectation( 'PING', _MsgTok.NONE, - ((_MsgTok.ANY, ':reply'),)), + ((_MsgTok.ANY, 'do_pong:reply'),)), _MsgParseExpectation( 'PONG', _MsgTok.SERVER, (_MsgTok.SERVER, - (_MsgTok.ANY, ':reply'),)), + (_MsgTok.ANY, 'do_check_pong:reply'),)), # misc. diff --git a/src/tests/channels.test b/src/tests/channels.test index 605a91b..61db464 100644 --- a/src/tests/channels.test +++ b/src/tests/channels.test @@ -35,7 +35,7 @@ insert 001-setting-nick log 1 > JOIN :#ch_test0 insert usermode insert servermsglogged : + MSG ::foo!~baz@baz.bar.foo JOIN #ch_test0 -insert join-empty : + CHAN_WIN_ID=3 CHANNEL :#ch_test0 +insert join-empty 2: + CHAN_WIN_ID=3 CHANNEL :#ch_test0 × join-already-in > /join TARGET