sources refactor

This commit is contained in:
Dmitry Belyaev 2024-02-25 14:44:16 +03:00
parent 20ef74f32b
commit 3131f2d0a0
Signed by: b4tman
GPG Key ID: 41A00BF15EA7E5F3
3 changed files with 63 additions and 48 deletions

View File

@ -6,7 +6,7 @@ from httpx import AsyncHTTPTransport
class IPAddreses(NamedTuple):
"""набор из названия источника и IP адресов, результат одного из источников"""
"""Набор из названия источника и IP адресов, результат одного из источников"""
source_name: str
ipv4: str
@ -14,7 +14,7 @@ class IPAddreses(NamedTuple):
class BaseSourceProvider(ABC):
"""базовый класс для провайдеров источников"""
"""Базовый класс для провайдеров источников"""
_childs = {}
registred = {}
@ -35,14 +35,22 @@ class BaseSourceProvider(ABC):
self.post_init()
def post_init(self):
"""метод для переопределения пост инициализации"""
"""Метод для переопределения пост инициализации"""
...
def __str__(self):
return f"{self.__class__.__name__}: {self.name}"
def filter_ipv4(self, value: str) -> str:
"""Функция для проверки валидности IPv4 адреса, возвращает "" если адрес неправильный или пустой"""
return value if value and valid_ipv4(value) else ""
def filter_ipv6(self, value: str) -> str:
"""Функция для проверки валидности IPv6 адреса, возвращает "" если адрес неправильный или пустой"""
return value if value and valid_ipv6(value) else ""
async def fetch_all(self) -> IPAddreses:
"""метод для получения всех ip адресов сразу"""
"""Метод для получения всех IP адресов сразу"""
results = await asyncio.gather(
self.fetch_v4(), self.fetch_v6(), return_exceptions=True
)
@ -51,13 +59,23 @@ class BaseSourceProvider(ABC):
self.name, *("" if isinstance(i, Exception) else i for i in results)
)
async def fetch_v4(self) -> str:
"""Метод внешнего интерфейса для получения IPv4"""
ipv4 = await self.fetch_v4_impl()
return self.filter_ipv4(ipv4)
async def fetch_v6(self) -> str:
"""Метод внешнего интерфейса для получения IPv6"""
ipv6 = await self.fetch_v6_impl()
return self.filter_ipv6(ipv6)
def __init_subclass__(cls) -> None:
BaseSourceProvider._childs[cls.__name__] = cls
return super().__init_subclass__()
@classmethod
def validate_source_config(cls, name: str, config: dict):
"""метод валидации конфигурации для провайдера"""
"""Метод валидации конфигурации для провайдера"""
if "provider" not in config:
return False
prov_name = config["provider"]
@ -73,7 +91,7 @@ class BaseSourceProvider(ABC):
ipv4t: AsyncHTTPTransport,
ipv6t: AsyncHTTPTransport,
):
"""метод регистрации провайдера по конфигурации"""
"""Метод регистрации провайдера по конфигурации"""
if not cls.validate_source_config(name, config):
return
@ -81,18 +99,18 @@ class BaseSourceProvider(ABC):
cls.registred[name] = provider(name, config, ipv4t, ipv6t)
@abstractmethod
async def fetch_v4(self) -> str:
"""необходимый метод для реализации получения ipv4"""
async def fetch_v4_impl(self) -> Optional[str]:
"""Необходимый метод для реализации получения IPv4"""
...
@abstractmethod
async def fetch_v6(self) -> str:
"""необходимый метод для реализации получения ipv6"""
async def fetch_v6_impl(self) -> Optional[str]:
"""Необходимый метод для реализации получения IPv6"""
...
class BaseOutputProvider(ABC):
"""базовый класс для провайдеров вывода"""
"""Базовый класс для провайдеров вывода"""
_childs = {}
registred = {}
@ -109,7 +127,7 @@ class BaseOutputProvider(ABC):
self.post_init()
def post_init(self):
"""метод для переопределения пост инициализации"""
"""Метод для переопределения пост инициализации"""
...
def __init_subclass__(cls) -> None:
@ -120,14 +138,14 @@ class BaseOutputProvider(ABC):
return f"{self.__class__.__name__}: {self.name}"
def best_transport(self, addr_v4: str, addr_v6: str) -> AsyncHTTPTransport:
"""метод выбирает лучший транспорт для отправки адресов (либо ipv4 либо ipv6)"""
"""Метод выбирает лучший транспорт для отправки адресов (либо ipv4 либо ipv6)"""
if addr_v6:
return self.ipv6t
return self.ipv4t
@classmethod
def validate_source_config(cls, name: str, config: dict):
"""метод валидации конфигурации для провайдера"""
"""Метод валидации конфигурации для провайдера"""
if "provider" not in config:
return False
@ -144,24 +162,24 @@ class BaseOutputProvider(ABC):
ipv4t: AsyncHTTPTransport,
ipv6t: AsyncHTTPTransport,
):
"""метод регистрации провайдера по конфигурации"""
"""Метод регистрации провайдера по конфигурации"""
if not cls.validate_source_config(name, config):
return
provider = cls._childs[config["provider"]]
cls.registred[name] = provider(name, config, ipv4t, ipv6t)
async def set_addrs(self, source_provider: str, addr_v4: str, addr_v6: str):
"""метод внешнего интерфейса для отправки адресов"""
"""Метод внешнего интерфейса для отправки адресов"""
return await self.set_addrs_imp(source_provider, addr_v4, addr_v6)
@abstractmethod
async def set_addrs_imp(self, source_provider: str, addr_v4: str, addr_v6: str):
"""необходимый метод для реализации отправки/вывода IP аддресов"""
"""Необходимый метод для реализации отправки/вывода IP аддресов"""
...
class BaseFilterProvider(ABC):
"""базовый класс для провайдеров фильтров"""
"""Базовый класс для провайдеров фильтров"""
_childs = {}
registred = {}
@ -178,7 +196,7 @@ class BaseFilterProvider(ABC):
self.post_init()
def post_init(self):
"""метод для переопределения пост инициализации"""
"""Метод для переопределения пост инициализации"""
...
def __init_subclass__(cls) -> None:
@ -190,7 +208,7 @@ class BaseFilterProvider(ABC):
@classmethod
def validate_source_config(cls, name: str, config: dict) -> bool:
"""метод валидации конфигурации для провайдера"""
"""Метод валидации конфигурации для провайдера"""
if "provider" not in config:
return False
@ -207,7 +225,7 @@ class BaseFilterProvider(ABC):
ipv4t: AsyncHTTPTransport,
ipv6t: AsyncHTTPTransport,
):
"""метод регистрации провайдера по конфигурации"""
"""Метод регистрации провайдера по конфигурации"""
if not cls.validate_source_config(name, config):
return
@ -215,20 +233,10 @@ class BaseFilterProvider(ABC):
cls.registred[name] = provider(name, config, ipv4t, ipv6t)
async def check(self, source_provider: str, addr_v4: str, addr_v6: str) -> bool:
"""метод внешнего интерфейса для проверки адресов"""
"""Метод внешнего интерфейса для проверки адресов"""
return await self.check_imp(source_provider, addr_v4, addr_v6)
@abstractmethod
async def check_imp(self, source_provider: str, addr_v4: str, addr_v6: str) -> bool:
"""необходимый метод реализации проверки"""
"""Необходимый метод реализации проверки"""
...
def filter_ipv4(value: str) -> Optional[str]:
"""функция для проверки валидности IPv4 адреса, возвращает None если адрес неправильный или пустой"""
return value and valid_ipv4(value) and value or None
def filter_ipv6(value: str) -> Optional[str]:
"""функция для проверки валидности IPv6 адреса, возвращает None если адрес неправильный или пустой"""
return value and valid_ipv6(value) and value or None

