From 6a0c1fe7267a1265e8d332ae5d5ef35448c2053a Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 24 Dec 2022 22:23:32 +0100 Subject: [PATCH] Add software check on follow/unfollow --- relay/http_client.py | 129 ++++++++++++++++++------------------------- relay/manage.py | 12 +++- 2 files changed, 65 insertions(+), 76 deletions(-) diff --git a/relay/http_client.py b/relay/http_client.py index ef1242d..79ac8b9 100644 --- a/relay/http_client.py +++ b/relay/http_client.py @@ -87,55 +87,60 @@ class HttpClient: headers.update(self.database.signer.sign_headers( 'GET', url, algorithm='original')) - try: - logging.verbose(f'Fetching resource: {url}') + async with ClientSession( + connector=TCPConnector( + limit=self.limit, ttl_dns_cache=300), + headers=HEADERS, + connector_owner=True, + timeout=ClientTimeout(total=self.timeout)) as session: + try: + logging.verbose(f'Fetching resource: {url}') + async with session.get(url, headers=headers) as resp: + # Not expecting a response with 202s, so just return + if resp.status == 202: + return - async with self._session.get(url, headers=headers) as resp: - # Not expecting a response with 202s, so just return - if resp.status == 202: - return + elif resp.status != 200: + logging.verbose( + f'Received error when requesting {url}: {resp.status}') + logging.verbose(await resp.read()) # change this to debug + return - elif resp.status != 200: - logging.verbose( - f'Received error when requesting {url}: {resp.status}') - logging.verbose(await resp.read()) # change this to debug - return + if loads: + message = await resp.json(loads=loads) - if loads: - message = await resp.json(loads=loads) + elif resp.content_type == MIMETYPES['activity']: + message = await resp.json(loads=Message.new_from_json) - elif resp.content_type == MIMETYPES['activity']: - message = await resp.json(loads=Message.new_from_json) + elif resp.content_type == MIMETYPES['json']: + message = await resp.json(loads=DotDict.new_from_json) - elif resp.content_type == MIMETYPES['json']: - message = await resp.json(loads=DotDict.new_from_json) + else: + # todo: raise TypeError or something + logging.verbose( + f'Invalid Content-Type for "{url}": {resp.content_type}') + return logging.debug(f'Response: {resp.read()}') - else: - # todo: raise TypeError or something - logging.verbose( - f'Invalid Content-Type for "{url}": {resp.content_type}') - return logging.debug(f'Response: {resp.read()}') + logging.debug(f'{url} >> resp {message.to_json(4)}') - logging.debug(f'{url} >> resp {message.to_json(4)}') + self.cache[url] = message + return message - self.cache[url] = message - return message + except JSONDecodeError: + logging.verbose(f'Failed to parse JSON') - except JSONDecodeError: - logging.verbose(f'Failed to parse JSON') + except (ClientConnectorError, ServerTimeoutError): + logging.verbose(f'Failed to connect to {urlparse(url).netloc}') - except (ClientConnectorError, ServerTimeoutError): - logging.verbose(f'Failed to connect to {urlparse(url).netloc}') + except Exception as e: + traceback.print_exc() + raise e - except Exception as e: - traceback.print_exc() - raise e - - async def post(self, url, message): + async def post(self, url, message, software=None): instance = self.database.get_inbox(url) # Using the old algo by default is probably a better idea right now - if instance and instance.get('software') in {'mastodon'}: + if (instance and instance.get('software') in {'mastodon'}) or (software and software in {'mastodon'}): algorithm = 'hs2019' else: @@ -145,42 +150,18 @@ class HttpClient: headers.update(self.database.signer.sign_headers( 'POST', url, message, algorithm=algorithm)) - try: - logging.verbose(f'Sending "{message.type}" to {url}') - logging.verbose( - f'url: {url}\nheaders: {headers}\ndata: {message.to_json()}') + async with ClientSession( + connector=TCPConnector( + limit=self.limit, ttl_dns_cache=300), + headers=HEADERS, + connector_owner=True, + timeout=ClientTimeout(total=self.timeout)) as session: - # The following does not work and throws exception on 'relay inbox follow': - # Traceback (most recent call last): - # File "/home/vriess/Dokumente/Repos/relay-1/relay/http_client.py", line 153, in post - # async with self._session.post(url, headers=headers, data=message.to_json()) as resp: - # File "/home/vriess/Dokumente/Repos/relay-1/.venv/lib/python3.10/site-packages/aiohttp/client.py", line 1141, in __aenter__ - # self._resp = await self._coro - # File "/home/vriess/Dokumente/Repos/relay-1/.venv/lib/python3.10/site-packages/aiohttp/client.py", line 448, in _request - # handle = tm.start() - # File "/home/vriess/Dokumente/Repos/relay-1/.venv/lib/python3.10/site-packages/aiohttp/helpers.py", line 651, in start - # return self._loop.call_at(when, self.__call__) - # File "/usr/lib/python3.10/asyncio/base_events.py", line 732, in call_at - # self._check_closed() - # File "/usr/lib/python3.10/asyncio/base_events.py", line 515, in _check_closed - # raise RuntimeError('Event loop is closed') - # RuntimeError: Event loop is closed - # ↓↓↓↓ - # async with self._session.post(url, headers=headers, data=message.to_json()) as resp: - # ## Not expecting a response, so just return - # if resp.status in {200, 202}: - # return logging.info(f'Successfully sent "{message.type}" to {url}') + try: + logging.verbose(f'Sending "{message.type}" to {url}') + logging.verbose( + f'url: {url}\nheaders: {headers}\ndata: {message.to_json()}') - # logging.info(f'Received error when pushing to {url}: {resp.status}') - # return logging.info(await resp.read()) # change this to debug - - # Creating a session here works for some reason and does not throw an error - async with ClientSession( - connector=TCPConnector( - limit=self.limit, ttl_dns_cache=300), - headers=HEADERS, - connector_owner=True, - timeout=ClientTimeout(total=self.timeout)) as session: async with session.post(url, headers=headers, data=message.to_json()) as resp: # Not expecting a response, so just return if resp.status in {200, 202}: @@ -191,12 +172,12 @@ class HttpClient: # change this to debug return logging.info(await resp.read()) - except (ClientConnectorError, ServerTimeoutError): - logging.verbose(f'Failed to connect to {url}') + except (ClientConnectorError, ServerTimeoutError): + logging.verbose(f'Failed to connect to {url}') - # prevent workers from being brought down - except Exception as e: - traceback.print_exc() + # prevent workers from being brought down + except Exception as e: + traceback.print_exc() ## Additional methods ## diff --git a/relay/manage.py b/relay/manage.py index 0d7decc..5eb0a77 100644 --- a/relay/manage.py +++ b/relay/manage.py @@ -160,7 +160,11 @@ def cli_inbox_follow(actor): actor = actor ) - asyncio.run(app.client.post(inbox, message)) + # Fetch software to decide on algorithm + nodeinfo = asyncio.run(app.client.fetch_nodeinfo(domain)) + software = nodeinfo.sw_name if nodeinfo else None + + asyncio.run(app.client.post(inbox, message, software)) click.echo(f'Sent follow message to actor: {actor}') @@ -198,7 +202,11 @@ def cli_inbox_unfollow(actor): } ) - asyncio.run(app.client.post(inbox, message)) + # Fetch software to decide on algorithm + nodeinfo = asyncio.run(app.client.fetch_nodeinfo(domain)) + software = nodeinfo.sw_name if nodeinfo else None + + asyncio.run(app.client.post(inbox, message, software)) click.echo(f'Sent unfollow message to: {actor}')