from fastapi import Depends, FastAPI, HTTPException, Query, Body, Request from contextlib import asynccontextmanager import asyncio from statistics import median from db import * from call2api import check_user_token, user_in_db, transfer_coins, get_stats, create_invoice, delete_invoice, \ get_invoice from func import * #------------------------------------------------------------ # INIT #------------------------------------------------------------ @asynccontextmanager async def lifespan(app: FastAPI): init_engine() await create_db_and_tables() yield app = FastAPI(lifespan=lifespan) CONFIG = asyncio.run(read()) SYSTEM_API_TOKEN = CONFIG['system_api_token'] #------------------------- END ------------------------------ #------------------------------------------------------------ # APIs (main code) #------------------------------------------------------------ async def token_check(username, user_token): result = await check_user_token(SYSTEM_API_TOKEN, username, user_token) if result == 'OK': return True else: return False # For SystemAPI ONLY # IN : token (str), user_token (str) # OUT: 'OK' / 'Invalid token' (401) / 'Token already exist' (409) / General error (500) @app.post('/api/register_user_token/') async def register_user_token_api( request: Request, token: str = Body(), user_token: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if token != SYSTEM_API_TOKEN: raise HTTPException(status_code=401, detail='Invalid token') user_token_db = await user_token_in_db_func(session, user_token) if user_token_db: raise HTTPException(status_code=409, detail='Token already exist') new_user_token = UserToken(token=user_token) try: session.add(new_user_token) await session.commit() await session.refresh(new_user_token) return 'OK' except Exception as e: await session.rollback() raise HTTPException(status_code=500, detail=str(e)) # For SystemAPI ONLY # IN : token (str), user_token (str) # OUT: 'OK' / 'Invalid token' (401) / 'Token not exist' (404) / General error (500) @app.post('/api/unregister_user_token/') async def unregister_user_token_api( request: Request, token: str = Body(), user_token: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if token != SYSTEM_API_TOKEN: raise HTTPException(status_code=401, detail='Invalid token') user_token_db = await user_token_in_db_func(session, user_token) if not user_token_db: raise HTTPException(status_code=404, detail='Token not exist') try: await session.delete(user_token_db) await session.commit() return 'OK' except Exception as e: await session.rollback() raise HTTPException(status_code=500, detail=str(e)) # IN : username (str), user_token (str) # OUT: {'issue_date': str, 'logs': str} / 'Invalid username or token' (401) / 'Token not exist' (404) / General error (500) @app.post('/api/get_user_token_info/') async def get_user_token_info_api( request: Request, username: str | None = Body(None), user_token: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') user_token_db = await user_token_in_db_func(session, user_token) if not user_token_db: raise HTTPException(status_code=404, detail='Token not exist') # Force data retrieval (DB can not load it properly, because it "lazy") issue_date = await session.run_sync(lambda sess: user_token_db.issue_date) logs = await session.run_sync(lambda sess: user_token_db.logs) return {'issue_date': issue_date, 'logs': logs} # IN : username (str), user_token (str) # OUT: { # "creator_id_type": str, # "username": str, # "mine_uuid": str, # "tg_id": int, # "balance": float, # "tokens": "{}", # "password": "HIDDEN", # "creator_id": str, # "mine_name": str, # "ds_id": int, # "frozen": "no"/"temporarily"/"forever", # "last_activity": null, # } / 'Invalid username or token' (401) / 'User not found' (404) / General error (500) @app.post('/api/user_in_db/') async def user_in_db_api( request: Request, username: str | None = Body(None), user_token: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/user_in_db') return await user_in_db(token=SYSTEM_API_TOKEN, username=username) # IN : username (str), user_token (str), dst_username (str), amount (float) # OUT: 'OK' / 'Invalid username or token' (401) / 'No money' (400) / 'Too low' (400) # / 'User not found' (404) / 'Frozen temporarily' (401) / 'Frozen forever' (401) # / General error (500) @app.post('/api/transfer_coins/') async def transfer_coins_api( request: Request, username: str = Body(), user_token: str = Body(), dst_username: str = Body(), amount: float = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/transfer_coins: (dst_username: {dst_username}, amount: {amount})') return await transfer_coins(token=SYSTEM_API_TOKEN, src_username=username , dst_username=dst_username, amount=amount) # IN : username (str), user_token (str) # OUT: { # "amount": float, # "frozen_amount": int, # "users": int, # "frozen_users": int, # "average": float, # "median": float, # "min": float, # "max": float # } / 'Invalid username or token' (401) / General error (500) @app.post('/api/get_stats/') async def get_stats_api( request: Request, username: str = Body(), user_token: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/get_stats') return await get_stats(token=SYSTEM_API_TOKEN) # IN : username (str), user_token (str), amount (float) # OUT: invoice_id (str) / 'Invalid username or token' (401) / 'Destination user not found' (401) # / General error (500) @app.post('/api/create_invoice/') async def create_invoice_api( request: Request, username: str = Body(), user_token: str = Body(), amount: float | None = Body(None), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/create_invoice: (amount: {amount})') return await create_invoice(token=SYSTEM_API_TOKEN, dst_username=username, amount=amount) # IN : username (str), user_token (str), invoice_id (str) # OUT: 'OK' / 'Invalid username or token' (401) / 'Invoice id not found' (404) / General error (500) @app.post('/api/delete_invoice/') async def delete_invoice_api( request: Request, username: str = Body(), user_token: str = Body(), invoice_id: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/delete_invoice: (id: {invoice_id})') return await delete_invoice(token=SYSTEM_API_TOKEN, invoice_id=invoice_id) # IN : username (str), user_token (str), invoice_id (str) # OUT: { # "id": str, # "dst_username": str, # "amount": null / float, # "status": false/true # } / 'Invalid username or token' (401) / 'Invoice id not found' (404) / General error (500) @app.post('/api/get_invoice/') async def get_invoice_api( request: Request, username: str = Body(), user_token: str = Body(), invoice_id: str = Body(), session: AsyncSession = Depends(get_session) ): if await is_rate_limited(request.client.host): raise HTTPException(status_code=429, detail='Too many requests') if not await token_check(username, user_token): raise HTTPException(status_code=401, detail='Invalid username or token') await log(session, user_token, f'/get_invoice: (id: {invoice_id})') return await get_invoice(token=SYSTEM_API_TOKEN, invoice_id=invoice_id) #------------------------- END ------------------------------ #------------------------------------------------------------ # START #------------------------------------------------------------ if __name__ == '__main__': import uvicorn uvicorn.run(app, host='0.0.0.0', port=8010) #------------------------- END ------------------------------