All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m21s
- Replace hardcoded POSTGRES_PASSWORD, ADMIN_TOKEN, and L1 host IP with env var references in docker-compose.yml - Remove default password fallback from database.py and app/config.py - Update .env.example with required POSTGRES_PASSWORD, ADMIN_TOKEN, L1_HOST - Update README to mark DATABASE_URL as required Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
"""
|
|
L1 Server Configuration.
|
|
|
|
Environment-based configuration with sensible defaults.
|
|
All config should go through this module - no direct os.environ calls elsewhere.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from dataclasses import dataclass, field
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class Settings:
|
|
"""Application settings loaded from environment."""
|
|
|
|
# Server
|
|
host: str = field(default_factory=lambda: os.environ.get("HOST", "0.0.0.0"))
|
|
port: int = field(default_factory=lambda: int(os.environ.get("PORT", "8000")))
|
|
debug: bool = field(default_factory=lambda: os.environ.get("DEBUG", "").lower() == "true")
|
|
|
|
# Cache (use /data/cache in Docker via env var, ~/.artdag/cache locally)
|
|
cache_dir: Path = field(
|
|
default_factory=lambda: Path(os.environ.get("CACHE_DIR", str(Path.home() / ".artdag" / "cache")))
|
|
)
|
|
|
|
# Redis
|
|
redis_url: str = field(
|
|
default_factory=lambda: os.environ.get("REDIS_URL", "redis://localhost:6379/5")
|
|
)
|
|
|
|
# Database
|
|
database_url: str = field(
|
|
default_factory=lambda: os.environ.get("DATABASE_URL", "")
|
|
)
|
|
|
|
# IPFS
|
|
ipfs_api: str = field(
|
|
default_factory=lambda: os.environ.get("IPFS_API", "/dns/localhost/tcp/5001")
|
|
)
|
|
ipfs_gateway_url: str = field(
|
|
default_factory=lambda: os.environ.get("IPFS_GATEWAY_URL", "https://ipfs.io/ipfs")
|
|
)
|
|
|
|
# L2 Server
|
|
l2_server: Optional[str] = field(
|
|
default_factory=lambda: os.environ.get("L2_SERVER")
|
|
)
|
|
l2_domain: Optional[str] = field(
|
|
default_factory=lambda: os.environ.get("L2_DOMAIN")
|
|
)
|
|
|
|
# GPU/Streaming settings
|
|
streaming_gpu_persist: bool = field(
|
|
default_factory=lambda: os.environ.get("STREAMING_GPU_PERSIST", "0") == "1"
|
|
)
|
|
ipfs_gateways: str = field(
|
|
default_factory=lambda: os.environ.get(
|
|
"IPFS_GATEWAYS", "https://ipfs.io,https://cloudflare-ipfs.com,https://dweb.link"
|
|
)
|
|
)
|
|
|
|
# Derived paths
|
|
@property
|
|
def plan_cache_dir(self) -> Path:
|
|
return self.cache_dir / "plans"
|
|
|
|
@property
|
|
def analysis_cache_dir(self) -> Path:
|
|
return self.cache_dir / "analysis"
|
|
|
|
def ensure_dirs(self) -> None:
|
|
"""Create required directories."""
|
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
self.plan_cache_dir.mkdir(parents=True, exist_ok=True)
|
|
self.analysis_cache_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def log_config(self, logger=None) -> None:
|
|
"""Log all configuration values for debugging."""
|
|
output = logger.info if logger else lambda x: print(x, file=sys.stderr)
|
|
output("=" * 60)
|
|
output("CONFIGURATION")
|
|
output("=" * 60)
|
|
output(f" cache_dir: {self.cache_dir}")
|
|
output(f" redis_url: {self.redis_url}")
|
|
output(f" database_url: {self.database_url[:50]}...")
|
|
output(f" ipfs_api: {self.ipfs_api}")
|
|
output(f" ipfs_gateway_url: {self.ipfs_gateway_url}")
|
|
output(f" ipfs_gateways: {self.ipfs_gateways[:50]}...")
|
|
output(f" streaming_gpu_persist: {self.streaming_gpu_persist}")
|
|
output(f" l2_server: {self.l2_server}")
|
|
output("=" * 60)
|
|
|
|
|
|
# Singleton settings instance
|
|
settings = Settings()
|
|
|
|
# Log config on import if DEBUG or SHOW_CONFIG is set
|
|
if os.environ.get("DEBUG") or os.environ.get("SHOW_CONFIG"):
|
|
settings.log_config()
|