|
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
from faker import Faker
|
|
|
|
from devplacepy.config import WORKSPACE_TUNNEL_DOMAIN
|
|
from devplacepy.database import get_setting, get_table
|
|
|
|
LABEL = re.compile(r"^[a-z0-9]([a-z0-9-]{0,48}[a-z0-9])?$")
|
|
MAX_ATTEMPTS = 12
|
|
|
|
_faker = Faker()
|
|
|
|
|
|
def domain() -> str:
|
|
return get_setting("workspace_tunnel_domain", WORKSPACE_TUNNEL_DOMAIN).strip(".")
|
|
|
|
|
|
def host_pattern() -> str:
|
|
return get_setting("workspace_hostname_pattern", "{name}.{domain}")
|
|
|
|
|
|
def port_pattern() -> str:
|
|
return get_setting("workspace_port_hostname_pattern", "{port}-{name}.{domain}")
|
|
|
|
|
|
def is_valid_label(value: str) -> bool:
|
|
return bool(value) and bool(LABEL.match(value))
|
|
|
|
|
|
def _slugify(value: str) -> str:
|
|
cleaned = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
|
|
return cleaned[:49].strip("-")
|
|
|
|
|
|
def candidate(index: int) -> str:
|
|
words = [_slugify(_faker.word()) for _ in range(2)]
|
|
words = [word for word in words if word]
|
|
if not words:
|
|
words = ["workspace"]
|
|
name = "-".join(words)
|
|
if index:
|
|
name = f"{name}-{index}"
|
|
return name if is_valid_label(name) else "workspace"
|
|
|
|
|
|
def taken(name: str) -> bool:
|
|
return bool(get_table("instances").find_one(tunnel_name=name, deleted_at=None))
|
|
|
|
|
|
def generate(fallback_uid: str = "") -> str:
|
|
for attempt in range(MAX_ATTEMPTS):
|
|
name = candidate(attempt)
|
|
if not taken(name):
|
|
return name
|
|
tail = (fallback_uid or "").replace("-", "")[-8:]
|
|
return f"workspace-{tail}" if tail else "workspace"
|
|
|
|
|
|
def hostname_for(name: str, port: int = 0) -> str:
|
|
if not name:
|
|
return ""
|
|
pattern = port_pattern() if port else host_pattern()
|
|
return pattern.format(name=name, domain=domain(), port=port)
|
|
|
|
|
|
def proxy_uri_template(name: str) -> str:
|
|
if not name:
|
|
return ""
|
|
return "https://" + port_pattern().format(
|
|
name=name, domain=domain(), port="{{port}}"
|
|
)
|
|
|
|
|
|
def is_tunnel_host(host: str) -> bool:
|
|
if not host:
|
|
return False
|
|
bare = host.split(":", 1)[0].lower().rstrip(".")
|
|
suffix = "." + domain().lower()
|
|
return bare.endswith(suffix)
|