refactor: изменение классов OutboundSpec, OutboundFactory и Outbound для использования класса Target

This commit is contained in:
2026-07-04 03:19:37 +03:00
parent d0c3d5d50e
commit c637f944f9
+20 -35
View File
@@ -11,6 +11,7 @@ from urllib.parse import parse_qs, quote, unquote, urlencode, urlparse
from .outbound_fields import OUTBOUND_FIELDS from .outbound_fields import OUTBOUND_FIELDS
if TYPE_CHECKING: if TYPE_CHECKING:
from .target import Target, TargetStorage
from .xray_config import XrayConfig from .xray_config import XrayConfig
from .xray_manager_config import XrayManagerConfig from .xray_manager_config import XrayManagerConfig
@@ -18,7 +19,7 @@ if TYPE_CHECKING:
@dataclass(frozen=True) @dataclass(frozen=True)
class OutboundSpec: class OutboundSpec:
protocol: str protocol: str
target: str target_id: str
O = TypeVar("O", bound="Outbound") O = TypeVar("O", bound="Outbound")
@@ -50,22 +51,19 @@ class OutboundFactory:
return list(cls._registry) return list(cls._registry)
@classmethod @classmethod
def from_link( def from_link(cls, target_storage: TargetStorage, link: str) -> Outbound:
cls, xray_manager_config: XrayManagerConfig, link: str
) -> Outbound:
scheme = link.split("://", 1)[0] scheme = link.split("://", 1)[0]
if scheme not in cls._scheme_registry: if scheme not in cls._scheme_registry:
raise ValueError(f"Unsupported link scheme: {scheme}") raise ValueError(f"Unsupported link scheme: {scheme}")
outbound_cls = cls._scheme_registry[scheme] outbound_cls = cls._scheme_registry[scheme]
targets = xray_manager_config.targets return outbound_cls.from_link(target_storage, link)
return outbound_cls.from_link(targets, link)
@classmethod @classmethod
def from_inbound( def from_inbound(
cls, cls,
xray_manager_config: XrayManagerConfig, target_storage: TargetStorage,
host: str, host: str,
client: dict, client: dict,
inbound: dict, inbound: dict,
@@ -76,9 +74,8 @@ class OutboundFactory:
raise ValueError(f"Unsupported protocol: {protocol}") raise ValueError(f"Unsupported protocol: {protocol}")
outbound_cls = cls._registry[protocol] outbound_cls = cls._registry[protocol]
targets = xray_manager_config.targets
username, outbound = outbound_cls.from_inbound( username, outbound = outbound_cls.from_inbound(
targets, host, client, inbound target_storage, host, client, inbound
) )
return username, outbound return username, outbound
@@ -86,26 +83,18 @@ class OutboundFactory:
def from_spec( def from_spec(
cls, cls,
xray_config: XrayConfig, xray_config: XrayConfig,
xray_manager_config: XrayManagerConfig, target_storage: TargetStorage,
spec: OutboundSpec, spec: OutboundSpec,
) -> Outbound: ) -> Outbound:
if spec.protocol not in cls._registry: if spec.protocol not in cls._registry:
raise ValueError(f"Unsupported protocol: {spec.protocol}") raise ValueError(f"Unsupported protocol: {spec.protocol}")
if spec.target not in xray_manager_config.get_targets_list(): target = target_storage.load_by_id(spec.target_id)
raise ValueError(f"Target {spec.target} not found")
inbound = xray_config.find_managed_inbound_by_protocol(spec.protocol) inbound = xray_config.find_managed_inbound_by_protocol(spec.protocol)
outbound_cls = cls._registry[spec.protocol] outbound_cls = cls._registry[spec.protocol]
targets = xray_manager_config.targets return outbound_cls.from_scratch(target, xray_config.host, inbound)
target_pretty_name = targets.get(spec.target, {}).get(
"pretty_name", spec.target
)
return outbound_cls.from_scratch(
spec.target, target_pretty_name, xray_config.host, inbound
)
class Outbound(ABC): class Outbound(ABC):
@@ -115,14 +104,14 @@ class Outbound(ABC):
@classmethod @classmethod
@abstractmethod @abstractmethod
def from_link( def from_link(
cls, targets: dict[str, dict[str, str]], link: str cls, target_storage: TargetStorage, link: str
) -> Outbound: ... ) -> Outbound: ...
@classmethod @classmethod
@abstractmethod @abstractmethod
def from_inbound( def from_inbound(
cls, cls,
targets: dict[str, dict[str, str]], target_storage: TargetStorage,
host: str, host: str,
client: dict, client: dict,
inbound: dict, inbound: dict,
@@ -131,7 +120,7 @@ class Outbound(ABC):
@classmethod @classmethod
@abstractmethod @abstractmethod
def from_scratch( def from_scratch(
cls, target: str, target_pretty_name: str, host: str, inbound: dict cls, target: Target, host: str, inbound: dict
) -> Outbound: ... ) -> Outbound: ...
@abstractmethod @abstractmethod
@@ -184,7 +173,7 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
@classmethod @classmethod
def from_link( def from_link(
cls, targets: dict[str, dict[str, str]], link: str cls, target_storage: TargetStorage, link: str
) -> ShadowsocksOutbound: ) -> ShadowsocksOutbound:
import base64 import base64
@@ -198,15 +187,12 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
method, server_password, client_password = prefix_str.split(":") method, server_password, client_password = prefix_str.split(":")
target_pretty_name = unquote(quoted_target_pretty_name) target_pretty_name = unquote(quoted_target_pretty_name)
target = cls.find_target_by_pretty_name(targets, target_pretty_name) target = target_storage.load_by_pretty(target_pretty_name)
if target is None:
target = "unknown"
return cls( return cls(
host=host, host=host,
port=port, port=port,
target=target, target=target,
target_pretty_name=target_pretty_name,
method=method, method=method,
server_password=server_password, server_password=server_password,
client_password=client_password, client_password=client_password,
@@ -215,7 +201,7 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
@classmethod @classmethod
def from_inbound( def from_inbound(
cls, cls,
targets: dict[str, dict[str, str]], target_storage: TargetStorage,
host: str, host: str,
client: dict, client: dict,
inbound: dict, inbound: dict,
@@ -225,15 +211,15 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
server_password = inbound["settings"]["password"] server_password = inbound["settings"]["password"]
client_password = client["password"] client_password = client["password"]
email = client["email"] email = client["email"]
username, target = cls.split_client_email(email)
target_pretty_name = targets.get(target, {}).get("pretty_name", target) username, target_id = cls.split_client_email(email)
target = target_storage.load_by_id(target_id)
outbound = cls( outbound = cls(
host=host, host=host,
port=port, port=port,
target=target, target=target,
target_pretty_name=target_pretty_name,
method=method, method=method,
server_password=server_password, server_password=server_password,
client_password=client_password, client_password=client_password,
@@ -242,7 +228,7 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
@classmethod @classmethod
def from_scratch( def from_scratch(
cls, target: str, target_pretty_name: str, host: str, inbound: dict cls, target: Target, host: str, inbound: dict
) -> ShadowsocksOutbound: ) -> ShadowsocksOutbound:
port = inbound["port"] port = inbound["port"]
method = inbound["settings"]["method"] method = inbound["settings"]["method"]
@@ -253,7 +239,6 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
host=host, host=host,
port=port, port=port,
target=target, target=target,
target_pretty_name=target_pretty_name,
method=method, method=method,
server_password=server_password, server_password=server_password,
client_password=client_password, client_password=client_password,
@@ -264,7 +249,7 @@ class ShadowsocksOutbound(_ShadowsocksFields, Outbound):
prefix = f"{self.method}:{self.server_password}:{self.client_password}" prefix = f"{self.method}:{self.server_password}:{self.client_password}"
prefix_b64 = base64.urlsafe_b64encode(prefix.encode()).decode() prefix_b64 = base64.urlsafe_b64encode(prefix.encode()).decode()
tag = quote(self.target_pretty_name) tag = quote(self.target.pretty)
link = f"ss://{prefix_b64}@{self.host}:{self.port}#{tag}" link = f"ss://{prefix_b64}@{self.host}:{self.port}#{tag}"
return link return link