from contextlib import asynccontextmanager from fastapi import FastAPI, Query, HTTPException from fastapi.responses import FileResponse from app.api.endpoints import users, auth, messages, media, admin from app.websocket.connection_manager import wsRouter from fastapi.middleware.cors import CORSMiddleware import os from app.db import models from app.core.config import config from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles import mimetypes # Планировщик from apscheduler.schedulers.asyncio import AsyncIOScheduler from app.tasks import delete_old_sessions from app.db.models import AsyncSessionLocal # Обертка для задачи, чтобы управлять сессией БД async def run_delete_old_sessions(): async with AsyncSessionLocal() as db: await delete_old_sessions(db) # Создаем менеджер контекста жизненного цикла приложения @asynccontextmanager async def lifespan(app: FastAPI): print("Инициализация базы данных...") await models.init_models() async with AsyncSessionLocal() as db: from app.db.models import User from sqlalchemy import select result = await db.execute(select(User).where(User.id == 0)) if not result.scalars().first(): system_user = User( id=0, # Явно задаем ID 0 username="chepuhagram", first_name="Chepuhagram", last_name="Систесные уведомления", hashed_password="system_account_no_password", is_blocked=0 ) db.add(system_user) await db.commit() print("Системный аккаунт (id: 0) успешно создан.") print("База данных успешно инициализирована.") # Инициализация и запуск планировщика scheduler = AsyncIOScheduler() scheduler.add_job(run_delete_old_sessions, 'interval', hours=24) scheduler.start() print("Планировщик запущен.") yield # Здесь сервер работает и принимает запросы print("Выключение сервера...") scheduler.shutdown() print("Планировщик остановлен.") # Подключаем lifespan при создании приложения app = FastAPI(lifespan=lifespan) app.include_router(auth.authRouter) app.include_router(users.usersRouter) app.include_router(messages.messagesRouter) app.include_router(media.mediaRouter) app.include_router(wsRouter) app.include_router(admin.adminRouter) app.add_middleware( CORSMiddleware, allow_origins=config.ALLOWED_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Папка, где лежат твои релизы на сервере RELEASE_DIR = "releases" @app.get("/check-update") async def check_update(platform: str = Query("android", description="Платформа: android или windows")): if platform.lower() == "windows": return { "latest_version": "2.0.2", "download_url": "https://api.chepuhagram.ru/get-update?platform=windows", "force_update": False } return { "latest_version": "2.0.2", "apk_url": "https://api.chepuhagram.ru/get-update?platform=android", "apk_zip_url": "https://api.chepuhagram.ru/get-update?platform=android-zip", "force_update": False } @app.get("/get-update") @app.head("/get-update") async def get_update(platform: str = Query("android")): """Отдача самих файлов пакетов (APK или MSIX)""" if platform.lower() == "windows": file_path = os.path.join(RELEASE_DIR, "chepuhagram_setup.exe") if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="Файл MSIX не найден") return FileResponse( path=file_path, filename="Chepuhagram.exe", media_type="application/x-msdownload" ) # Ветка для Android if "zip" in platform.lower(): file_path = os.path.join(RELEASE_DIR, "app-release.zip") if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="Файл ZIP не найден") return FileResponse( path=file_path, filename="chepuhagram-release.zip", media_type="application/zip" ) file_path = os.path.join(RELEASE_DIR, "app-release.apk") if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="Файл APK не найден") return FileResponse( path=file_path, filename="chepuhagram-release.apk", media_type="application/vnd.android.package-archive" ) if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=8587, reload=True)