mirror of
https://github.com/matrix-org/pantalaimon.git
synced 2025-02-07 02:25:23 -05:00
pantalaimon: Add a configuration file for the daemon.
This commit is contained in:
parent
65d1401b76
commit
2987589854
2
Makefile
2
Makefile
@ -10,4 +10,4 @@ typecheck:
|
||||
mypy --ignore-missing-imports pantalaimon
|
||||
|
||||
run-local:
|
||||
python -m pantalaimon.main https://localhost:8448 --proxy http://localhost:8080 -k --log-level debug
|
||||
python -m pantalaimon.main --log-level debug --config ./contrib/pantalaimon.conf
|
||||
|
150
pantalaimon/config.py
Normal file
150
pantalaimon/config.py
Normal file
@ -0,0 +1,150 @@
|
||||
import configparser
|
||||
import os
|
||||
|
||||
from typing import Union
|
||||
|
||||
from ipaddress import ip_address, IPv4Address, IPv6Address
|
||||
from urllib.parse import urlparse, ParseResult
|
||||
|
||||
import logbook
|
||||
import attr
|
||||
|
||||
|
||||
class PanConfigParser(configparser.ConfigParser):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
default_section="Default",
|
||||
defaults={
|
||||
"SSL": "True",
|
||||
"ListenAddress": "localhost",
|
||||
"ListenPort": "8009",
|
||||
"LogLevel": "warnig",
|
||||
},
|
||||
converters={
|
||||
"address": parse_address,
|
||||
"url": parse_url,
|
||||
"loglevel": parse_log_level,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def parse_address(value):
|
||||
# type: (str) -> Union[IPv4Address, IPv6Address]
|
||||
if value == "localhost":
|
||||
return ip_address("127.0.0.1")
|
||||
|
||||
return ip_address(value)
|
||||
|
||||
|
||||
def parse_url(value):
|
||||
# type: (str) -> ParseResult
|
||||
value = urlparse(value)
|
||||
|
||||
if value.scheme not in ('http', 'https'):
|
||||
raise ValueError(f"Invalid URL scheme {value.scheme}. "
|
||||
f"Only HTTP(s) URLs are allowed")
|
||||
value.port
|
||||
|
||||
return value
|
||||
|
||||
def parse_log_level(value):
|
||||
# type: (str) -> logbook
|
||||
value = value.lower()
|
||||
|
||||
if value == "info":
|
||||
return logbook.INFO
|
||||
elif value == "warning":
|
||||
return logbook.WARNING
|
||||
elif value == "error":
|
||||
return logbook.ERROR
|
||||
elif value == "debug":
|
||||
return logbook.DEBUG
|
||||
|
||||
return logbook.WARNING
|
||||
|
||||
|
||||
class PanConfigError(Exception):
|
||||
"""Pantalaimon configuration error."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@attr.s
|
||||
class ServerConfig:
|
||||
"""Server configuration.
|
||||
|
||||
Args:
|
||||
homeserver (ParseResult): The URL of the Matrix homeserver that we want
|
||||
to forward requests to.
|
||||
listen_address (str): The local address where pantalaimon will listen
|
||||
for connections.
|
||||
listen_port (int): The port where pantalaimon will listen for
|
||||
connections.
|
||||
proxy (ParseResult):
|
||||
A proxy that the daemon should use when making connections to the
|
||||
homeserver.
|
||||
ssl (bool): Enable or disable SSL for the connection between
|
||||
pantalaimon and the homeserver.
|
||||
"""
|
||||
|
||||
homeserver = attr.ib()
|
||||
listen_address = attr.ib(type=Union[IPv4Address, IPv6Address])
|
||||
listen_port = attr.ib(type=int)
|
||||
proxy = attr.ib(type=str)
|
||||
ssl = attr.ib(type=bool, default=True)
|
||||
|
||||
|
||||
@attr.s
|
||||
class PanConfig:
|
||||
"""Pantalaimon configuration.
|
||||
|
||||
Args:
|
||||
config_path (str): The path where we should search for a configuration
|
||||
file.
|
||||
filename (str): The name of the file that we should read.
|
||||
"""
|
||||
|
||||
config_file = attr.ib()
|
||||
|
||||
log_level = attr.ib(default=None)
|
||||
servers = attr.ib(init=False, default=attr.Factory(dict))
|
||||
|
||||
def read(self):
|
||||
"""Read the configuration file.
|
||||
|
||||
Raises OSError if the file can't be read or PanConfigError if there is
|
||||
a syntax error with the config file.
|
||||
"""
|
||||
config = PanConfigParser()
|
||||
try:
|
||||
config.read(os.path.abspath(self.config_file))
|
||||
except configparser.Error as e:
|
||||
raise PanConfigError(e)
|
||||
|
||||
if self.log_level is None:
|
||||
self.log_level = config["Default"].getloglevel("LogLevel")
|
||||
|
||||
try:
|
||||
for section_name, section in config.items():
|
||||
|
||||
if section_name == "Default":
|
||||
continue
|
||||
|
||||
homeserver = section.geturl("Homeserver")
|
||||
listen_address = section.getaddress("ListenAddress")
|
||||
listen_port = section.getint("ListenPort")
|
||||
ssl = section.getboolean("SSL")
|
||||
proxy = section.geturl("Proxy")
|
||||
|
||||
server_conf = ServerConfig(
|
||||
homeserver,
|
||||
listen_address,
|
||||
listen_port,
|
||||
proxy,
|
||||
ssl
|
||||
)
|
||||
|
||||
self.servers[section_name] = server_conf
|
||||
|
||||
except ValueError as e:
|
||||
raise PanConfigError(e)
|
@ -7,16 +7,28 @@ from urllib.parse import urlparse
|
||||
|
||||
import click
|
||||
import janus
|
||||
import logbook
|
||||
|
||||
from appdirs import user_data_dir
|
||||
from appdirs import user_data_dir, user_config_dir
|
||||
from logbook import StderrHandler
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from pantalaimon.ui import GlibT
|
||||
from pantalaimon.log import logger
|
||||
from pantalaimon.daemon import ProxyDaemon
|
||||
from pantalaimon.config import PanConfig, PanConfigError, parse_log_level
|
||||
from pantalaimon.log import logger
|
||||
|
||||
|
||||
def create_dirs(data_dir, conf_dir):
|
||||
try:
|
||||
os.makedirs(data_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.makedirs(conf_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
async def init(homeserver, http_proxy, ssl, send_queue, recv_queue):
|
||||
@ -84,77 +96,55 @@ class ipaddress(click.ParamType):
|
||||
@click.command(
|
||||
help=("pantalaimon is a reverse proxy for matrix homeservers that "
|
||||
"transparently encrypts and decrypts messages for clients that "
|
||||
"connect to pantalaimon.\n\n"
|
||||
"HOMESERVER - the homeserver that the daemon should connect to.")
|
||||
"connect to pantalaimon.")
|
||||
|
||||
)
|
||||
@click.option(
|
||||
"--proxy",
|
||||
type=URL(),
|
||||
default=None,
|
||||
help="A proxy that will be used to connect to the homeserver."
|
||||
)
|
||||
@click.option(
|
||||
"-k",
|
||||
"--ssl-insecure/--no-ssl-insecure",
|
||||
default=False,
|
||||
help="Disable SSL verification for the homeserver connection."
|
||||
)
|
||||
@click.option(
|
||||
"-l",
|
||||
"--listen-address",
|
||||
type=ipaddress(),
|
||||
default=ip_address("127.0.0.1"),
|
||||
help=("The listening address for incoming client connections "
|
||||
"(default: 127.0.0.1)")
|
||||
)
|
||||
@click.option(
|
||||
"-p",
|
||||
"--listen-port",
|
||||
type=int,
|
||||
default=8009,
|
||||
help="The listening port for incoming client connections (default: 8009)"
|
||||
)
|
||||
@click.option("--log-level", type=click.Choice([
|
||||
"error",
|
||||
"warning",
|
||||
"info",
|
||||
"debug"
|
||||
]), default="error")
|
||||
@click.argument(
|
||||
"homeserver",
|
||||
type=URL(),
|
||||
)
|
||||
]), default=None)
|
||||
@click.option("-c", "--config", type=click.Path(exists=True))
|
||||
@click.pass_context
|
||||
def main(
|
||||
proxy,
|
||||
ssl_insecure,
|
||||
listen_address,
|
||||
listen_port,
|
||||
context,
|
||||
log_level,
|
||||
homeserver
|
||||
config
|
||||
):
|
||||
ssl = None if ssl_insecure is False else False
|
||||
conf_dir = user_config_dir("pantalaimon", "")
|
||||
data_dir = user_data_dir("pantalaimon", "")
|
||||
create_dirs(data_dir, conf_dir)
|
||||
|
||||
StderrHandler(level=log_level.upper()).push_application()
|
||||
config = config or os.path.join(conf_dir, "pantalaimon.conf")
|
||||
|
||||
if log_level == "info":
|
||||
logger.level = logbook.INFO
|
||||
elif log_level == "warning":
|
||||
logger.level = logbook.WARNING
|
||||
elif log_level == "error":
|
||||
logger.level = logbook.ERROR
|
||||
elif log_level == "debug":
|
||||
logger.level = logbook.DEBUG
|
||||
if log_level:
|
||||
log_level = parse_log_level(log_level)
|
||||
|
||||
pan_conf = PanConfig(config, log_level)
|
||||
|
||||
try:
|
||||
pan_conf.read()
|
||||
except (OSError, PanConfigError) as e:
|
||||
context.fail(e)
|
||||
|
||||
if not pan_conf.servers:
|
||||
context.fail("Homeserver is not configured.")
|
||||
|
||||
logger.level = pan_conf.log_level
|
||||
StderrHandler().push_application()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
pan_queue = janus.Queue(loop=loop)
|
||||
ui_queue = janus.Queue(loop=loop)
|
||||
|
||||
# TODO start the other servers as well
|
||||
server_conf = list(pan_conf.servers.values())[0]
|
||||
|
||||
proxy, app = loop.run_until_complete(init(
|
||||
homeserver,
|
||||
proxy.geturl() if proxy else None,
|
||||
ssl,
|
||||
server_conf.homeserver,
|
||||
server_conf.proxy.geturl() if server_conf.proxy else None,
|
||||
server_conf.ssl,
|
||||
pan_queue.async_q,
|
||||
ui_queue.async_q
|
||||
))
|
||||
@ -179,7 +169,11 @@ def main(
|
||||
home = os.path.expanduser("~")
|
||||
os.chdir(home)
|
||||
|
||||
web.run_app(app, host=str(listen_address), port=listen_port)
|
||||
web.run_app(
|
||||
app,
|
||||
host=str(server_conf.listen_address),
|
||||
port=server_conf.listen_port
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
x
Reference in New Issue
Block a user