from database import engine, SessionLocal, Base from fastapi import FastAPI, HTTPException, Depends, Security from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session import json import models import os import schemas from sqlalchemy import select, update from sqlalchemy.orm import aliased app = FastAPI( title="Сервис Счетчиков", description="Сервис для инкрементирования, получения и сброса счетчиков с поддержкой namespaces, приложений и версий.", version="1.0.0" ) # Создаем таблицы в базе данных Base.metadata.create_all(bind=engine) # Зависимость для получения сессии базы данных def get_db(): db = SessionLocal() try: yield db finally: db.close() # Базовая авторизация через Bearer токен security = HTTPBearer() TOKEN: str = os.environ.get("BUILD_INC_TOKEN", None) if TOKEN is None: THIS_SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(THIS_SCRIPT_PATH, "token.json"), 'r') as f: t = json.load(f) TOKEN = t["auth.token"] def get_current_user(credentials: HTTPAuthorizationCredentials = Security(security)): if credentials.credentials != TOKEN: raise HTTPException(status_code=401, detail="Invalid or missing token") return credentials.credentials @app.post("/{namespace}/{application}/{version}", response_model=schemas.CounterResponse, summary="Инкрементировать счетчик и получить новое значение") def increment_counter( namespace: str, application: str, version: str, db: Session = Depends(get_db), user: str = Depends(get_current_user) ): try: # Попытка найти существующий счетчик counter = db.query(models.Counter).filter_by( namespace=namespace, application=application, version=version ).with_for_update().first() if counter: counter.value += 1 else: # Если счетчик не существует, создать новый с value=1 counter = models.Counter( namespace=namespace, application=application, version=version, value=1 ) db.add(counter) db.commit() db.refresh(counter) return counter except IntegrityError: db.rollback() raise HTTPException(status_code=500, detail="Ошибка при доступе к базе данных.") @app.get("/{namespace}/{application}/{version}", response_model=schemas.CounterResponse, summary="Получить текущее значение счетчика") def get_counter( namespace: str, application: str, version: str, db: Session = Depends(get_db), user: str = Depends(get_current_user) ): counter = db.query(models.Counter).filter_by( namespace=namespace, application=application, version=version ).first() if not counter: # Если счетчик не найден, вернуть значение 0 return schemas.CounterResponse( namespace=namespace, application=application, version=version, value=0 ) return counter @app.delete("/{namespace}/{application}/{version}", response_model=schemas.CounterResponse, summary="Сбросить счетчик до 0") def reset_counter( namespace: str, application: str, version: str, db: Session = Depends(get_db), user: str = Depends(get_current_user) ): counter = db.query(models.Counter).filter_by( namespace=namespace, application=application, version=version ).with_for_update().first() if counter: counter.value = 0 else: # Если счетчик не существует, создать его с value=0 counter = models.Counter( namespace=namespace, application=application, version=version, value=0 ) db.add(counter) db.commit() db.refresh(counter) return counter