sedi-relay/relay/config.py

217 lines
4 KiB
Python
Raw Permalink Normal View History

2022-11-27 00:59:20 +00:00
import os
2022-12-13 13:27:09 +00:00
import sys
2022-05-06 07:04:51 +00:00
import yaml
2022-11-27 00:59:20 +00:00
from functools import cached_property
2022-05-06 07:04:51 +00:00
from pathlib import Path
from platform import system
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
from .misc import AppBase, DotDict
DEFAULTS = {
'general_listen': '0.0.0.0',
'general_port': 8080,
'general_host': 'relay.example.com',
'database_type': 'sqlite',
'database_min_connections': 0,
'database_max_connections': 10,
'sqlite_database': Path('relay.sqlite3'),
2022-12-13 13:27:09 +00:00
'postgres_database': 'activityrelay',
'postgres_hostname': None,
'postgres_port': None,
'postgres_username': None,
'postgres_password': None,
'mysql_database': 'activityrelay',
'mysql_hostname': None,
'mysql_port': None,
'mysql_username': None,
'mysql_password': None
}
CATEGORY_NAMES = [
'general',
'database',
'sqlite',
2022-12-13 13:27:09 +00:00
'postgres',
'mysql'
2022-05-06 07:04:51 +00:00
]
2022-12-13 13:27:09 +00:00
def get_config_dir():
cwd = Path.cwd().joinpath('config.yaml')
plat = system()
if cwd.exists():
return cwd
elif plat == 'Linux':
cfgpath = Path('~/.config/activityrelay/config.yaml').expanduser()
2022-11-10 17:38:08 +00:00
2022-12-13 13:27:09 +00:00
if cfgpath.exists():
return cfgpath
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
etcpath = Path('/etc/activityrelay/config.yaml')
2022-05-06 07:04:51 +00:00
if etcpath.exists() and os.getuid() == etcpath.stat().st_uid:
return etcpath
elif plat == 'Windows':
cfgpath = Path('~/AppData/Roaming/activityrelay/config.yaml').expanduer()
if cfgpath.exists():
2022-12-13 13:27:09 +00:00
return cfgpath
2022-05-06 07:04:51 +00:00
elif plat == 'Darwin':
cfgpath = Path('~/Library/Application Support/activityaelay/config.yaml')
return cwd
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
class Config(AppBase, dict):
def __init__(self, path=None):
DotDict.__init__(self, DEFAULTS)
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
if self.is_docker:
path = Path('/data/config.yaml')
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
elif not path:
path = get_config_dir()
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
else:
path = Path(path).expanduser()
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
self._path = path
self.load()
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
def __setitem__(self, key, value):
if key in {'database', 'hostname', 'port', 'username', 'password'}:
key = f'{self.dbtype}_{key}'
2022-12-13 13:27:09 +00:00
if (self.is_docker and key in {'general_host', 'general_port'}) or value == '__DEFAULT__':
value = DEFAULTS[key]
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
elif key in {'general_port', 'database_min_connections', 'database_max_connections'}:
value = int(value)
2022-05-06 07:04:51 +00:00
elif key == 'sqlite_database':
if not isinstance(value, Path):
value = Path(value)
2022-12-13 13:27:09 +00:00
dict.__setitem__(self, key, value)
2022-05-06 07:04:51 +00:00
@property
2022-12-13 13:27:09 +00:00
def dbconfig(self):
config = {
'type': self['database_type'],
'min_conn': self['database_min_connections'],
'max_conn': self['database_max_connections']
}
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
if self.dbtype == 'sqlite':
if not self['sqlite_database'].is_absolute():
config['database'] = self.path.with_name(str(self['sqlite_database'])).resolve()
else:
config['database'] = self['sqlite_database'].resolve()
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
else:
for key, value in self.items():
cat, name = key.split('_', 1)
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
if self.dbtype == cat:
config[name] = value
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
return config
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@cached_property
def is_docker(self):
return bool(os.getenv('DOCKER_RUNNING'))
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@property
def path(self):
return self._path
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
## General config
@property
def host(self):
return self['general_host']
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@property
def listen(self):
return self['general_listen']
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@property
def port(self):
return self['general_port']
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
## Database config
@property
def dbtype(self):
return self['database_type']
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
## AP URLs
@property
def actor(self):
return f'https://{self.host}/actor'
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@property
def inbox(self):
return f'https://{self.host}/inbox'
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
@property
def keyid(self):
return f'{self.actor}#main-key'
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
def reset(self):
self.clear()
self.update(DEFAULTS)
2022-05-06 07:04:51 +00:00
def load(self):
options = {}
try:
options['Loader'] = yaml.FullLoader
except AttributeError:
pass
try:
with open(self.path) as fd:
config = yaml.load(fd, **options)
except FileNotFoundError:
return False
2022-12-13 13:27:09 +00:00
for key, value in DEFAULTS.items():
cat, name = key.split('_', 1)
self[key] = config.get(cat, {}).get(name, DEFAULTS[key])
2022-05-06 07:04:51 +00:00
2022-11-20 11:14:37 +00:00
2022-12-13 13:27:09 +00:00
def save(self):
config = {key: {} for key in CATEGORY_NAMES}
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
for key, value in self.items():
cat, name = key.split('_', 1)
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
if isinstance(value, Path):
value = str(value)
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
config[cat][name] = value
2022-05-06 07:04:51 +00:00
2022-12-13 13:27:09 +00:00
with open(self.path, 'w') as fd:
2022-05-06 07:04:51 +00:00
yaml.dump(config, fd, sort_keys=False)