Skip to Content
SourceÚj DDNS szolgáltatások integrálása

Új DDNS szolgáltatások integrálása

A Hálózati elérés szekcióban látható beépített DDNS szolgáltatások (pl. DuckDNS) mellett lehetőség van saját vagy más nyilvános DDNS szolgáltatók beépítésére is.

Ebben a dokumentumban bemutatjuk, hogy milyen interfészt kell megvalósítani egy új DDNS szolgáltató integrálásához a StremHU Source backendjében.

Működési elv

A StremHU Source automatikusan felfedezi a DDNS szolgáltatókat az app/modules/network/ddns/providers/ könyvtárban található Python fájlok vizsgálatával. Bármely osztály, amely a BaseDDNSProvider absztrakt osztályból származik, automatikusan regisztrálásra kerül. Nincs szükség manuális regisztrációra központi helyen.

Új szolgáltató beépítése

  1. Hozz létre egy új Python fájlt az app/modules/network/ddns/providers/ könyvtárban (pl. custom_ddns.py).
  2. Készíts egy osztályt, amely a BaseDDNSProvider-ből öröklődik.
  3. Implementáld a kötelező tulajdonságokat (property) és az update metódust.

A BaseDDNSProvider interfész

Az új szolgáltatónak az alábbiakat kell megvalósítania:

from app.modules.network.ddns.base import BaseDDNSProvider from app.modules.network.ddns.schemas.internal import DDNSIpUpdate, DDNSTxtUpdate class MyCustomProvider(BaseDDNSProvider): @property def id(self) -> str: """A szolgáltató egyedi string azonosítója (pl. 'duckdns', 'myaddr')""" return "custom_id" @property def name(self) -> str: """A szolgáltató neve, ahogy a UI-on megjelenik (pl. 'Custom DNS')""" return "Custom DNS" @property def website_url(self) -> str: """A szolgáltató weboldala, ez megjelenik kliens oldalon is""" return "https://www.example.com" @property def domain_regex(self) -> str: """A szolgáltatóhoz tartozó érvényes domain validálására szolgáló reguláris kifejezés""" return r"^[a-zA-Z0-9-]+\.example\.com$" async def update(self, payload: DDNSIpUpdate | DDNSTxtUpdate) -> None: """IP cím vagy TXT rekord (ACME challenge) frissítése a szolgáltatónál""" # API hívás implementálása... pass

Az update metódus és a payloadok

Az update metódus kétféle esemény kezeléséért felelős: az IP cím frissítéséért (alap DDNS funkció), illetve a Let’s Encrypt SSL tanúsítványok kiállításához szükséges TXT rekordok beállításáért (DNS-01 ACME challenge folyamat során).

A paraméterként kapott payload típusa alapján el kell dönteni, hogy milyen akciót kell végrehajtani:

1. DDNSIpUpdate (IP frissítés)

  • payload.provider_token: A felhasználó tokenje / kulcsa az API-hoz.
  • payload.host: A frissítendő domain név.
  • payload.ip: Az új IP cím, amire a domaint be kell állítani.

2. DDNSTxtUpdate (TXT rekord / ACME Challenge)

  • payload.provider_token: A felhasználó tokenje / kulcsa az API-hoz.
  • payload.host: A domain név.
  • payload.txt: A beállítandó TXT rekord értéke.
  • payload.clear_txt: Boolean érték. Ha True, akkor törölni kell a korábbi TXT rekordot (takarítás a sikeres challenge validáció után). Ha a szolgáltatód ezt nem igényli/támogatja, elég egy return utasítással kilépni a metódusból.

Példa API híváshoz

A hálózati kérésekhez a projektben az httpx könyvtár ajánlott aszinkron (httpx.AsyncClient) módban:

import httpx from app.common.logger import logger # ... az update metódus implementációja a fenti osztályban: async def update(self, payload: DDNSIpUpdate | DDNSTxtUpdate) -> None: params = {"token": payload.provider_token, "domain": payload.host} if isinstance(payload, DDNSIpUpdate): params["ip"] = payload.ip if isinstance(payload, DDNSTxtUpdate): if payload.clear_txt: # TXT rekord törlésének logikája, ha szükséges params["clear"] = "true" else: params["txt"] = payload.txt try: async with httpx.AsyncClient(timeout=10.0) as client: # Példa kérés elküldése (szolgáltató API-jától függően POST is lehet json payload-al) response = await client.get(f"{self.website_url}/api/update", params=params) response.raise_for_status() except httpx.HTTPError as e: logger.error("MyCustomProvider hálózati hiba: %s", e) raise RuntimeError(f"MyCustomProvider hálózati hiba: {e}") from e if "ERROR" in response.text: logger.error("MyCustomProvider API hiba: %s", response.text) raise RuntimeError(f"Frissítés sikertelen: {response.text}")

A szolgáltatónak az update folyamat sikerességét Exception (célszerűen RuntimeError) dobásával (hibás esetben) vagy anélkül (sikeres esetben) kell jeleznie. Javasolt a hálózati szintű hibákat (httpx.HTTPError) és az API logikai hibáit külön kezelni. Ha a metódus lefut anélkül, hogy hibát dobna, a frissítést a szerver sikeresnek tekinti.