import json from importlib.metadata import distribution from importlib.util import find_spec from pathlib import Path from typing import Mapping from nyahome.cli.cli import console from nyahome.data import db_type_allowlist, db_driver_available class CliWarning: def __init__(self) -> None: self.counter = 0 def info(self, description: str) -> None: console.print(f"INFO - {description}") def warning(self, description: str) -> None: self.counter += 1 console.print(f"[yellow]WARNING {self.counter}[/yellow] - {description}") cw = CliWarning() def check_database_connector() -> dict[str, str]: """ 检查是否安装用于数据库连接的各种驱动库。只有安装对应的驱动库之后才可以连接到对应的数据库。 Returns: {驱动库: 可用状态描述} """ def _(value: bool, description: str) -> str: return f"{'[green]可用[/green]' if value else '[yellow]不可用[/yellow]'} - {description}" result: dict[str, str] = { "sqlite3": _(bool(find_spec("sqlite3")), "Python 标准库,支持 sqlite"), "pymysql": _(bool(find_spec("pymysql")), "社区维护的 MySQL 驱动库"), "psycopg": _(bool(find_spec("psycopg")), "更先进的 PostgreSQL 驱动库"), } return result def check_database_type(environ: Mapping[str, str | None]) -> None: db_type = environ.get("NYAHOME_DB_TYPE") db_driver = environ.get("NYAHOME_DB_DRIVER") db_name = environ.get("NYAHOME_DB_NAME") db_user = environ.get("NYAHOME_DB_USER") db_password = environ.get("NYAHOME_DB_PASSWORD") db_host = environ.get("NYAHOME_DB_HOST") db_port = environ.get("NYAHOME_DB_PORT") if not db_type: cw.warning("NYAHOME_DB_TYPE 未设置,将回退到默认数据库 sqlite。") elif db_type not in db_type_allowlist: cw.warning(f"NYAHOME_DB_TYPE 的值 {db_type} 不受 NyaHome 官方支持。") if not db_driver: cw.warning("NYAHOME_DB_DRIVER 未设置,将使用 SQLModel 的默认驱动库。") elif not find_spec(db_driver): cw.warning(f"NYAHOME_DB_DRIVER 的值 {db_driver} 未在当前 NyaHome 中安装。") elif db_type and (db_driver not in db_driver_available.get(db_type, [])): cw.warning(f"NYAHOME_DB_DRIVER 的值 {db_driver} 是为数据库 {db_type} 准备的吗?") if db_driver and db_type != "sqlite": # 对于 sqlite 数据库,不需要设置凭证 if not db_name: cw.warning("NYAHOME_DB_NAME 未设置,将使用 [cyan]nyahome[/cyan] 作为默认值。") if not db_user: cw.warning("NYAHOME_DB_USER 未设置,将使用 [cyan]nyahome[/cyan] 作为默认值。") if not db_password: cw.warning("NYAHOME_DB_PASSWORD 未设置,将使用 [cyan]nyahome[/cyan] 作为默认值。") if not db_host: cw.warning("NYAHOME_DB_HOST 未设置,将使用 [cyan]localhost[/cyan] 作为默认值。") if not db_port: cw.warning("NYAHOME_DB_PORT 未设置,将使用 [cyan]3306[/cyan] 作为默认值。") cw.info("自检未检查数据库状态是否可用。") else: cw.info("使用 sqlite 数据库,跳过数据库凭证检查。") def check_uvicorn(environ: Mapping[str, str | None]) -> None: un_host = environ.get("NYAHOME_UVICORN_HOST") un_port = environ.get("NYAHOME_UVICORN_PORT") un_reload = environ.get("NYAHOME_UVICORN_RELOAD") if not un_host: cw.warning("NYAHOME_UVICORN_HOST 未设置,将使用 [cyan]0.0.0.0[/cyan] 作为默认值。") if not un_port: cw.warning("NYAHOME_UVICORN_PORT 未设置,将使用 [cyan]9000[/cyan] 作为默认值。") if not un_reload: cw.warning("NYAHOME_UVICORN_RELOAD 未设置,将使用 [cyan]false[/cyan] 作为默认值。") else: if un_reload in ["True", "true", "1"]: cw.warning("NYAHOME_UVICORN_RELOAD 设置为 [cyan]true[/cyan],在生产环境中不应如此。") def check_nyahome_status() -> None: # 检查是否以可编辑模式安装 NyaHome dist = distribution("nyahome") try: f = dist.read_text("direct_url.json") if f: data = json.loads(f) if data.get("dir_info", {}).get("editable", False): cw.warning("当前 NyaHome 以可编辑模式安装。在生产环境中不应如此。") except Exception: pass # 检查 NyaHome 是否受 git 管理 git_dir = Path.cwd() / ".git" if git_dir.is_dir(): cw.warning("当前 NyaHome 受版本控制系统管理。在生产环境中不应如此。") LOGGING_YAML_CONTENT = """version: 1 disable_existing_loggers: false formatters: default: "()": uvicorn.logging.DefaultFormatter fmt: "%(asctime)s | %(levelprefix)s %(name)s | %(message)s" use_colors: true access: "()": uvicorn.logging.AccessFormatter fmt: '%(asctime)s | %(client_addr)s - "%(request_line)s" %(status_code)s' use_colors: true handlers: default: formatter: default class: logging.StreamHandler stream: ext://sys.stderr access: formatter: access class: logging.StreamHandler stream: ext://sys.stdout file: formatter: default class: logging.handlers.RotatingFileHandler filename: .nyahome/app.log maxBytes: 10485760 backupCount: 5 encoding: utf8 loggers: uvicorn: handlers: [ default, file ] level: INFO propagate: false uvicorn.error: handlers: [ default, file ] level: INFO propagate: false uvicorn.access: handlers: [ access, file ] level: INFO propagate: false nyahome: handlers: [ default, file ] level: DEBUG propagate: false"""