From 89c7ac15ddacace3e5a1cf04c24ea1426b2edc40 Mon Sep 17 00:00:00 2001 From: jesopo Date: Tue, 21 Apr 2020 21:40:46 +0100 Subject: [PATCH] rename some matching Params, restructure matching --- ircrobots/ircv3.py | 6 +- ircrobots/join_info.py | 4 +- ircrobots/matching.py | 98 --------------------------------- ircrobots/matching/__init__.py | 3 + ircrobots/matching/params.py | 50 +++++++++++++++++ ircrobots/matching/responses.py | 63 +++++++++++++++++++++ ircrobots/sasl.py | 4 +- ircrobots/server.py | 7 +-- 8 files changed, 126 insertions(+), 109 deletions(-) delete mode 100644 ircrobots/matching.py create mode 100644 ircrobots/matching/__init__.py create mode 100644 ircrobots/matching/params.py create mode 100644 ircrobots/matching/responses.py diff --git a/ircrobots/ircv3.py b/ircrobots/ircv3.py index 835c697..3ccef8a 100644 --- a/ircrobots/ircv3.py +++ b/ircrobots/ircv3.py @@ -5,7 +5,7 @@ from irctokens import build from ircstates.server import ServerDisconnectedException from .contexts import ServerContext -from .matching import Response, ResponseOr, ParamAny +from .matching import Response, ResponseOr, ANY from .interface import ICapability from .params import ConnectionParams, STSPolicy @@ -101,8 +101,8 @@ class CAPContext(ServerContext): while cap_names: line = await self.server.wait_for(ResponseOr( - Response("CAP", [ParamAny(), "ACK"]), - Response("CAP", [ParamAny(), "NAK"]) + Response("CAP", [ANY, "ACK"]), + Response("CAP", [ANY, "NAK"]) )) current_caps = line.params[2].split(" ") diff --git a/ircrobots/join_info.py b/ircrobots/join_info.py index 2d0f238..2d95abe 100644 --- a/ircrobots/join_info.py +++ b/ircrobots/join_info.py @@ -3,7 +3,7 @@ from irctokens import build from ircstates.numerics import * from .contexts import ServerContext -from .matching import Response, ResponseOr, ParamAny, ParamFolded +from .matching import Response, ResponseOr, ANY, Folded class WHOContext(ServerContext): async def ensure(self, channel: str): @@ -15,5 +15,5 @@ class WHOContext(ServerContext): await self.server.send(build("WHO", [channel])) line = await self.server.wait_for( - Response(RPL_ENDOFWHO, [ParamAny(), ParamFolded(folded)]) + Response(RPL_ENDOFWHO, [ANY, Folded(folded)]) ) diff --git a/ircrobots/matching.py b/ircrobots/matching.py deleted file mode 100644 index ce77d37..0000000 --- a/ircrobots/matching.py +++ /dev/null @@ -1,98 +0,0 @@ -from typing import List, Optional, Union -from irctokens import Line, Hostmask -from .interface import (IServer, IMatchResponse, IMatchResponseParam, - IMatchResponseHostmask) - -TYPE_PARAM = Union[str, IMatchResponseParam] -class Responses(IMatchResponse): - def __init__(self, - commands: List[str], - params: List[TYPE_PARAM]=[], - source: Optional[IMatchResponseHostmask]=None): - self._commands = commands - self._params = params - self._source = source - def __repr__(self) -> str: - return f"Responses({self._commands!r}: {self._params!r})" - - def match(self, server: IServer, line: Line) -> bool: - for command in self._commands: - if (line.command == command and ( - self._source is None or ( - line.hostmask is not None and - self._source.match(server, line.hostmask) - ))): - - for i, param in enumerate(self._params): - if i >= len(line.params): - break - elif (isinstance(param, str) and - not param == line.params[i]): - break - elif (isinstance(param, IMatchResponseParam) and - not param.match(server, line.params[i])): - break - else: - return True - else: - return False - -class Response(Responses): - def __init__(self, - command: str, - params: List[TYPE_PARAM]=[], - source: Optional[IMatchResponseHostmask]=None): - super().__init__([command], params, source=source) - - def __repr__(self) -> str: - return f"Response({self._commands[0]}: {self._params!r})" - -class ResponseOr(IMatchResponse): - def __init__(self, *responses: IMatchResponse): - self._responses = responses - def __repr__(self) -> str: - return f"ResponseOr({self._responses!r})" - def match(self, server: IServer, line: Line) -> bool: - for response in self._responses: - if response.match(server, line): - return True - else: - return False - -class ParamAny(IMatchResponseParam): - def __repr__(self) -> str: - return "Any()" - def match(self, server: IServer, arg: str) -> bool: - return True - -class ParamFolded(IMatchResponseParam): - def __init__(self, value: str): - self._value = value - self._folded: Optional[str] = None - def __repr__(self) -> str: - return f"FoldString({self._value!r})" - def match(self, server: IServer, arg: str) -> bool: - if self._folded is None: - self._folded = server.casefold(self._value) - return self._folded == server.casefold(arg) - -class ParamNot(IMatchResponseParam): - def __init__(self, param: IMatchResponseParam): - self._param = param - def __repr__(self) -> str: - return f"Not({self._param!r})" - def match(self, server: IServer, arg: str) -> bool: - return not self._param.match(server, arg) - -class Nickname(IMatchResponseHostmask): - def __init__(self, nickname: str): - self._nickname = nickname - self._folded: Optional[str] = None - - def __repr__(self) -> str: - mask = f"{self._nickname}!*@*" - return f"Hostmask({mask!r})" - def match(self, server: IServer, hostmask: Hostmask): - if self._folded is None: - self._folded = server.casefold(self._nickname) - return self._folded == server.casefold(hostmask.nickname) diff --git a/ircrobots/matching/__init__.py b/ircrobots/matching/__init__.py new file mode 100644 index 0000000..58608e6 --- /dev/null +++ b/ircrobots/matching/__init__.py @@ -0,0 +1,3 @@ + +from .responses import * +from .params import * diff --git a/ircrobots/matching/params.py b/ircrobots/matching/params.py new file mode 100644 index 0000000..5979c9d --- /dev/null +++ b/ircrobots/matching/params.py @@ -0,0 +1,50 @@ +from typing import Optional +from irctokens import Hostmask +from ..interface import IMatchResponseParam, IMatchResponseHostmask, IServer + +class Any(IMatchResponseParam): + def __repr__(self) -> str: + return "Any()" + def match(self, server: IServer, arg: str) -> bool: + return True +ANY = Any() + +class Literal(IMatchResponseParam): + def __init__(self, value: str): + self._value = value + def __repr__(self) -> str: + return f"{self._value!r}" + def match(self, server: IServer, arg: str) -> bool: + return arg == self._value + +class Folded(IMatchResponseParam): + def __init__(self, value: str): + self._value = value + self._folded: Optional[str] = None + def __repr__(self) -> str: + return f"FoldString({self._value!r})" + def match(self, server: IServer, arg: str) -> bool: + if self._folded is None: + self._folded = server.casefold(self._value) + return self._folded == server.casefold(arg) + +class Not(IMatchResponseParam): + def __init__(self, param: IMatchResponseParam): + self._param = param + def __repr__(self) -> str: + return f"Not({self._param!r})" + def match(self, server: IServer, arg: str) -> bool: + return not self._param.match(server, arg) + +class Nickname(IMatchResponseHostmask): + def __init__(self, nickname: str): + self._nickname = nickname + self._folded: Optional[str] = None + + def __repr__(self) -> str: + mask = f"{self._nickname}!*@*" + return f"Hostmask({mask!r})" + def match(self, server: IServer, hostmask: Hostmask): + if self._folded is None: + self._folded = server.casefold(self._nickname) + return self._folded == server.casefold(hostmask.nickname) diff --git a/ircrobots/matching/responses.py b/ircrobots/matching/responses.py new file mode 100644 index 0000000..0aee0de --- /dev/null +++ b/ircrobots/matching/responses.py @@ -0,0 +1,63 @@ +from typing import List, Optional, Union +from irctokens import Line +from ..interface import (IServer, IMatchResponse, IMatchResponseParam, + IMatchResponseHostmask) +from .params import * + +TYPE_PARAM = Union[str, IMatchResponseParam] +class Responses(IMatchResponse): + def __init__(self, + commands: List[str], + params: List[TYPE_PARAM]=[], + source: Optional[IMatchResponseHostmask]=None): + self._commands = commands + self._source = source + + self._params: List[IMatchResponseParam] = [] + for param in params: + if isinstance(param, str): + self._params.append(Literal(param)) + elif isinstance(param, IMatchResponseParam): + self._params.append(param) + + def __repr__(self) -> str: + return f"Responses({self._commands!r}: {self._params!r})" + + def match(self, server: IServer, line: Line) -> bool: + for command in self._commands: + if (line.command == command and ( + self._source is None or ( + line.hostmask is not None and + self._source.match(server, line.hostmask) + ))): + + for i, param in enumerate(self._params): + if (i >= len(line.params) or + not param.match(server, line.params[i])): + break + else: + return True + else: + return False + +class Response(Responses): + def __init__(self, + command: str, + params: List[TYPE_PARAM]=[], + source: Optional[IMatchResponseHostmask]=None): + super().__init__([command], params, source=source) + + def __repr__(self) -> str: + return f"Response({self._commands[0]}: {self._params!r})" + +class ResponseOr(IMatchResponse): + def __init__(self, *responses: IMatchResponse): + self._responses = responses + def __repr__(self) -> str: + return f"ResponseOr({self._responses!r})" + def match(self, server: IServer, line: Line) -> bool: + for response in self._responses: + if response.match(server, line): + return True + else: + return False diff --git a/ircrobots/sasl.py b/ircrobots/sasl.py index 7dfbcf9..028b744 100644 --- a/ircrobots/sasl.py +++ b/ircrobots/sasl.py @@ -4,7 +4,7 @@ from base64 import b64decode, b64encode from irctokens import build from ircstates.numerics import * -from .matching import ResponseOr, Responses, Response, ParamAny +from .matching import ResponseOr, Responses, Response, ANY from .contexts import ServerContext from .params import SASLParams from .scram import SCRAMContext @@ -29,7 +29,7 @@ class SASLUnknownMechanismError(SASLError): AUTH_BYTE_MAX = 400 -AUTHENTICATE_ANY = Response("AUTHENTICATE", [ParamAny()]) +AUTHENTICATE_ANY = Response("AUTHENTICATE", [ANY]) NUMERICS_FAIL = Response(ERR_SASLFAIL) NUMERICS_INITIAL = Responses([ERR_SASLFAIL, ERR_SASLALREADY, RPL_SASLMECHS]) diff --git a/ircrobots/server.py b/ircrobots/server.py index c2cf45e..f2ff9aa 100644 --- a/ircrobots/server.py +++ b/ircrobots/server.py @@ -12,8 +12,7 @@ from .ircv3 import (CAPContext, sts_transmute, CAP_ECHO, CAP_SASL, CAP_LABEL, LABEL_TAG) from .sasl import SASLContext, SASLResult from .join_info import WHOContext -from .matching import (ResponseOr, Responses, Response, ParamAny, ParamFolded, - Nickname) +from .matching import ResponseOr, Responses, Response, ANY, Folded, Nickname from .asyncs import MaybeAwait from .struct import Whois from .params import ConnectionParams, SASLParams, STSPolicy @@ -285,7 +284,7 @@ class Server(IServer): while folded_names: line = await self.wait_for( - Response(RPL_CHANNELMODEIS, [ParamAny(), ParamAny()]) + Response(RPL_CHANNELMODEIS, [ANY, ANY]) ) folded = self.casefold(line.params[1]) @@ -302,7 +301,7 @@ class Server(IServer): async def _assure(): await fut - params = [ParamAny(), ParamFolded(folded)] + params = [ANY, Folded(folded)] obj = Whois() while True: line = await self.wait_for(Responses([