source/projects/activitypub_relay/src/python/relay/application.py

135 lines
3.3 KiB
Python
Raw Normal View History

2022-11-20 06:45:47 +00:00
import asyncio
2022-11-21 05:39:44 +00:00
from datetime import datetime, timedelta
2022-11-20 06:45:47 +00:00
import logging
import os
import signal
2022-11-21 05:39:44 +00:00
from uuid import uuid4
2022-11-20 06:45:47 +00:00
from aiohttp import web
from cachetools import LRUCache
from relay.config import RelayConfig
from relay.database import RelayDatabase
2022-11-21 05:39:44 +00:00
from relay.misc import (
check_open_port,
DotDict,
set_app,
)
2022-11-20 06:45:47 +00:00
from relay.views import routes
class Application(web.Application):
def __init__(self, cfgpath, middlewares=None):
web.Application.__init__(self, middlewares=middlewares)
self["starttime"] = None
self["running"] = False
self["is_docker"] = bool(os.environ.get("DOCKER_RUNNING"))
2022-11-26 22:46:42 +00:00
self["config"] = RelayConfig(cfgpath)
2022-11-20 06:45:47 +00:00
if not self["config"].load():
self["config"].save()
self["database"] = RelayDatabase(self["config"])
self["database"].load()
self["cache"] = DotDict(
{
key: Cache(maxsize=self["config"][key])
for key in self["config"].cachekeys
}
)
self["semaphore"] = asyncio.Semaphore(self["config"].push_limit)
self.set_signal_handler()
set_app(self)
@property
def cache(self):
return self["cache"]
@property
def config(self):
return self["config"]
@property
def database(self):
return self["database"]
@property
def is_docker(self):
return self["is_docker"]
@property
def semaphore(self):
return self["semaphore"]
@property
def uptime(self):
if not self["starttime"]:
return timedelta(seconds=0)
uptime = datetime.now() - self["starttime"]
return timedelta(seconds=uptime.seconds)
def set_signal_handler(self):
signal.signal(signal.SIGHUP, self.stop)
signal.signal(signal.SIGINT, self.stop)
signal.signal(signal.SIGQUIT, self.stop)
signal.signal(signal.SIGTERM, self.stop)
def run(self):
if not check_open_port(self.config.listen, self.config.port):
return logging.error(
f"A server is already running on port {self.config.port}"
)
for route in routes:
self.router.add_route(*route)
logging.info(
f"Starting webserver at {self.config.host} ({self.config.listen}:{self.config.port})"
)
asyncio.run(self.handle_run())
2022-11-27 06:08:25 +00:00
# Save off config before exit
self.config.save()
self.database.save()
2022-11-20 06:45:47 +00:00
def stop(self, *_):
self["running"] = False
async def handle_run(self):
self["running"] = True
runner = web.AppRunner(
self, access_log_format='%{X-Forwarded-For}i "%r" %s %b "%{User-Agent}i"'
)
await runner.setup()
site = web.TCPSite(
runner, host=self.config.listen, port=self.config.port, reuse_address=True
)
await site.start()
self["starttime"] = datetime.now()
while self["running"]:
await asyncio.sleep(0.25)
await site.stop()
self["starttime"] = None
self["running"] = False
class Cache(LRUCache):
def set_maxsize(self, value):
self.__maxsize = int(value)
@web.middleware
async def request_id_middleware(request, handler):
request.id = uuid4()
return await handler(request)