View File

@ -6,27 +6,33 @@ from pddnsc.base import BaseSourceProvider
class DummySource(BaseSourceProvider):
"""имитация получения пустых адресов"""
"""Имитация получения пустых адресов"""
async def fetch_v4(self) -> str:
async def fetch_v4_impl(self) -> str:
result = await asyncio.sleep(self.config.get("delay", 1), result="")
return result
async def fetch_v6(self) -> str:
async def fetch_v6_impl(self) -> str:
result = await asyncio.sleep(self.config.get("delay", 1), result="")
return result
class FakeSource(BaseSourceProvider):
"""имитация получения заданных в конфигурации адресов"""
"""Имитация получения заданных в конфигурации адресов
async def fetch_v4(self) -> str:
Конфигурация:
- ipv4: строка IPv4, по умолчанию "127.0.0.1"
- ipv6: строка IPv6, по умолчанию "::1"
"""
async def fetch_v4_impl(self) -> str:
result = await asyncio.sleep(
self.config.get("delay", 1), result=self.config.get("ipv4", "127.0.0.1")
)
return result
async def fetch_v6(self) -> str:
async def fetch_v6_impl(self) -> str:
result = await asyncio.sleep(
self.config.get("delay", 1), result=self.config.get("ipv6", "::1")
)

View File

@ -1,6 +1,7 @@
from typing import Optional
import httpx
from pddnsc.base import BaseSourceProvider, filter_ipv4, filter_ipv6
from pddnsc.base import BaseSourceProvider
class GenericHttpSource(BaseSourceProvider):
@ -18,7 +19,7 @@ class GenericHttpSource(BaseSourceProvider):
self.url_v6 = self.config.get("url_v6")
self.headers = self.config.get("headers", {})
async def fetch_v4(self) -> str:
async def fetch_v4_impl(self) -> Optional[str]:
if not self.url_v4:
return None
@ -29,9 +30,9 @@ class GenericHttpSource(BaseSourceProvider):
response = await client.get(self.url_v4)
if response.is_success:
result = response.text.strip()
return filter_ipv4(result)
return result
async def fetch_v6(self) -> str:
async def fetch_v6_impl(self) -> Optional[str]:
if not self.url_v6:
return None
@ -42,7 +43,7 @@ class GenericHttpSource(BaseSourceProvider):
response = await client.get(self.url_v6)
if response.is_success:
result = response.text.strip()
return filter_ipv6(result)
return result
class GenericHttpJsonSource(BaseSourceProvider):
@ -68,7 +69,7 @@ class GenericHttpJsonSource(BaseSourceProvider):
headers = {}
self.headers = headers.update(self.config.get("headers", {}))
async def fetch_v4(self) -> str:
async def fetch_v4_impl(self) -> Optional[str]:
if not self.url_v4 or self.key_v4 is None:
return None
@ -79,9 +80,9 @@ class GenericHttpJsonSource(BaseSourceProvider):
response = await client.get(self.url_v4)
if response.is_success:
result = response.json()[self.key_v4].strip()
return filter_ipv4(result)
return result
async def fetch_v6(self) -> str:
async def fetch_v6_impl(self) -> Optional[str]:
if not self.url_v6 or self.key_v6 is None:
return None
@ -92,4 +93,4 @@ class GenericHttpJsonSource(BaseSourceProvider):
response = await client.get(self.url_v6)
if response.is_success:
result = response.json()[self.key_v6].strip()
return filter_ipv6(result)
return result