From 35b2e46945163ccae6dcba83a709a7c8314f8231 Mon Sep 17 00:00:00 2001 From: jesopo Date: Thu, 19 Mar 2020 11:28:44 +0000 Subject: [PATCH] change Emits to just be one object --- ircstates/emit.py | 66 +++++--------------- ircstates/server.py | 147 ++++++++++++++++++++++++++------------------ test/channel.py | 5 +- test/emit.py | 69 +++++++++++++-------- 4 files changed, 146 insertions(+), 141 deletions(-) diff --git a/ircstates/emit.py b/ircstates/emit.py index 77049ac..ad87495 100644 --- a/ircstates/emit.py +++ b/ircstates/emit.py @@ -1,60 +1,24 @@ -from typing import List +from typing import List, Optional from .user import User from .channel import Channel -class Emit(object): - def __eq__(self, other): - return repr(self) == repr(other) +class Emits(object): + command: Optional[str] = None -class EmitCommand(Emit): - def __init__(self, command: str): - self.command = command - def __repr__(self) -> str: - return f"EmitCommand({self.command})" + text: Optional[str] = None -class EmitSelf(Emit): - def __repr__(self) -> str: - return f"{self.__class__.__name__}()" -class EmitSourceSelf(EmitSelf): - pass -class EmitTargetSelf(EmitSelf): - pass + self: Optional[bool] = None + self_source: Optional[bool] = None + self_target: Optional[bool] = None -class EmitText(Emit): - def __init__(self, text: str): - self.text = text - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.text!r})" + user: Optional[User] = None + user_source: Optional[User] = None + user_target: Optional[User] = None -class EmitUser(Emit): - def __init__(self, user: User): - self.user = user - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.user.nickname!r})" -class EmitSourceUser(EmitUser): - pass -class EmitTargetUser(EmitSourceUser): - pass + users: Optional[List[User]] = None -class EmitUsers(Emit): - def __init__(self, users: List[User]): - self.users = users - def __repr__(self) -> str: - return f"Users(count={len(self.users)})" - -class EmitChannel(Emit): - def __init__(self, channel: Channel): - self.channel = channel - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.channel.name!r})" -class EmitSourceChannel(EmitChannel): - pass -class EmitTargetChannel(EmitChannel): - pass - -class EmitTarget(Emit): - def __init__(self, target: str): - self.target = target - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.target!r})" + channel: Optional[Channel] = None + channel_source: Optional[Channel] = None + channel_target: Optional[Channel] = None + target: Optional[str] = None diff --git a/ircstates/server.py b/ircstates/server.py index 105cfac..4107071 100644 --- a/ircstates/server.py +++ b/ircstates/server.py @@ -11,7 +11,7 @@ from .decorators import line_handler_decorator from .casemap import casefold from .emit import * -LINE_HANDLERS: Dict[str, List[Callable[["Server", Line], List[Emit]]]] = {} +LINE_HANDLERS: Dict[str, List[Callable[["Server", Line], Emits]]] = {} line_handler = line_handler_decorator(LINE_HANDLERS) class ServerException(Exception): @@ -60,10 +60,9 @@ class Server(Named): def parse_tokens(self, line: Line): all_emits: List[List[Emit]] = [] if line.command in LINE_HANDLERS: - command_emit = EmitCommand(line.command) for callback in LINE_HANDLERS[line.command]: emits = callback(self, line) - emits.insert(0, command_emit) + emits.command = line.command all_emits.append(emits) return all_emits @@ -96,8 +95,8 @@ class Server(Named): self.channel_users[channel][user] = channel_user return channel_user - def _emit(self) -> List[Emit]: - return [] + def _emit(self) -> Emits: + return Emits() @line_handler("001") # first message reliably sent to us after registration is complete @@ -124,7 +123,7 @@ class Server(Named): def handle_372(self, line: Line): emits = self._emit() text = line.params[1] - emits.append(EmitText(text)) + emits.text = text self.motd.append(text) return emits @@ -137,13 +136,13 @@ class Server(Named): if nickname_lower in self.users: user = self.users.pop(nickname_lower) - emits.append(EmitSourceUser(user)) + emits.user = user new_nickname_lower = self.casefold(new_nickname) user.set_nickname(new_nickname, new_nickname_lower) self.users[new_nickname_lower] = user if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self.nickname = new_nickname self.nickname_lower = self.casefold(new_nickname) @@ -161,7 +160,7 @@ class Server(Named): channel_lower = self.casefold(line.params[0]) nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True if not channel_lower in self.channels: channel = Channel(line.params[0]) self.channels[channel_lower] = channel @@ -176,12 +175,12 @@ class Server(Named): if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel if not nickname_lower in self.users: self.add_user(line.hostmask.nickname, nickname_lower) user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) + emits.user = user if line.hostmask.username: user.username = line.hostmask.username if line.hostmask.hostname: @@ -196,18 +195,29 @@ class Server(Named): def _handle_part(self, line: Line, nickname: str, channel_name: str, - reason_i: int): + reason_i: int) -> Tuple[Emits, Optional[User]]: emits = self._emit() channel_lower = self.casefold(channel_name) reason = line.params[reason_i] if line.params[reason_i:] else None if not reason is None: - emits.append(EmitText(reason)) + emits.text = reason + user: Optional[User] = None if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) - if self.casefold_equals(nickname, self.nickname): - emits.append(EmitSourceSelf()) + emits.channel = channel + + nickname_lower = self.casefold(nickname) + if nickname_lower in self.users: + user = self.users[nickname_lower] + user = user + self.user_channels[user].remove(channel) + if not self.user_channels[user]: + del self.users[nickname_lower] + del self.user_channels[user] + del self.channel_users[channel][user] + + if nickname_lower == self.nickname_lower: del self.channels[channel_lower] channel_users = self.channel_users.pop(channel) @@ -216,25 +226,39 @@ class Server(Named): if not self.user_channels[user]: del self.user_channels[user] del self.users[self.casefold(user.nickname)] - else: - nickname_lower = self.casefold(nickname) - if nickname_lower in self.users: - user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) - self.user_channels[user].remove(channel) - if not self.user_channels[user]: - del self.users[nickname_lower] - del self.user_channels[user] - del self.channel_users[channel][user] - return emits + + return emits, user @line_handler("PART") def handle_PART(self, line: Line): - return self._handle_part(line, line.hostmask.nickname, line.params[0], - 1) + emits, user = self._handle_part(line, line.hostmask.nickname, + line.params[0], 1) + if not user is None: + emits.user = user + if user.nickname_lower == self.nickname_lower: + emits.self = True + return emits @line_handler("KICK") def handle_KICK(self, line: Line): - return self._handle_part(line, line.params[1], line.params[0], 2) + emits, kicked = self._handle_part(line, line.params[1], line.params[0], + 2) + if not kicked is None: + emits.user_target = kicked + + if kicked.nickname_lower == self.nickname_lower: + emits.self = True + + kicker_lower = self.casefold(line.hostmask.nickname) + if kicker_lower == self.nickname_lower: + emits.self_source = True + + if kicker_lower in self.users: + emits.user_source = self.users[kicker_lower] + else: + emits.user_source = self.create_user(line.hostmask.nickname, + kicker_lower) + + return emits def _self_quit(self): self.users.clear() @@ -248,15 +272,15 @@ class Server(Named): nickname_lower = self.casefold(line.hostmask.nickname) reason = line.params[0] if line.params else None if not reason is None: - emits.append(EmitText(reason)) + emits.text = reason if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self._self_quit() else: if nickname_lower in self.users: user = self.users.pop(nickname_lower) - emits.append(EmitSourceUser(user)) + emits.user = user for channel in self.user_channels[user]: del self.channel_users[channel][user] del self.user_channels[user] @@ -274,10 +298,10 @@ class Server(Named): channel_lower = self.casefold(line.params[2]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel nicknames = list(filter(bool, line.params[3].split(" "))) users: List[User] = [] - emits.append(EmitUsers(users)) + emits.users = users for nickname in nicknames: modes = "" @@ -318,7 +342,7 @@ class Server(Named): channel_lower = self.casefold(line.params[1]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel channel.created = datetime.fromtimestamp(int(line.params[2])) return emits @@ -328,7 +352,7 @@ class Server(Named): channel_lower = self.casefold(line.params[0]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel channel.topic = line.params[1] channel.topic_setter = str(line.hostmask) channel.topic_time = datetime.utcnow() @@ -341,7 +365,7 @@ class Server(Named): channel_lower = self.casefold(line.params[1]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel self.channels[channel_lower].topic = line.params[2] return emits @line_handler("333") @@ -351,7 +375,7 @@ class Server(Named): channel_lower = self.casefold(line.params[1]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel channel.topic_setter = line.params[2] channel.topic_time = datetime.fromtimestamp(int(line.params[3])) return emits @@ -406,7 +430,7 @@ class Server(Named): target_lower = self.casefold(target) if target_lower == self.nickname_lower: - emits.append(EmitTargetSelf()) + emits.self_target = True for add, char in modes: if add: if not char in self.modes: @@ -415,7 +439,7 @@ class Server(Named): self.modes.remove(char) elif target_lower in self.channels: channel = self.channels[self.casefold(target)] - emits.append(EmitChannel(channel)) + emits.channel = channel self._channel_modes(channel, modes, params) return emits @@ -426,7 +450,7 @@ class Server(Named): channel_lower = self.casefold(line.params[1]) if channel_lower in self.channels: channel = self.channels[channel_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel modes = [(True, char) for char in line.params[2].lstrip("+")] params = line.params[3:] self._channel_modes(channel, modes, params) @@ -447,11 +471,11 @@ class Server(Named): emits = self._emit() message = line.params[1] if line.params[1:] else None if not message is None: - emits.append(EmitText(message)) + emits.text = message nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self_source = True if line.hostmask.username: self.username = line.hostmask.username if line.hostmask.hostname: @@ -461,7 +485,8 @@ class Server(Named): user = self.users[nickname_lower] else: user = self.create_user(line.hostmask.nickname, nickname_lower) - emits.append(EmitSourceUser(user)) + emits.user = user + if line.hostmask.username: user.username = line.hostmask.username if line.hostmask.hostname: @@ -475,15 +500,15 @@ class Server(Named): target = target[1:] else: break - emits.append(EmitTarget(target_raw)) + emits.target = target_raw target_lower = self.casefold(target) if self.is_channel(target): if target_lower in self.channels: channel = self.channels[target_lower] - emits.append(EmitChannel(channel)) + emits.channel = channel elif target_lower == self.nickname_lower: - emits.append(EmitTargetSelf()) + emits.self_target = True return emits @line_handler("396") @@ -499,7 +524,7 @@ class Server(Named): # WHO line, "WHO #channel|nickname" response def handle_352(self, line: Line): emits = self._emit() - emits.append(EmitTarget(line.params[1])) + emits.target = line.params[1] nickname = line.params[5] username = line.params[2] hostname = line.params[3] @@ -507,14 +532,14 @@ class Server(Named): nickname_lower = self.casefold(line.params[5]) if nickname_lower == self.nickname_lower: - emits.append(EmitSelf()) + emits.self = True self.username = username self.hostname = hostname self.realname = realname if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitUser(user)) + emits.user = user user.username = username user.hostname = hostname user.realname = realname @@ -531,14 +556,14 @@ class Server(Named): nickname_lower = self.casefold(nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSelf()) + emits.self = True self.username = username self.hostname = hostname self.realname = realname if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitUser(user)) + emits.user = user user.username = username user.hostname = hostname user.realname = realname @@ -551,13 +576,13 @@ class Server(Named): hostname = line.params[1] nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self.username = username self.hostname = hostname if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) + emits.user = user user.username = username user.hostname = hostname return emits @@ -568,12 +593,12 @@ class Server(Named): realname = line.params[0] nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self.realname = realname if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) + emits.user = user user.realname = realname return emits @@ -583,12 +608,12 @@ class Server(Named): away = line.params[0] if line.params else None nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self.away = away if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) + emits.user = user user.away = away return emits @@ -598,12 +623,12 @@ class Server(Named): account = line.params[0].strip("*") nickname_lower = self.casefold(line.hostmask.nickname) if nickname_lower == self.nickname_lower: - emits.append(EmitSourceSelf()) + emits.self = True self.account = account if nickname_lower in self.users: user = self.users[nickname_lower] - emits.append(EmitSourceUser(user)) + emits.user = user user.account = account return emits diff --git a/test/channel.py b/test/channel.py index 05d9e78..82137bc 100644 --- a/test/channel.py +++ b/test/channel.py @@ -62,7 +62,8 @@ class ChannelTestKick(unittest.TestCase): server = ircstates.Server("test") server.parse_tokens(irctokens.tokenise("001 nickname")) server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan")) - server.parse_tokens(irctokens.tokenise("KICK #chan nickname")) + server.parse_tokens( + irctokens.tokenise(":nickname KICK #chan nickname")) self.assertEqual(len(server.users), 0) self.assertEqual(len(server.channels), 0) self.assertEqual(len(server.user_channels), 0) @@ -73,7 +74,7 @@ class ChannelTestKick(unittest.TestCase): server.parse_tokens(irctokens.tokenise("001 nickname")) server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan")) server.parse_tokens(irctokens.tokenise(":other JOIN #chan")) - server.parse_tokens(irctokens.tokenise("KICK #chan other")) + server.parse_tokens(irctokens.tokenise(":nickname KICK #chan other")) user = server.users["nickname"] channel = server.channels["#chan"] diff --git a/test/emit.py b/test/emit.py index fbbe7ba..3b37593 100644 --- a/test/emit.py +++ b/test/emit.py @@ -8,18 +8,17 @@ class EmitTest(unittest.TestCase): emits = server.parse_tokens( irctokens.tokenise(":nickname JOIN #chan"))[0] - self.assertIn(ircstates.EmitCommand("JOIN"), emits) - self.assertIn(ircstates.EmitSourceSelf(), emits) - user = server.users["nickname"] - self.assertIn(ircstates.EmitSourceUser(user), emits) - channel = server.channels["#chan"] - self.assertIn(ircstates.EmitChannel(channel), emits) + self.assertEqual(emits.command, "JOIN") + self.assertEqual(emits.self, True) + self.assertEqual(emits.user, server.users["nickname"]) + self.assertEqual(emits.channel, server.channels["#chan"]) emits = server.parse_tokens( irctokens.tokenise(":other JOIN #chan"))[0] - self.assertNotIn(ircstates.EmitSourceSelf(), emits) - other = server.users["other"] - self.assertIn(ircstates.EmitSourceUser(other), emits) + self.assertEqual(emits.command, "JOIN") + self.assertEqual(emits.self, None) + self.assertEqual(emits.user, server.users["other"]) + self.assertEqual(emits.channel, server.channels["#chan"]) def test_privmsg(self): server = ircstates.Server("test") @@ -27,21 +26,20 @@ class EmitTest(unittest.TestCase): server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan")) emits = server.parse_tokens( irctokens.tokenise(":nickname PRIVMSG #chan :hello"))[0] - - self.assertIn(ircstates.EmitCommand("PRIVMSG"), emits) - self.assertIn(ircstates.EmitText("hello"), emits) - self.assertIn(ircstates.EmitSourceSelf(), emits) - user = server.users["nickname"] - self.assertIn(ircstates.EmitSourceUser(user), emits) - channel = server.channels["#chan"] - self.assertIn(ircstates.EmitChannel(channel), emits) + self.assertEqual(emits.command, "PRIVMSG") + self.assertEqual(emits.text, "hello") + self.assertEqual(emits.self_source, True) + self.assertEqual(emits.user, server.users["nickname"]) + self.assertEqual(emits.channel, server.channels["#chan"]) server.parse_tokens(irctokens.tokenise(":other JOIN #chan")) emits = server.parse_tokens( - irctokens.tokenise(":other PRIVMSG #chan :hello"))[0] - self.assertNotIn(ircstates.EmitSourceSelf(), emits) - other = server.users["other"] - self.assertIn(ircstates.EmitSourceUser(other), emits) + irctokens.tokenise(":other PRIVMSG #chan :hello2"))[0] + self.assertEqual(emits.command, "PRIVMSG") + self.assertEqual(emits.text, "hello2") + self.assertEqual(emits.self_source, None) + self.assertEqual(emits.user, server.users["other"]) + self.assertEqual(emits.channel, server.channels["#chan"]) def test_privmsg_nojoin(self): server = ircstates.Server("test") @@ -51,10 +49,27 @@ class EmitTest(unittest.TestCase): emits = server.parse_tokens( irctokens.tokenise(":other PRIVMSG #chan :hello"))[0] - self.assertIn(ircstates.EmitCommand("PRIVMSG"), emits) - self.assertIn(ircstates.EmitText("hello"), emits) - self.assertNotIn(ircstates.EmitSourceSelf(), emits) - self.assertIn(ircstates.EmitSourceUser( - server.create_user("other", "other")), emits) + self.assertEqual(emits.command, "PRIVMSG") + self.assertEqual(emits.text, "hello") + self.assertEqual(emits.self_source, None) + self.assertIsNotNone(emits.user) channel = server.channels["#chan"] - self.assertIn(ircstates.EmitChannel(channel), emits) + self.assertEqual(emits.channel, channel) + + def test_kick(self): + server = ircstates.Server("test") + server.parse_tokens(irctokens.tokenise("001 nickname")) + server.parse_tokens(irctokens.tokenise(":nickname JOIN #chan")) + user = server.users["nickname"] + channel = server.channels["#chan"] + server.parse_tokens(irctokens.tokenise(":other JOIN #chan")) + user_other = server.users["other"] + emits = server.parse_tokens( + irctokens.tokenise(":nickname KICK #chan other :reason"))[0] + + self.assertEqual(emits.command, "KICK") + self.assertEqual(emits.text, "reason") + self.assertEqual(emits.self_source, True) + self.assertEqual(emits.user_source, user) + self.assertEqual(emits.user_target, user_other) + self.assertEqual(emits.channel, channel)