mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2025-04-20 01:26:43 +00:00
replace pathlib.Path
with blib.File
This commit is contained in:
parent
c2fd96b758
commit
fd680dfd0b
10 changed files with 63 additions and 99 deletions
|
@ -10,12 +10,11 @@ from aiohttp import web
|
||||||
from aiohttp.web import HTTPException, StaticResource
|
from aiohttp.web import HTTPException, StaticResource
|
||||||
from aputils.signer import Signer
|
from aputils.signer import Signer
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
from blib import File, HttpError, port_check
|
from blib import File, HttpError, Path, port_check
|
||||||
from bsql import Database
|
from bsql import Database
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from pathlib import Path
|
|
||||||
from threading import Event, Thread
|
from threading import Event, Thread
|
||||||
from typing import TYPE_CHECKING, Any, cast
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ class Application(web.Application):
|
||||||
return cls.DEFAULT
|
return cls.DEFAULT
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, cfgpath: Path | None, dev: bool = False):
|
def __init__(self, cfgpath: File | str | None, dev: bool = False):
|
||||||
web.Application.__init__(self,
|
web.Application.__init__(self,
|
||||||
middlewares = [
|
middlewares = [
|
||||||
handle_response_headers, # type: ignore[list-item]
|
handle_response_headers, # type: ignore[list-item]
|
||||||
|
@ -157,7 +156,7 @@ class Application(web.Application):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
static = CachedStaticResource(
|
static = CachedStaticResource(
|
||||||
"/static", Path(File.from_resource("relay", "frontend/static"))
|
"/static", File(File.from_resource("relay", "frontend/static"))
|
||||||
)
|
)
|
||||||
|
|
||||||
self.router.register_resource(static)
|
self.router.register_resource(static)
|
||||||
|
@ -241,27 +240,30 @@ class Application(web.Application):
|
||||||
|
|
||||||
|
|
||||||
class CachedStaticResource(StaticResource):
|
class CachedStaticResource(StaticResource):
|
||||||
def __init__(self, prefix: str, path: Path):
|
def __init__(self, prefix: str, path: File):
|
||||||
StaticResource.__init__(self, prefix, path)
|
StaticResource.__init__(self, prefix, path)
|
||||||
|
|
||||||
self.cache: dict[str, bytes] = {}
|
self.cache: dict[str, bytes] = {}
|
||||||
|
|
||||||
for filename in path.rglob("*"):
|
for filename in path.glob(recursive = True):
|
||||||
if filename.is_dir():
|
if filename.isdir:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
rel_path = str(filename.relative_to(path))
|
rel_path = filename.relative_to(path)
|
||||||
|
|
||||||
with filename.open("rb") as fd:
|
with filename.open("rb") as fd:
|
||||||
logging.debug("Loading static resource \"%s\"", rel_path)
|
logging.debug("Loading static resource \"%s\"", rel_path)
|
||||||
self.cache[rel_path] = fd.read()
|
self.cache[str(rel_path)] = fd.read()
|
||||||
|
|
||||||
|
|
||||||
async def _handle(self, request: web.Request) -> web.StreamResponse:
|
async def _handle(self, request: web.Request) -> web.StreamResponse:
|
||||||
rel_url = request.match_info["filename"]
|
rel_url = str(Path(request.match_info["filename"], True))
|
||||||
|
|
||||||
if Path(rel_url).anchor:
|
if rel_url.startswith("/"):
|
||||||
raise web.HTTPForbidden()
|
if len(rel_url) < 2:
|
||||||
|
raise web.HTTPForbidden()
|
||||||
|
|
||||||
|
rel_url = rel_url[1:]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return web.Response(
|
return web.Response(
|
||||||
|
|
|
@ -4,9 +4,9 @@ import click
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
|
from blib import File
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
from pathlib import Path
|
|
||||||
from typing import Concatenate, ParamSpec, TypeVar
|
from typing import Concatenate, ParamSpec, TypeVar
|
||||||
|
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
|
@ -19,24 +19,24 @@ R = TypeVar("R")
|
||||||
|
|
||||||
|
|
||||||
@click.group("cli", context_settings = {"show_default": True})
|
@click.group("cli", context_settings = {"show_default": True})
|
||||||
@click.option("--config", "-c", type = Path, help = "path to the relay config")
|
@click.option("--config", "-c", type = File, help = "path to the relay config")
|
||||||
@click.version_option(version = __version__, prog_name = "ActivityRelay")
|
@click.version_option(version = __version__, prog_name = "ActivityRelay")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx: click.Context, config: Path | None) -> None:
|
def cli(ctx: click.Context, config: File | None) -> None:
|
||||||
if IS_DOCKER:
|
if IS_DOCKER:
|
||||||
config = Path("/data/relay.yaml")
|
config = File("/data/relay.yaml")
|
||||||
|
|
||||||
# The database was named "relay.jsonld" even though it"s an sqlite file. Fix it.
|
# The database was named "relay.jsonld" even though it"s an sqlite file. Fix it.
|
||||||
db = Path("/data/relay.sqlite3")
|
db = File("/data/relay.sqlite3")
|
||||||
wrongdb = Path("/data/relay.jsonld")
|
wrongdb = File("/data/relay.jsonld")
|
||||||
|
|
||||||
if wrongdb.exists() and not db.exists():
|
if wrongdb.exists and not db.exists:
|
||||||
try:
|
try:
|
||||||
with wrongdb.open("rb") as fd:
|
with wrongdb.open("rb") as fd:
|
||||||
json.load(fd)
|
json.load(fd)
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
wrongdb.rename(db)
|
wrongdb.move(db)
|
||||||
|
|
||||||
ctx.obj = Application(config)
|
ctx.obj = Application(config)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import aputils
|
import aputils
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from pathlib import Path
|
from blib import File
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
|
||||||
from . import cli, pass_app
|
from . import cli, pass_app
|
||||||
|
@ -28,10 +28,10 @@ def check_alphanumeric(text: str) -> str:
|
||||||
def cli_convert(app: Application, old_config: str) -> None:
|
def cli_convert(app: Application, old_config: str) -> None:
|
||||||
"Convert an old config and jsonld database to the new format."
|
"Convert an old config and jsonld database to the new format."
|
||||||
|
|
||||||
old_config = str(Path(old_config).expanduser().resolve()) if old_config else str(app.config.path)
|
old_config = File(old_config).resolve() if old_config else app.config.path
|
||||||
backup = app.config.path.parent.joinpath(f"{app.config.path.stem}.backup.yaml")
|
backup = app.config.path.parent.join(f"{app.config.path.stem}.backup.yaml")
|
||||||
|
|
||||||
if str(old_config) == str(app.config.path) and not backup.exists():
|
if str(old_config) == str(app.config.path) and not backup.exists:
|
||||||
logging.info("Created backup config @ %s", backup)
|
logging.info("Created backup config @ %s", backup)
|
||||||
copyfile(app.config.path, backup)
|
copyfile(app.config.path, backup)
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,20 @@ import json
|
||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from blib import convert_to_boolean
|
from blib import File, convert_to_boolean
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
class RelayConfig(dict[str, Any]):
|
class RelayConfig(dict[str, Any]):
|
||||||
def __init__(self, path: str):
|
def __init__(self, path: File | str):
|
||||||
dict.__init__(self, {})
|
dict.__init__(self, {})
|
||||||
|
|
||||||
if self.is_docker:
|
if self.is_docker:
|
||||||
path = "/data/config.yaml"
|
path = "/data/config.yaml"
|
||||||
|
|
||||||
self._path = Path(path).expanduser().resolve()
|
self._path = File(path).resolve()
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +35,8 @@ class RelayConfig(dict[str, Any]):
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def db(self) -> Path:
|
def db(self) -> File:
|
||||||
return Path(self["db"]).expanduser().resolve()
|
return File(self["db"]).resolve()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -63,7 +62,7 @@ class RelayConfig(dict[str, Any]):
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
self.clear()
|
self.clear()
|
||||||
self.update({
|
self.update({
|
||||||
"db": str(self._path.parent.joinpath(f"{self._path.stem}.jsonld")),
|
"db": self._path.parent.join(f"{self._path.stem}.jsonld"),
|
||||||
"listen": "0.0.0.0",
|
"listen": "0.0.0.0",
|
||||||
"port": 8080,
|
"port": 8080,
|
||||||
"note": "Make a note about your instance here.",
|
"note": "Make a note about your instance here.",
|
||||||
|
@ -91,7 +90,7 @@ class RelayConfig(dict[str, Any]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._path.open("r", encoding = "UTF-8") as fd:
|
with self._path.open("r") as fd:
|
||||||
config = yaml.load(fd, **options)
|
config = yaml.load(fd, **options)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
@ -172,5 +171,5 @@ class RelayDatabase(dict[str, Any]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except json.decoder.JSONDecodeError as e:
|
except json.decoder.JSONDecodeError as e:
|
||||||
if self.config.db.stat().st_size > 0:
|
if self.config.db.size > 0:
|
||||||
raise e from None
|
raise e from None
|
||||||
|
|
|
@ -5,8 +5,8 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from blib import File
|
||||||
from dataclasses import asdict, dataclass, fields
|
from dataclasses import asdict, dataclass, fields
|
||||||
from pathlib import Path
|
|
||||||
from platformdirs import user_config_dir
|
from platformdirs import user_config_dir
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ class Config:
|
||||||
rd_prefix: str = "activityrelay"
|
rd_prefix: str = "activityrelay"
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, path: Path | None = None, load: bool = False):
|
def __init__(self, path: File | str | None = None, load: bool = False):
|
||||||
self.path: Path = Config.get_config_dir(path)
|
self.path: File = Config.get_config_dir(path)
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
if load:
|
if load:
|
||||||
|
@ -90,32 +90,31 @@ class Config:
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_config_dir(path: Path | str | None = None) -> Path:
|
def get_config_dir(path: File | str | None = None) -> File:
|
||||||
if isinstance(path, str):
|
|
||||||
path = Path(path)
|
|
||||||
|
|
||||||
if path is not None:
|
if path is not None:
|
||||||
return path.expanduser().resolve()
|
return File(path).resolve()
|
||||||
|
|
||||||
paths = (
|
paths = (
|
||||||
Path("relay.yaml").resolve(),
|
File("relay.yaml").resolve(),
|
||||||
Path(user_config_dir("activityrelay"), "relay.yaml"),
|
File(user_config_dir("activityrelay")).join("relay.yaml"),
|
||||||
Path("/etc/activityrelay/relay.yaml")
|
File("/etc/activityrelay/relay.yaml")
|
||||||
)
|
)
|
||||||
|
|
||||||
for cfgfile in paths:
|
for cfgfile in paths:
|
||||||
if cfgfile.exists():
|
if cfgfile.exists:
|
||||||
return cfgfile
|
return cfgfile
|
||||||
|
|
||||||
return paths[0]
|
return paths[0]
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sqlite_path(self) -> Path:
|
def sqlite_path(self) -> File:
|
||||||
if not os.path.isabs(self.sq_path):
|
path = File(self.sq_path)
|
||||||
return self.path.parent.joinpath(self.sq_path).resolve()
|
|
||||||
|
|
||||||
return Path(self.sq_path).expanduser().resolve()
|
if not path.isabsolute:
|
||||||
|
return self.path.parent.join(self.sq_path)
|
||||||
|
|
||||||
|
return path.resolve()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -143,7 +142,7 @@ class Config:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with self.path.open("r", encoding = "UTF-8") as fd:
|
with self.path.open("r") as fd:
|
||||||
config = yaml.load(fd, **options)
|
config = yaml.load(fd, **options)
|
||||||
|
|
||||||
if not config:
|
if not config:
|
||||||
|
@ -185,7 +184,7 @@ class Config:
|
||||||
|
|
||||||
|
|
||||||
def save(self) -> None:
|
def save(self) -> None:
|
||||||
self.path.parent.mkdir(exist_ok = True, parents = True)
|
self.path.parent.mkdir()
|
||||||
|
|
||||||
data: dict[str, Any] = {}
|
data: dict[str, Any] = {}
|
||||||
|
|
||||||
|
@ -215,7 +214,7 @@ class Config:
|
||||||
|
|
||||||
data[key] = value
|
data[key] = value
|
||||||
|
|
||||||
with self.path.open("w", encoding = "utf-8") as fd:
|
with self.path.open("w") as fd:
|
||||||
yaml.dump(data, fd, sort_keys = False)
|
yaml.dump(data, fd, sort_keys = False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
class EmptyBodyError(Exception):
|
|
||||||
pass
|
|
|
@ -10,7 +10,6 @@ from typing import TYPE_CHECKING, Any, TypeVar, overload
|
||||||
from . import __version__, logger as logging
|
from . import __version__, logger as logging
|
||||||
from .cache import Cache
|
from .cache import Cache
|
||||||
from .database.schema import Instance
|
from .database.schema import Instance
|
||||||
from .errors import EmptyBodyError
|
|
||||||
from .misc import MIMETYPES, Message, get_app
|
from .misc import MIMETYPES, Message, get_app
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -40,6 +39,10 @@ SUPPORTS_HS2019 = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EmptyBodyError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class HttpClient:
|
class HttpClient:
|
||||||
def __init__(self, limit: int = 100, timeout: int = 10):
|
def __init__(self, limit: int = 100, timeout: int = 10):
|
||||||
self.limit = limit
|
self.limit = limit
|
||||||
|
|
|
@ -3,16 +3,9 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from enum import IntEnum
|
from blib import File
|
||||||
from pathlib import Path
|
from blib import IntEnum
|
||||||
from typing import TYPE_CHECKING, Any, Protocol
|
from typing import Any, Protocol
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
try:
|
|
||||||
from typing import Self
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
from typing_extensions import Self
|
|
||||||
|
|
||||||
|
|
||||||
class LoggingMethod(Protocol):
|
class LoggingMethod(Protocol):
|
||||||
|
@ -32,35 +25,6 @@ class LogLevel(IntEnum):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse(cls: type[Self], data: Any) -> Self:
|
|
||||||
try:
|
|
||||||
data = int(data)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if isinstance(data, cls):
|
|
||||||
return data
|
|
||||||
|
|
||||||
if isinstance(data, str):
|
|
||||||
data = data.upper()
|
|
||||||
|
|
||||||
try:
|
|
||||||
return cls[data]
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
return cls(data)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise AttributeError(f"Invalid enum property for {cls.__name__}: {data}")
|
|
||||||
|
|
||||||
|
|
||||||
def get_level() -> LogLevel:
|
def get_level() -> LogLevel:
|
||||||
return LogLevel.parse(logging.root.level)
|
return LogLevel.parse(logging.root.level)
|
||||||
|
|
||||||
|
@ -84,7 +48,7 @@ critical: LoggingMethod = logging.critical
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
env_log_file: Path | None = Path(os.environ["LOG_FILE"]).expanduser().resolve()
|
env_log_file: File | None = File(os.environ["LOG_FILE"]).resolve()
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
env_log_file = None
|
env_log_file = None
|
||||||
|
|
|
@ -35,7 +35,7 @@ class Template(Environment):
|
||||||
],
|
],
|
||||||
loader = FileSystemLoader([
|
loader = FileSystemLoader([
|
||||||
File.from_resource("relay", "frontend"),
|
File.from_resource("relay", "frontend"),
|
||||||
app.config.path.parent.joinpath("template")
|
app.config.path.parent.join("template")
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,12 @@ import traceback
|
||||||
|
|
||||||
from aiohttp.client_exceptions import ClientConnectionError, ClientSSLError
|
from aiohttp.client_exceptions import ClientConnectionError, ClientSSLError
|
||||||
from asyncio.exceptions import TimeoutError as AsyncTimeoutError
|
from asyncio.exceptions import TimeoutError as AsyncTimeoutError
|
||||||
from blib import HttpError
|
from blib import File, HttpError
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from multiprocessing import Event, Process, Queue, Value
|
from multiprocessing import Event, Process, Queue, Value
|
||||||
from multiprocessing.queues import Queue as QueueType
|
from multiprocessing.queues import Queue as QueueType
|
||||||
from multiprocessing.sharedctypes import Synchronized
|
from multiprocessing.sharedctypes import Synchronized
|
||||||
from multiprocessing.synchronize import Event as EventType
|
from multiprocessing.synchronize import Event as EventType
|
||||||
from pathlib import Path
|
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ class PushWorker(Process):
|
||||||
|
|
||||||
self.queue: QueueType[PostItem] = queue
|
self.queue: QueueType[PostItem] = queue
|
||||||
self.shutdown: EventType = Event()
|
self.shutdown: EventType = Event()
|
||||||
self.path: Path = get_app().config.path
|
self.path: File = get_app().config.path
|
||||||
self.log_level: Synchronized[int] = log_level
|
self.log_level: Synchronized[int] = log_level
|
||||||
self._log_level_changed: EventType = Event()
|
self._log_level_changed: EventType = Event()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue