123 lines
5.0 KiB
Python
123 lines
5.0 KiB
Python
import os
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
from granian import Granian
|
||
|
||
from utils.logger import root_logger as logger
|
||
|
||
|
||
def check_mkcert_installed():
|
||
"""
|
||
Проверяет, установлен ли инструмент mkcert в системе
|
||
|
||
Returns:
|
||
bool: True если mkcert установлен, иначе False
|
||
|
||
>>> check_mkcert_installed() # doctest: +SKIP
|
||
True
|
||
"""
|
||
try:
|
||
subprocess.run(["mkcert", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||
return True
|
||
except FileNotFoundError:
|
||
return False
|
||
|
||
|
||
def generate_certificates(domain="localhost", cert_file="localhost.pem", key_file="localhost-key.pem"):
|
||
"""
|
||
Генерирует сертификаты с использованием mkcert
|
||
|
||
Args:
|
||
domain: Домен для сертификата
|
||
cert_file: Имя файла сертификата
|
||
key_file: Имя файла ключа
|
||
|
||
Returns:
|
||
tuple: (cert_file, key_file) пути к созданным файлам
|
||
|
||
>>> generate_certificates() # doctest: +SKIP
|
||
('localhost.pem', 'localhost-key.pem')
|
||
"""
|
||
# Проверяем, существуют ли сертификаты
|
||
if os.path.exists(cert_file) and os.path.exists(key_file):
|
||
logger.info(f"Сертификаты уже существуют: {cert_file}, {key_file}")
|
||
return cert_file, key_file
|
||
|
||
# Проверяем, установлен ли mkcert
|
||
if not check_mkcert_installed():
|
||
logger.error("mkcert не установлен. Установите mkcert с помощью команды:")
|
||
logger.error(" macOS: brew install mkcert")
|
||
logger.error(" Linux: apt install mkcert или эквивалент для вашего дистрибутива")
|
||
logger.error(" Windows: choco install mkcert")
|
||
logger.error("После установки выполните: mkcert -install")
|
||
return None, None
|
||
|
||
try:
|
||
# Запускаем mkcert для создания сертификата
|
||
logger.info(f"Создание сертификатов для {domain} с помощью mkcert...")
|
||
result = subprocess.run(
|
||
["mkcert", "-cert-file", cert_file, "-key-file", key_file, domain],
|
||
stdout=subprocess.PIPE,
|
||
stderr=subprocess.PIPE,
|
||
text=True,
|
||
)
|
||
|
||
if result.returncode != 0:
|
||
logger.error(f"Ошибка при создании сертификатов: {result.stderr}")
|
||
return None, None
|
||
|
||
logger.info(f"Сертификаты созданы: {cert_file}, {key_file}")
|
||
return cert_file, key_file
|
||
except Exception as e:
|
||
logger.error(f"Не удалось создать сертификаты: {str(e)}")
|
||
return None, None
|
||
|
||
|
||
def run_server(host="0.0.0.0", port=8000, workers=1):
|
||
"""
|
||
Запускает сервер Granian с поддержкой HTTPS при необходимости
|
||
|
||
Args:
|
||
host: Хост для запуска сервера
|
||
port: Порт для запуска сервера
|
||
use_https: Флаг использования HTTPS
|
||
workers: Количество рабочих процессов
|
||
|
||
>>> run_server(use_https=True) # doctest: +SKIP
|
||
"""
|
||
# Проблема с многопроцессорным режимом - не поддерживает локальные объекты приложений
|
||
# Всегда запускаем в режиме одного процесса для отладки
|
||
if workers > 1:
|
||
logger.warning("Многопроцессорный режим может вызвать проблемы сериализации приложения. Использую 1 процесс.")
|
||
workers = 1
|
||
|
||
# При проблемах с ASGI можно попробовать использовать Uvicorn как запасной вариант
|
||
try:
|
||
# Генерируем сертификаты с помощью mkcert
|
||
cert_file, key_file = generate_certificates()
|
||
|
||
if not cert_file or not key_file:
|
||
logger.error("Не удалось сгенерировать сертификаты для HTTPS")
|
||
return
|
||
|
||
logger.info(f"Запуск HTTPS сервера на https://{host}:{port} с использованием Granian")
|
||
# Запускаем Granian сервер с явным указанием ASGI
|
||
server = Granian(
|
||
address=host,
|
||
port=port,
|
||
workers=workers,
|
||
interface="asgi",
|
||
target="main:app",
|
||
ssl_cert=Path(cert_file),
|
||
ssl_key=Path(key_file),
|
||
)
|
||
server.serve()
|
||
except Exception as e:
|
||
# В случае проблем с Granian, пробуем запустить через Uvicorn
|
||
logger.error(f"Ошибка при запуске Granian: {str(e)}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
run_server()
|