117 lines
5.1 KiB
Python
117 lines
5.1 KiB
Python
|
import os
|
|||
|
import subprocess
|
|||
|
from pathlib import Path
|
|||
|
from utils.logger import root_logger as logger
|
|||
|
from granian import Granian
|
|||
|
|
|||
|
|
|||
|
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()
|