Files
talkscore-asr/app/launcher.py
T
Vladimir BryzgalovandClaude Opus 5 febec7f124 Логика запуска и Caddyfile переехали внутрь app
Файлы вне папки app обновление не доставляло: чтобы изменить порядок
запуска или конфигурацию Caddy, требовалась переустановка. Теперь .bat -
заглушка из трёх строк, вызывающая app/launcher.py, а Caddyfile создаётся
из настроек [https] в config.toml. Отредактированный вручную Caddyfile
не затирается: новая версия откладывается рядом как Caddyfile.new.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 17:23:47 +05:00

132 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Запуск сервиса: обновление, Caddyfile, HTTPS.
Раньше вся эта последовательность жила в .bat-файлах, а Caddyfile правился
руками. Оба файла лежат вне папки app, поэтому обновление их не доставляло:
чтобы получить новый порядок запуска, приходилось переустанавливать сервис.
Теперь .bat - это трёхстрочная заглушка, которая просто зовёт этот модуль,
а Caddyfile создаётся здесь из настроек. Меняется только код внутри app,
который обновление возит штатно.
"""
import subprocess
import sys
from pathlib import Path
__all__ = ["render_caddyfile", "ensure_caddyfile", "main"]
# По этой строке отличаем свой файл от отредактированного вручную.
MARK = "# Создан автоматически talkscore-asr. Правки будут перезаписаны."
CADDY_WAIT_SEC = 3
def render_caddyfile(domains: str, port: int, max_upload_mb: int) -> str:
"""Собирает конфигурацию Caddy из настроек сервиса."""
listed = ", ".join(d.strip() for d in domains.split(",") if d.strip())
return f"""{MARK}
# Домены и предел размера берутся из config.toml, менять нужно там.
{{
\t# Caddy очень подробно рассказывает про сертификаты. В консоли из-за этого
\t# не видно сообщений сервиса, поэтому его вывод уходит в файл.
\tlog {{
\t\toutput file logs/caddy.log {{
\t\t\troll_size 10MiB
\t\t\troll_keep 5
\t\t}}
\t\tformat console
\t\tlevel INFO
\t}}
}}
{listed} {{
\treverse_proxy 127.0.0.1:{port} {{
\t\t# Реальный адрес клиента - иначе список разрешённых адресов
\t\t# увидит вместо него localhost и пустит кого угодно.
\t\theader_up X-Forwarded-For {{remote_host}}
\t}}
\trequest_body {{
\t\tmax_size {max_upload_mb}MB
\t}}
}}
"""
def ensure_caddyfile(base_dir: Path, content: str) -> Path | None:
"""Записывает Caddyfile, не затирая ручные правки.
Если файл создан не нами, откладываем новую версию рядом: молча стереть
чужую настройку хуже, чем оставить её устаревшей.
"""
target = base_dir / "Caddyfile"
if target.exists():
existing = target.read_text(encoding="utf-8", errors="replace")
if MARK not in existing:
spare = base_dir / "Caddyfile.new"
if existing.strip() != content.strip():
spare.write_text(content, encoding="utf-8")
return spare
return None
if existing == content:
return None
target.write_text(content, encoding="utf-8")
return target
def start_caddy(base_dir: Path) -> subprocess.Popen | None:
"""Поднимает Caddy отдельным процессом. Его отсутствие не должно ронять запуск."""
binary = base_dir / "bin" / "caddy.exe"
if not binary.is_file():
binary = base_dir / "bin" / "caddy"
if not binary.is_file():
print("\n Caddy не найден в папке bin - запускаюсь без HTTPS.\n")
return None
(base_dir / "logs").mkdir(exist_ok=True)
return subprocess.Popen(
[str(binary), "run", "--config", str(base_dir / "Caddyfile")],
cwd=str(base_dir))
def main(argv: list[str] | None = None) -> int:
argv = sys.argv[1:] if argv is None else argv
https = "https" in argv
from app import updater
from app.config import ConfigError, load_settings
try:
settings = load_settings()
except ConfigError as exc:
print(f"\n {exc}\n")
return 1
updater.main()
caddy = None
if https:
if not settings.https_domains.strip():
print("\n В config.toml не заданы домены: раздел [https], ключ domains."
"\n Без них сертификат выпустить не на что.\n")
return 1
written = ensure_caddyfile(
settings.base_dir,
render_caddyfile(settings.https_domains, settings.port,
settings.max_upload_mb))
if written is not None and written.name.endswith(".new"):
print(f"\n Caddyfile правили вручную, поэтому не трогаю его."
f"\n Новая версия отложена рядом: {written}\n")
caddy = start_caddy(settings.base_dir)
try:
from app.main import run
run()
finally:
if caddy is not None:
caddy.terminate()
return 0
if __name__ == "__main__":
sys.exit(main())