feat: add separated switch for status reporting

This commit is contained in:
2023-11-11 00:15:44 +02:00
parent fc8f6c2985
commit e4a857dad0
12 changed files with 164 additions and 99 deletions

View File

@ -21,6 +21,7 @@ import argparse
from pathlib import Path
from pwd import getpwuid
from urllib.parse import quote_plus as urlencode
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@ -128,8 +129,12 @@ class Setup(Handler):
if args.web_port is not None:
configuration.set_option("web", "port", str(args.web_port))
if (host := root.get("web", "host", fallback=None)) is not None:
configuration.set_option("status", "address", f"http://{host}:{args.web_port}")
if args.web_unix_socket is not None:
configuration.set_option("web", "unix_socket", str(args.web_unix_socket))
unix_socket = str(args.web_unix_socket)
configuration.set_option("web", "unix_socket", unix_socket)
configuration.set_option("status", "address", f"http+unix://{urlencode(unix_socket)}")
if args.generate_salt:
configuration.set_option("auth", "salt", User.generate_password(20))

View File

@ -249,6 +249,32 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
},
},
},
"status": {
"type": "dict",
"schema": {
"enabled": {
"type": "boolean",
"coerce": "boolean",
},
"address": {
"type": "string",
"empty": False,
"is_url": [],
},
"password": {
"type": "string",
"empty": False,
},
"suppress_http_log_errors": {
"type": "boolean",
"coerce": "boolean",
},
"username": {
"type": "string",
"empty": False,
},
},
},
"web": {
"type": "dict",
"schema": {

View File

@ -72,7 +72,9 @@ class HttpLogHandler(logging.Handler):
if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None:
return handler # there is already registered instance
suppress_errors = configuration.getboolean("settings", "suppress_http_log_errors", fallback=False)
suppress_errors = configuration.getboolean( # read old-style first and then fallback to new style
"settings", "suppress_http_log_errors",
fallback=configuration.getboolean("status", "suppress_http_log_errors", fallback=False))
handler = cls(repository_id, configuration, report=report, suppress_errors=suppress_errors)
root.addHandler(handler)

View File

@ -49,16 +49,19 @@ class Client:
"""
if not report:
return Client()
if not configuration.getboolean("status", "enabled", fallback=True): # global switch
return Client()
address = configuration.get("web", "address", fallback=None)
# new-style section
address = configuration.get("status", "address", fallback=None)
# old-style section
legacy_address = configuration.get("web", "address", fallback=None)
host = configuration.get("web", "host", fallback=None)
port = configuration.getint("web", "port", fallback=None)
socket = configuration.get("web", "unix_socket", fallback=None)
# basically we just check if there is something we can use for interaction with remote server
# at the moment (end of 2022) I think it would be much better idea to introduce flag like `enabled`,
# but it will totally break used experience
if address or (host and port) or socket:
if address or legacy_address or (host and port) or socket:
from ahriman.core.status.web_client import WebClient
return WebClient(repository_id, configuration)
return Client()

View File

@ -22,7 +22,7 @@ import logging
import requests
from functools import cached_property
from urllib.parse import quote_plus as urlencode
from urllib.parse import quote_plus as urlencode, urlparse
from ahriman import __version__
from ahriman.core.configuration import Configuration
@ -42,7 +42,6 @@ class WebClient(Client, SyncHttpClient):
Attributes:
address(str): address of the web service
repository_id(RepositoryId): repository unique identifier
use_unix_socket(bool): use websocket or not
"""
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
@ -53,11 +52,13 @@ class WebClient(Client, SyncHttpClient):
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
"""
suppress_errors = configuration.getboolean("settings", "suppress_http_log_errors", fallback=False)
SyncHttpClient.__init__(self, configuration, "web", suppress_errors=suppress_errors)
section, self.address = self.parse_address(configuration)
suppress_errors = configuration.getboolean( # read old-style first and then fallback to new style
"settings", "suppress_http_log_errors",
fallback=configuration.getboolean("status", "suppress_http_log_errors", fallback=False))
SyncHttpClient.__init__(self, configuration, section, suppress_errors=suppress_errors)
self.repository_id = repository_id
self.address, self.use_unix_socket = self.parse_address(configuration)
@cached_property
def session(self) -> requests.Session:
@ -67,41 +68,7 @@ class WebClient(Client, SyncHttpClient):
Returns:
request.Session: created session object
"""
return self._create_session(use_unix_socket=self.use_unix_socket)
@staticmethod
def parse_address(configuration: Configuration) -> tuple[str, bool]:
"""
parse address from configuration
Args:
configuration(Configuration): configuration instance
Returns:
tuple[str, bool]: tuple of server address and socket flag (True in case if unix socket must be used)
"""
if (unix_socket := configuration.get("web", "unix_socket", fallback=None)) is not None:
# special pseudo-protocol which is used for unix sockets
return f"http+unix://{urlencode(unix_socket)}", True
address = configuration.get("web", "address", fallback=None)
if not address:
# build address from host and port directly
host = configuration.get("web", "host")
port = configuration.getint("web", "port")
address = f"http://{host}:{port}"
return address, False
def _create_session(self, *, use_unix_socket: bool) -> requests.Session:
"""
generate new request session
Args:
use_unix_socket(bool): if set to True then unix socket session will be generated instead of native requests
Returns:
requests.Session: generated session object
"""
if use_unix_socket:
if urlparse(self.address).scheme == "http+unix":
import requests_unixsocket # type: ignore[import-untyped]
session: requests.Session = requests_unixsocket.Session()
session.headers["User-Agent"] = f"ahriman/{__version__}"
@ -113,6 +80,33 @@ class WebClient(Client, SyncHttpClient):
return session
@staticmethod
def parse_address(configuration: Configuration) -> tuple[str, str]:
"""
parse address from legacy configuration
Args:
configuration(Configuration): configuration instance
Returns:
tuple[str, str]: tuple of section name and server address
"""
# new-style section
if (address := configuration.get("status", "address", fallback=None)) is not None:
return "status", address
# legacy-style section
if (unix_socket := configuration.get("web", "unix_socket", fallback=None)) is not None:
# special pseudo-protocol which is used for unix sockets
return "web", f"http+unix://{urlencode(unix_socket)}"
address = configuration.get("web", "address", fallback=None)
if not address:
# build address from host and port directly
host = configuration.get("web", "host")
port = configuration.getint("web", "port")
address = f"http://{host}:{port}"
return "web", address
def _login(self, session: requests.Session) -> None:
"""
process login to the service