Files
MoviePilot/app/adapters/network/resolver.py
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

71 lines
2.1 KiB
Python

"""
系统 DNS 解析适配器。
"""
from __future__ import annotations
import asyncio
import ipaddress
import socket
from collections.abc import Iterable
from typing import Optional
def _normalize_addresses(
address_infos: Iterable[
tuple[object, object, object, object, tuple[object, ...]]
],
) -> Optional[tuple[str, ...]]:
"""
把系统 address info 全量归一化;任一异常条目都按解析失败处理。
"""
addresses: list[str] = []
for address_info in address_infos:
try:
address = ipaddress.ip_address(str(address_info[4][0]))
except (IndexError, TypeError, ValueError):
return None
addresses.append(str(address))
return tuple(addresses) or None
class SocketDnsResolver:
"""
通过系统套接字解析器实现同步与异步 DNS 查询。
"""
def resolve(self, hostname: str) -> Optional[tuple[str, ...]]:
"""
同步解析主机的全部流式连接地址。
:param hostname: 要交给系统 DNS 解析的主机名
:return: 地址文本元组;解析失败、结果为空或任一条目无效时返回 None
"""
try:
address_infos = socket.getaddrinfo(
hostname,
None,
type=socket.SOCK_STREAM,
)
except socket.gaierror:
return None
return _normalize_addresses(address_infos)
async def async_resolve(self, hostname: str) -> Optional[tuple[str, ...]]:
"""
通过当前事件循环解析地址,避免阻塞异步安全校验。
:param hostname: 要交给系统 DNS 解析的主机名
:return: 地址文本元组;解析失败、结果为空或任一条目无效时返回 None
"""
loop = asyncio.get_running_loop()
try:
address_infos = await loop.getaddrinfo(
hostname,
None,
type=socket.SOCK_STREAM,
)
except socket.gaierror:
return None
return _normalize_addresses(address_infos)