Files
TJWaterServerBinary/app/core/config.py
T
jiang 90b02057bc
Generic Container CI/CD / test-build-publish (push) Successful in 1m13s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 1m13s
feat(projects): automate project infrastructure provisioning
2026-09-11 10:57:51 +08:00

164 lines
5.4 KiB
Python

from pathlib import Path
from typing import Optional
from urllib.parse import quote_plus
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
PROJECT_NAME: str = "TJWater Server"
ENVIRONMENT: str = "production"
API_V1_STR: str = "/api/v1"
NETWORK_NAME: str = "default_network"
# 敏感配置加密密钥 (Fernet)
DATABASE_ENCRYPTION_KEY: str = ""
# Database Config (PostgreSQL)
DB_NAME: str = "tjwater"
DB_HOST: str = "localhost"
DB_PORT: str = "5432"
DB_USER: str = "postgres"
DB_PASSWORD: str = "password"
# Database Config (TimescaleDB)
TIMESCALEDB_DB_NAME: str = "tjwater"
TIMESCALEDB_DB_HOST: str = "localhost"
TIMESCALEDB_DB_PORT: str = "5433"
TIMESCALEDB_DB_USER: str = "postgres"
TIMESCALEDB_DB_PASSWORD: str = "password"
# Metadata Database Config (PostgreSQL)
METADATA_DB_NAME: str = "system_hub"
METADATA_DB_HOST: str = "localhost"
METADATA_DB_PORT: str = "5432"
METADATA_DB_USER: str = "postgres"
METADATA_DB_PASSWORD: str = "password"
METADATA_DB_POOL_SIZE: int = 5
METADATA_DB_MAX_OVERFLOW: int = 10
PROJECT_PG_CACHE_SIZE: int = 16
PROJECT_TS_CACHE_SIZE: int = 16
PROJECT_PG_POOL_MIN_SIZE: int = 0
PROJECT_PG_POOL_SIZE: int = 4
PROJECT_PG_MAX_OVERFLOW: int = 2
PROJECT_TS_POOL_MIN_SIZE: int = 0
PROJECT_TS_POOL_MAX_SIZE: int = 4
WNDB_SCHEMA_TEMPLATE_DB_NAME: str = "tjwater_v2_schema_template"
TIMESCALEDB_SCHEMA_TEMPLATE_DB_NAME: str = "tjwater_v2_timescale_template"
WNDB_TEMP_DB_MAX_COUNT: int = 8
# GeoServer project provisioning
GEOSERVER_URL: str = "http://localhost:8080/geoserver"
GEOSERVER_USERNAME: str = ""
GEOSERVER_PASSWORD: str = ""
GEOSERVER_DB_HOST: str = ""
GEOSERVER_DB_PORT: str = ""
GEOSERVER_DB_USER: str = ""
GEOSERVER_DB_PASSWORD: str = ""
GEOSERVER_CLIENT_CACHE_SECONDS: int = 30 * 24 * 60 * 60
# Keycloak access token verification
KEYCLOAK_PUBLIC_KEY: str = ""
KEYCLOAK_ALGORITHM: str = "RS256"
KEYCLOAK_AUDIENCE: str = ""
KEYCLOAK_ACCESS_TOKEN_MAX_AGE_SECONDS: int = 900
# Bocha Web Search API
BOCHA_API_KEY: str = ""
BOCHA_WEB_SEARCH_URL: str = "https://api.bochaai.com/v1/web-search"
BOCHA_WEB_SEARCH_TIMEOUT_SECONDS: float = 30.0
# Tianditu Geocoding API
TIANDITU_GEOCODER_TOKEN: str = ""
TIANDITU_GEOCODER_URL: str = "https://api.tianditu.gov.cn/geocoder"
TIANDITU_GEOCODER_TIMEOUT_SECONDS: float = 30.0
@property
def SQLALCHEMY_DATABASE_URI(self) -> str:
db_password = quote_plus(self.DB_PASSWORD)
return f"postgresql://{self.DB_USER}:{db_password}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
@property
def METADATA_DATABASE_URI(self) -> str:
metadata_password = quote_plus(self.METADATA_DB_PASSWORD)
return (
f"postgresql+psycopg://{self.METADATA_DB_USER}:{metadata_password}"
f"@{self.METADATA_DB_HOST}:{self.METADATA_DB_PORT}/{self.METADATA_DB_NAME}"
)
model_config = SettingsConfigDict(
env_file=Path(__file__).resolve().parents[2] / ".env",
extra="ignore",
)
settings = Settings()
def get_pgconn_string(
db_name: Optional[str] = None,
db_host: Optional[str] = None,
db_port: Optional[str] = None,
db_user: Optional[str] = None,
db_password: Optional[str] = None,
) -> str:
"""Return PostgreSQL connection string in psycopg conninfo format."""
resolved_db_name = db_name or settings.DB_NAME
resolved_db_host = db_host or settings.DB_HOST
resolved_db_port = db_port or settings.DB_PORT
resolved_db_user = db_user or settings.DB_USER
resolved_db_password = db_password or settings.DB_PASSWORD
return (
f"dbname={resolved_db_name} host={resolved_db_host} port={resolved_db_port} "
f"user={resolved_db_user} password={resolved_db_password}"
)
def get_pg_config() -> dict:
"""Return PostgreSQL configuration except password."""
return {
"name": settings.DB_NAME,
"host": settings.DB_HOST,
"port": settings.DB_PORT,
"user": settings.DB_USER,
}
def get_pg_password() -> str:
"""Return PostgreSQL password (use with care)."""
return settings.DB_PASSWORD
def get_timescaledb_pgconn_string(
db_name: Optional[str] = None,
db_host: Optional[str] = None,
db_port: Optional[str] = None,
db_user: Optional[str] = None,
db_password: Optional[str] = None,
) -> str:
"""Return TimescaleDB connection string in psycopg conninfo format."""
resolved_db_name = db_name or settings.TIMESCALEDB_DB_NAME
resolved_db_host = db_host or settings.TIMESCALEDB_DB_HOST
resolved_db_port = db_port or settings.TIMESCALEDB_DB_PORT
resolved_db_user = db_user or settings.TIMESCALEDB_DB_USER
resolved_db_password = db_password or settings.TIMESCALEDB_DB_PASSWORD
return (
f"dbname={resolved_db_name} host={resolved_db_host} port={resolved_db_port} "
f"user={resolved_db_user} password={resolved_db_password}"
)
def get_timescaledb_pg_config() -> dict:
"""Return TimescaleDB configuration except password."""
return {
"name": settings.TIMESCALEDB_DB_NAME,
"host": settings.TIMESCALEDB_DB_HOST,
"port": settings.TIMESCALEDB_DB_PORT,
"user": settings.TIMESCALEDB_DB_USER,
}
def get_timescaledb_pg_password() -> str:
"""Return TimescaleDB password (use with care)."""
return settings.TIMESCALEDB_DB_PASSWORD