Логика запуска и 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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
cd3acafa8a
commit
febec7f124
+131
@@ -0,0 +1,131 @@
|
||||
"""Запуск сервиса: обновление, 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())
|
||||
Reference in New Issue
Block a user