Files
cool-domain/cool_domain/factory.py
T
2026-06-15 14:22:40 +02:00

81 lines
2.5 KiB
Python

import logging
import random
import shutil
import subprocess
import typing
if typing.TYPE_CHECKING:
from .tld_list import TLDList
from .word_list import WordList
class FactoryError(Exception):
pass
class Factory:
__slots__ = ["__found", "__tld_list", "__word_list", "logger", "__words"]
def __init__(self, tld_list: TLDList, word_list: WordList, words: int) -> None:
self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)
self.__tld_list = tld_list
self.__word_list = word_list
self.__words = words
self.__found: set[str] = set()
def __iter__(self) -> typing.Self:
return self
def __next__(self) -> str:
return self.random_domain()
@property
def __tld_list_shuffled(self) -> typing.Iterable[str]:
if self.__tld_list.tlds is None:
msg = "TLD list is not loaded"
raise FactoryError(msg)
return random.sample(self.__tld_list.tlds, len(self.__tld_list.tlds))
def __is_domain_available(self, domain: str) -> bool:
dig_bin = shutil.which("dig")
if dig_bin is None:
msg = "dig is not installed"
raise FactoryError(msg)
try:
output = subprocess.check_output([dig_bin, domain, "NS", "+short"]) # noqa: S603
return len(output) == 0
except subprocess.CalledProcessError:
return False
def random_domain(self) -> str:
k = 10000
while (k := k - 1) > 0 and (domain := self.__random_domain()) is None:
pass
if domain is None:
raise StopIteration
return domain
def random_available_domain(self) -> str:
k = 10000
while (k := k - 1) > 0 and not self.__is_domain_available(
domain := self.random_domain()
):
pass
if k <= 0:
raise StopIteration
return domain
def __random_domain(self) -> str | None:
word = self.__random_word()
for tld in self.__tld_list_shuffled:
tld_escaped = tld.replace(".", "")
if word.endswith(tld_escaped) and len(word) > len(tld_escaped):
domain = word[: -len(tld_escaped)] + "." + tld
if domain not in self.__found:
self.__found.add(domain)
return domain
return None
def __random_word(self) -> str:
return "-".join(random.sample(self.__word_list.words, self.__words))