key, data = _tuple_key_val_from_eq_str(item)
self.isupport[key] = data
+ def set_nick_incl_wanted(self, user: _User, nick: str) -> None:
+ 'Set new_nick to user, and .nick_wanted if ourselves.'
+ self.users[user.id_].nick = nick
+ if user.id_ == 'me':
+ self.nick_wanted = nick
+
+ def part_user_maybe_us(self, parter: _User, channel: str, msg='') -> None:
+ 'Call parter.part, and if ourselves also remove channel.'
+ parter.part(channel, msg)
+ if parter is self.users['me']:
+ del self.channels[channel]
+ self.users.purge()
+
def messaging(self, src: str | NickUserHost) -> ChatMessage:
'Start input chain for chat message data.'
return _ChatMessage(sender=src, db=self)
for ret_name in [k for k in ret if ret[k] == n_u_h]:
ret[ret_name] = self.db.users[id_]
for verb in ('setattr', 'do', 'doafter'):
- for task, tok_names in [t for t in ret['_tasks'].items()
- if t[0].verb == verb]:
+ for task, args in [t for t in ret['_tasks'].items()
+ if t[0].verb == verb]:
path = list(task.path)
node: Any = (ret[path.pop(0)]
if task.path and path[0].isupper() else self)
node = (node[key] if isinstance(node, Dict)
else (node(key) if callable(node)
else getattr(node, key)))
- for tok_name in tok_names:
+ for arg in args:
if task.verb == 'setattr':
- setattr(node, tok_name, ret[tok_name])
- elif tok_name:
- node(ret[tok_name])
+ setattr(node, arg, ret[arg])
+ elif ',' in arg:
+ node(*(ret[split] for split in arg.split(',')))
+ elif arg:
+ node(ret[arg])
else:
node()
if ret['_verb'] == '401': # ERR_NOSUCHNICK
self.send('AUTHENTICATE', _SASL_PLAIN)
else:
self.caps.end_negotiation()
- elif ret['_verb'] == 'MODE' and 'mode_on_nick' in ret:
- self.db.channels[ret['channel']].mode_on_nick(
- ret['nick'], ret['mode_on_nick'])
- elif ret['_verb'] == 'NICK':
- user_id = self.db.users.id_for_nickuserhost(ret['named'],
- updating=True)
- assert user_id is not None
- self.db.users[user_id].nick = ret['nick']
- if user_id == 'me':
- self.db.nick_wanted = ret['nick']
- elif ret['_verb'] == 'PART':
- ret['parter'].part(ret['channel'], ret.get('message', ''))
- if ret['parter'] is self.db.users['me']:
- del self.db.channels[ret['channel']]
- self.db.users.purge()
ClientsDb = dict[str, Client]
class _Code(NamedTuple):
- tok_name: str = ''
commands: tuple[_Command, ...] = tuple()
+ arg: str = ''
skip_nuh: bool = False
def __bool__(self) -> bool:
- return bool(self.tok_name) or bool(self.commands)
+ return bool(self.commands) or bool(self.arg)
@classmethod
def from_(cls, input_: str) -> Self:
- 'Split by ":" into commands (further split by ","), tok_name.'
- commands_str, tok_name = input_.split(':', maxsplit=1)
+ 'Split by ":" into commands (further split by ","), argument.'
+ commands_str, arg = input_.split(':', maxsplit=1)
skip_nuh = False
commands: list[_Command] = []
for command_str in commands_str.split(','):
skip_nuh = True
elif command_str:
commands += [_Command.from_(command_str)]
- return cls(tok_name, tuple(commands), skip_nuh)
+ return cls(tuple(commands), arg, skip_nuh)
class _TokenExpectation(NamedTuple):
for code in (tuple(exp_field.code for exp_field in self._fields)
+ tuple(_Code.from_(item) for item in bonus_tasks)):
for cmd in code.commands:
- tasks[cmd] = tasks.get(cmd, []) + [code.tok_name]
+ tasks[cmd] = tasks.get(cmd, []) + [code.arg]
self._harvest_invariables = {'_verb': self.verb, '_tasks': tasks}
@property
if not validators.get(exp_tok.type_, lambda _: True)(msg_tok):
return None # validator found for this type, but failed it
if isinstance(exp_tok.type_, str) and exp_tok.type_ != msg_tok:
- return None # validator for specific string
+ return None # "specific string"-validator failed
if exp_tok.type_ is _MsgToken.NICK_USER_HOST\
and not exp_tok.code.skip_nuh:
nickuserhosts += [parsed(exp_tok.type_, msg_tok)]
- if exp_tok.code.tok_name:
- d[exp_tok.code.tok_name] = parsed(exp_tok.type_, msg_tok)
+ if exp_tok.code.arg:
+ d[exp_tok.code.arg] = parsed(exp_tok.type_, msg_tok)
return d | {'_nickuserhosts': tuple(nickuserhosts)}
if (msg_fields := divide_msg(msg)):
_MsgParseExpectation(
'NICK',
- (_MsgToken.NICK_USER_HOST, ':named'),
- ((_MsgToken.NICKNAME, ':nick'),)),
+ (_MsgToken.NICK_USER_HOST, ':user'),
+ ((_MsgToken.NICKNAME, ':nick'),),
+ bonus_tasks=('do_db.set_nick_incl_wanted:user,nick',)),
# joining/leaving
_MsgParseExpectation(
'PART',
(_MsgToken.NICK_USER_HOST, ':parter'),
- ((_MsgToken.CHANNEL, ':channel'),)),
+ ((_MsgToken.CHANNEL, ':channel'),),
+ bonus_tasks=('do_db.part_user_maybe_us:parter,channel',)),
_MsgParseExpectation(
'PART',
(_MsgToken.NICK_USER_HOST, ':parter'),
((_MsgToken.CHANNEL, ':channel'),
- (_MsgToken.ANY, ':message'))),
+ (_MsgToken.ANY, ':message')),
+ bonus_tasks=('do_db.part_user_maybe_us:parter,channel,message',)),
# messaging
_MsgParseExpectation(
'MODE',
_MsgToken.SERVER,
- ((_MsgToken.CHANNEL, ':channel'),
- (_MsgToken.ANY, ':mode_on_nick'),
- (_MsgToken.NICKNAME, ':nick'))),
+ ((_MsgToken.CHANNEL, ':CHANNEL'),
+ (_MsgToken.ANY, ':mode'),
+ (_MsgToken.NICKNAME, ':nick')),
+ bonus_tasks=('do_db.channels.CHANNEL.mode_on_nick:nick,mode',)),
_MsgParseExpectation(
'TOPIC',