Add generic endpoint list parsing
This commit is contained in:
@@ -1,9 +1,84 @@
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
from .adapters import Endpoint
|
||||
from .normalizer import normalize_hostname, normalize_ipv4
|
||||
|
||||
|
||||
def parse_endpoint_list(
|
||||
plugin: str,
|
||||
value: str,
|
||||
default_port: int,
|
||||
) -> tuple[Endpoint, ...]:
|
||||
if not 1 <= default_port <= 65535:
|
||||
raise RuntimeError(
|
||||
"Endpoint default port must be between 1 and 65535"
|
||||
)
|
||||
|
||||
raw_addresses = value.split(",")
|
||||
if any(not item.strip() for item in raw_addresses):
|
||||
raise RuntimeError(
|
||||
f"{plugin.upper()} endpoint list contains an empty address"
|
||||
)
|
||||
|
||||
endpoints: list[Endpoint] = []
|
||||
identities: set[str] = set()
|
||||
|
||||
for raw_address in raw_addresses:
|
||||
address = raw_address.strip().rstrip("/")
|
||||
|
||||
if "://" in address:
|
||||
raise RuntimeError(
|
||||
f"{plugin.upper()} endpoint {raw_address!r} must not "
|
||||
"include a URL scheme"
|
||||
)
|
||||
|
||||
if any(character.isspace() for character in address):
|
||||
raise RuntimeError(
|
||||
f"{plugin.upper()} endpoint {raw_address!r} "
|
||||
"contains whitespace"
|
||||
)
|
||||
|
||||
parsed = urlsplit(f"//{address}")
|
||||
if (
|
||||
not parsed.hostname
|
||||
or parsed.username
|
||||
or parsed.password
|
||||
or parsed.path
|
||||
or parsed.query
|
||||
or parsed.fragment
|
||||
):
|
||||
raise RuntimeError(
|
||||
f"Invalid {plugin.upper()} endpoint address: "
|
||||
f"{raw_address!r}"
|
||||
)
|
||||
|
||||
try:
|
||||
port = parsed.port or default_port
|
||||
except ValueError as exc:
|
||||
raise RuntimeError(
|
||||
f"Invalid {plugin.upper()} endpoint port: "
|
||||
f"{raw_address!r}"
|
||||
) from exc
|
||||
|
||||
host = parsed.hostname.lower()
|
||||
normalized_address = (
|
||||
f"[{host}]:{port}" if ":" in host else f"{host}:{port}"
|
||||
)
|
||||
endpoint = Endpoint(plugin, normalized_address)
|
||||
|
||||
if endpoint.identity in identities:
|
||||
raise RuntimeError(
|
||||
f"Duplicate {plugin.upper()} endpoint: {endpoint.address}"
|
||||
)
|
||||
|
||||
identities.add(endpoint.identity)
|
||||
endpoints.append(endpoint)
|
||||
|
||||
return tuple(endpoints)
|
||||
|
||||
|
||||
def env_bool(name: str, default: bool) -> bool:
|
||||
value = os.getenv(name)
|
||||
if value is None:
|
||||
|
||||
Reference in New Issue
Block a user