Files
BuildIncrementer/main.py

139 lines
4.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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