fix: 포트 충돌 회피 — note_bridge 8098, intent_service 8099
Jellyfin(8096), OrbStack(8097) 포트 충돌으로 변경. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import inspect
|
||||
import typing
|
||||
from abc import ABCMeta
|
||||
from base64 import b64encode
|
||||
from typing import Any
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
from ...util import parse_url
|
||||
from .protocols import BaseResolver, ProtocolResolver
|
||||
|
||||
|
||||
class ResolverFactory(metaclass=ABCMeta):
|
||||
@staticmethod
|
||||
def new(
|
||||
protocol: ProtocolResolver,
|
||||
specifier: str | None = None,
|
||||
implementation: str | None = None,
|
||||
**kwargs: Any,
|
||||
) -> BaseResolver:
|
||||
package_name: str = __name__.split(".")[0]
|
||||
|
||||
module_expr = f".{protocol.value.replace('-', '_')}"
|
||||
|
||||
if implementation:
|
||||
module_expr += f"._{implementation.replace('-', '_').lower()}"
|
||||
|
||||
spe_msg = " " if specifier is None else f' (w/ specifier "{specifier}") '
|
||||
|
||||
try:
|
||||
resolver_module = importlib.import_module(
|
||||
module_expr, f"{package_name}.contrib.resolver"
|
||||
)
|
||||
except ImportError as e:
|
||||
raise NotImplementedError(
|
||||
f"{protocol}{spe_msg}cannot be loaded. Tried to import '{module_expr}'. Did you specify a non-existent implementation?"
|
||||
) from e
|
||||
|
||||
implementations: list[tuple[str, type[BaseResolver]]] = inspect.getmembers(
|
||||
resolver_module,
|
||||
lambda e: isinstance(e, type)
|
||||
and issubclass(e, BaseResolver)
|
||||
and (
|
||||
(specifier is None and e.specifier is None) or specifier == e.specifier
|
||||
),
|
||||
)
|
||||
|
||||
if not implementations:
|
||||
raise NotImplementedError(
|
||||
f"{protocol}{spe_msg}cannot be loaded. "
|
||||
"No compatible implementation available. "
|
||||
"Make sure your implementation inherit from BaseResolver."
|
||||
)
|
||||
|
||||
implementation_target: type[BaseResolver] = implementations.pop()[1]
|
||||
|
||||
return implementation_target(**kwargs)
|
||||
|
||||
|
||||
class ResolverDescription:
|
||||
"""Describe how a BaseResolver must be instantiated."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
protocol: ProtocolResolver,
|
||||
specifier: str | None = None,
|
||||
implementation: str | None = None,
|
||||
server: str | None = None,
|
||||
port: int | None = None,
|
||||
*host_patterns: str,
|
||||
**kwargs: typing.Any,
|
||||
) -> None:
|
||||
self.protocol = protocol
|
||||
self.specifier = specifier
|
||||
self.implementation = implementation
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.host_patterns = host_patterns
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __setitem__(self, key: str, value: typing.Any) -> None:
|
||||
self.kwargs[key] = value
|
||||
|
||||
def __contains__(self, item: str) -> bool:
|
||||
return item in self.kwargs
|
||||
|
||||
def new(self) -> BaseResolver:
|
||||
kwargs = {**self.kwargs}
|
||||
|
||||
if self.server:
|
||||
kwargs["server"] = self.server
|
||||
if self.port:
|
||||
kwargs["port"] = self.port
|
||||
if self.host_patterns:
|
||||
kwargs["patterns"] = self.host_patterns
|
||||
|
||||
return ResolverFactory.new(
|
||||
self.protocol,
|
||||
self.specifier,
|
||||
self.implementation,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_url(url: str) -> ResolverDescription:
|
||||
parsed_url = parse_url(url)
|
||||
|
||||
schema = parsed_url.scheme
|
||||
|
||||
if schema is None:
|
||||
raise ValueError("Given DNS url is missing a protocol")
|
||||
|
||||
specifier = None
|
||||
implementation = None
|
||||
|
||||
if "+" in schema:
|
||||
schema, specifier = tuple(schema.lower().split("+", 1))
|
||||
|
||||
protocol = ProtocolResolver(schema)
|
||||
kwargs: dict[str, typing.Any] = {}
|
||||
|
||||
if parsed_url.path:
|
||||
kwargs["path"] = parsed_url.path
|
||||
|
||||
if parsed_url.auth:
|
||||
kwargs["headers"] = dict()
|
||||
if ":" in parsed_url.auth:
|
||||
username, password = parsed_url.auth.split(":")
|
||||
|
||||
username = username.strip("'\"")
|
||||
password = password.strip("'\"")
|
||||
|
||||
kwargs["headers"]["Authorization"] = (
|
||||
f"Basic {b64encode(f'{username}:{password}'.encode()).decode()}"
|
||||
)
|
||||
else:
|
||||
kwargs["headers"]["Authorization"] = f"Bearer {parsed_url.auth}"
|
||||
|
||||
if parsed_url.query:
|
||||
parameters = parse_qs(parsed_url.query)
|
||||
|
||||
for parameter in parameters:
|
||||
if not parameters[parameter]:
|
||||
continue
|
||||
|
||||
parameter_insensible = parameter.lower()
|
||||
|
||||
if (
|
||||
isinstance(parameters[parameter], list)
|
||||
and len(parameters[parameter]) > 1
|
||||
):
|
||||
if parameter == "implementation":
|
||||
raise ValueError("Only one implementation can be passed to URL")
|
||||
|
||||
values = []
|
||||
|
||||
for e in parameters[parameter]:
|
||||
if "," in e:
|
||||
values.extend(e.split(","))
|
||||
else:
|
||||
values.append(e)
|
||||
|
||||
if parameter_insensible in kwargs:
|
||||
if isinstance(kwargs[parameter_insensible], list):
|
||||
kwargs[parameter_insensible].extend(values)
|
||||
else:
|
||||
values.append(kwargs[parameter_insensible])
|
||||
kwargs[parameter_insensible] = values
|
||||
continue
|
||||
|
||||
kwargs[parameter_insensible] = values
|
||||
continue
|
||||
|
||||
value: str = parameters[parameter][0].lower().strip(" ")
|
||||
|
||||
if parameter == "implementation":
|
||||
implementation = value
|
||||
continue
|
||||
|
||||
if "," in value:
|
||||
list_of_values = value.split(",")
|
||||
|
||||
if parameter_insensible in kwargs:
|
||||
if isinstance(kwargs[parameter_insensible], list):
|
||||
kwargs[parameter_insensible].extend(list_of_values)
|
||||
else:
|
||||
list_of_values.append(kwargs[parameter_insensible])
|
||||
continue
|
||||
|
||||
kwargs[parameter_insensible] = list_of_values
|
||||
continue
|
||||
|
||||
value_converted: bool | int | float | None = None
|
||||
|
||||
if value in ["false", "true"]:
|
||||
value_converted = True if value == "true" else False
|
||||
elif value.isdigit():
|
||||
value_converted = int(value)
|
||||
elif (
|
||||
value.count(".") == 1
|
||||
and value.index(".") > 0
|
||||
and value.replace(".", "").isdigit()
|
||||
):
|
||||
value_converted = float(value)
|
||||
|
||||
kwargs[parameter_insensible] = (
|
||||
value if value_converted is None else value_converted
|
||||
)
|
||||
|
||||
host_patterns: list[str] = []
|
||||
|
||||
if "hosts" in kwargs:
|
||||
host_patterns = (
|
||||
kwargs["hosts"].split(",")
|
||||
if isinstance(kwargs["hosts"], str)
|
||||
else kwargs["hosts"]
|
||||
)
|
||||
del kwargs["hosts"]
|
||||
|
||||
return ResolverDescription(
|
||||
protocol,
|
||||
specifier,
|
||||
implementation,
|
||||
parsed_url.host,
|
||||
parsed_url.port,
|
||||
*host_patterns,
|
||||
**kwargs,
|
||||
)
|
||||
Reference in New Issue
Block a user