uncia/uncia/functions.py

139 lines
2.5 KiB
Python

import json
from functools import wraps
from izzylib import DotDict, LruCache, logging
from izzylib.http_urllib_client import HttpUrllibClient
from izzylib.http_urllib_client.error import MaxRetryError
from . import __version__
from .config import config
from .database import db
client = HttpUrllibClient(
appagent = f'UnciaRelay/{__version__}; https://{config.host}',
headers = {
'accept': 'application/activity+json,application/json'
}
)
client.set_global()
fetch_cache = LruCache()
def fetch_actor(url):
with db.session as s:
cached = s.get.actor(url)
if cached:
return cached
data = fetch(url, sign=True, cache=False)
if data == False:
return False
try:
error = data.get('error')
except:
error = None
if error:
logging.debug(f'Failed to fetch actor "{url}" with error: {error}')
return
if not data:
logging.verbose(f'Failed to fetch actor: {url}')
return
s.put.actor(url, data)
return data
def fetch(url, sign=False, headers={}, cache=True):
cached_data = fetch_cache.fetch(url)
if cached_data and cache:
return cached_data
if sign:
with db.session as s:
response = client.request(url,
privkey = s.get.config('privkey'),
keyid = f'https://{config.host}/actor#main-key',
headers = {}
)
else:
response = client.request(url)
if response.status == 410:
return False
try:
data = response.dict
except json.decoder.JSONDecodeError:
return {}
if not data:
return {}
if cache:
fetch_cache.store(url, data)
return data
def fetch_auth(url):
return fetch(url, sign=True)
def get_inbox(actor):
if not actor:
return
try:
return actor.endpoints.sharedInbox
except:
return actor.inbox
def push_message(inbox, message, headers={}):
with db.session as s:
try:
response = client.request(
inbox,
body = message.to_json(),
method = 'post',
privkey = s.get.config('privkey'),
keyid = f'https://{config.host}/actor#main-key'
)
except MaxRetryError as e:
response = DotDict(status=0, error=e)
except Exception as e:
#logging.debug(f'push_message: {e.__class__.__name__}: {e}')
response = DotDict(status=0, error=e)
if response.status not in [200, 202]:
s.put.retry(inbox, message, headers)
if response.status:
try:
body = response.dict
except:
body = response.text
logging.debug(f'Error from {inbox}: {response.status} {body}')
else:
logging.debug(f'Error from {inbox}: {response.error}')
return
logging.debug(f'Pushed message to {inbox}:', message['id'])
return response