Базовая реализация UserAPI
This commit is contained in:
parent
a50d1056eb
commit
2bb21e4ee4
50
user_api/call2api.py
Normal file
50
user_api/call2api.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
from aiohttp import ClientSession
|
||||||
|
from json import dumps, loads
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from db import read, write
|
||||||
|
CONFIG = asyncio.run(read())
|
||||||
|
global url_prefix
|
||||||
|
url_prefix = CONFIG['system_api_url']
|
||||||
|
|
||||||
|
async def call(api_url, data, pre=True, fix=True):
|
||||||
|
url = (url_prefix + api_url) if pre else api_url
|
||||||
|
async with ClientSession() as session:
|
||||||
|
async with session.post(url, json=data) as response:
|
||||||
|
text = await response.text()
|
||||||
|
try:
|
||||||
|
json = loads(text)
|
||||||
|
if 'detail' in json:
|
||||||
|
return json['detail']
|
||||||
|
else:
|
||||||
|
return json
|
||||||
|
except:
|
||||||
|
if fix:
|
||||||
|
return text.replace('"', '')
|
||||||
|
else:
|
||||||
|
return text
|
||||||
|
|
||||||
|
async def check_user_token(token, username, user_token):
|
||||||
|
data = {'token': token, 'username': username, 'user_token': user_token}
|
||||||
|
return await call('api/check_user_token/', data)
|
||||||
|
|
||||||
|
async def user_in_db(token, username=None, creator_id=None, tg_id=None, ds_id=None, mine_name=None):
|
||||||
|
data = {'token': token}
|
||||||
|
if username:
|
||||||
|
data['username'] = username
|
||||||
|
if creator_id:
|
||||||
|
data['creator_id'] = creator_id
|
||||||
|
if tg_id:
|
||||||
|
data['tg_id'] = tg_id
|
||||||
|
if ds_id:
|
||||||
|
data['ds_id'] = ds_id
|
||||||
|
if mine_name:
|
||||||
|
data['mine_name'] = mine_name
|
||||||
|
return await call('api/user_in_db/', data)
|
||||||
|
|
||||||
|
async def transfer_coins(token, src_username, dst_username, amount):
|
||||||
|
data = {'token': token, 'src_username': src_username, 'dst_username': dst_username, 'amount': amount}
|
||||||
|
return await call('api/transfer_coins/', data)
|
||||||
|
|
||||||
|
async def get_stats(token):
|
||||||
|
return await call('api/get_stats/', token)
|
||||||
57
user_api/call2user_api.py
Normal file
57
user_api/call2user_api.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from aiohttp import ClientSession
|
||||||
|
from json import dumps, loads
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from db import read, write
|
||||||
|
|
||||||
|
global url_prefix
|
||||||
|
url_prefix = 'http://127.0.0.1:8010/'
|
||||||
|
|
||||||
|
# async def call(api_url, data, pre=True, fix=True):
|
||||||
|
# url = (url_prefix + api_url) if pre else api_url
|
||||||
|
# async with ClientSession() as session:
|
||||||
|
# async with session.post(url, json=data) as response:
|
||||||
|
# text = await response.text()
|
||||||
|
# try:
|
||||||
|
# json = loads(text)
|
||||||
|
# if 'detail' in json:
|
||||||
|
# return json['detail']
|
||||||
|
# else:
|
||||||
|
# return json
|
||||||
|
# except:
|
||||||
|
# if fix:
|
||||||
|
# return text.replace('"', '')
|
||||||
|
# else:
|
||||||
|
# return text
|
||||||
|
from call2api import call
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# UserAPI
|
||||||
|
#------------------------------------------------------------
|
||||||
|
async def get_user_token_info(username, user_token):
|
||||||
|
data = {'username': username, 'user_token': user_token}
|
||||||
|
return await call('api/get_user_token_info/', data)
|
||||||
|
|
||||||
|
async def user_in_db(username, user_token):
|
||||||
|
data = {'username': username, 'user_token': user_token}
|
||||||
|
return await call('api/user_in_db/', data)
|
||||||
|
|
||||||
|
async def transfer_coins(username, user_token,
|
||||||
|
dst_username, amount):
|
||||||
|
data = {'username': username, 'user_token': user_token,
|
||||||
|
'dst_username': dst_username, 'amount': amount}
|
||||||
|
return await call('api/transfer_coins/', data)
|
||||||
|
#------------------------- END ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# SystemAPI usage only
|
||||||
|
#------------------------------------------------------------
|
||||||
|
async def register_user_token(token, user_token):
|
||||||
|
data = {'token': token, 'user_token': user_token}
|
||||||
|
return await call('api/register_user_token/', data)
|
||||||
|
|
||||||
|
async def unregister_user_token(token, user_token):
|
||||||
|
data = {'token': token, 'user_token': user_token}
|
||||||
|
return await call('api/unregister_user_token/', data)
|
||||||
|
#------------------------- END ------------------------------
|
||||||
80
user_api/db.py
Normal file
80
user_api/db.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# SQL
|
||||||
|
from sqlmodel import Field, SQLModel, or_, select
|
||||||
|
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||||
|
from sqlalchemy.ext.asyncio import create_async_engine
|
||||||
|
# CONFIGS
|
||||||
|
from os import path
|
||||||
|
import json
|
||||||
|
import aiofiles
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# INIT
|
||||||
|
#------------------------------------------------------------
|
||||||
|
global engine
|
||||||
|
def init_engine():
|
||||||
|
global engine
|
||||||
|
sqlite_file_name = "database.db"
|
||||||
|
sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}"
|
||||||
|
engine = create_async_engine(sqlite_url)
|
||||||
|
|
||||||
|
async def create_db_and_tables():
|
||||||
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(SQLModel.metadata.create_all)
|
||||||
|
|
||||||
|
async def get_session():
|
||||||
|
async with AsyncSession(engine) as session:
|
||||||
|
yield session
|
||||||
|
|
||||||
|
#------------------------- END ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# TABLES
|
||||||
|
#------------------------------------------------------------
|
||||||
|
class UserToken(SQLModel, table=True):
|
||||||
|
def __init__(self, token, logs=""):
|
||||||
|
self.token = token
|
||||||
|
self.logs = logs
|
||||||
|
self.issue_date = datetime.today().strftime('%Y-%m-%d')
|
||||||
|
token: str = Field(max_length=200, primary_key=True)
|
||||||
|
logs: str = Field()
|
||||||
|
issue_date: str = Field()
|
||||||
|
#------------------------- END ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# JSONS / CONFIGS
|
||||||
|
#------------------------------------------------------------
|
||||||
|
config_file = 'config.json'
|
||||||
|
if not path.exists(config_file):
|
||||||
|
db = {'system_api_token': 'None',
|
||||||
|
'system_api_url': 'None'}
|
||||||
|
js = json.dumps(db, indent=2)
|
||||||
|
with open(config_file, "w") as outfile:
|
||||||
|
outfile.write(js)
|
||||||
|
print(f'Created new {config_file}')
|
||||||
|
|
||||||
|
async def read(file=config_file):
|
||||||
|
async with aiofiles.open(file, "r", encoding="utf-8") as openfile:
|
||||||
|
content = await openfile.read()
|
||||||
|
db = json.loads(content)
|
||||||
|
return db
|
||||||
|
|
||||||
|
async def write(db, file=config_file):
|
||||||
|
js = json.dumps(db, indent=2, ensure_ascii=False)
|
||||||
|
async with aiofiles.open(file, "w", encoding="utf-8") as outfile:
|
||||||
|
await outfile.write(js)
|
||||||
|
|
||||||
|
#------------------------- END ------------------------------
|
||||||
|
|
||||||
|
async def user_token_in_db_func(
|
||||||
|
session: AsyncSession,
|
||||||
|
user_token: str
|
||||||
|
):
|
||||||
|
statement = select(UserToken).where(UserToken.token == user_token)
|
||||||
|
result = await session.exec(statement)
|
||||||
|
# Get the first result or None if not found
|
||||||
|
user_token_obj = result.first()
|
||||||
|
return user_token_obj
|
||||||
129
user_api/user_api.py
Normal file
129
user_api/user_api.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
from fastapi import Depends, FastAPI, HTTPException, Query, Body
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# 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):
|
||||||
|
return await check_user_token(SYSTEM_API_TOKEN, username, user_token)
|
||||||
|
|
||||||
|
@app.post('/api/register_user_token/')
|
||||||
|
async def register_user_token_api(
|
||||||
|
token: str = Body(),
|
||||||
|
user_token: str = Body(),
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
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))
|
||||||
|
|
||||||
|
@app.post('/api/unregister_user_token/')
|
||||||
|
async def unregister_user_token_api(
|
||||||
|
token: str = Body(),
|
||||||
|
user_token: str = Body(),
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
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=409, 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))
|
||||||
|
|
||||||
|
@app.post('/api/get_user_token_info/')
|
||||||
|
async def get_user_token_info_api(
|
||||||
|
username: str | None = Body(None),
|
||||||
|
user_token: str = Body(),
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
if not 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=409, 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}
|
||||||
|
|
||||||
|
@app.post('/api/user_in_db/')
|
||||||
|
async def user_in_db_api(
|
||||||
|
username: str | None = Body(None),
|
||||||
|
user_token: str = Body(),
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
if not token_check(username, user_token):
|
||||||
|
raise HTTPException(status_code=401, detail='Invalid username or token')
|
||||||
|
return await user_in_db(token=SYSTEM_API_TOKEN, username=username)
|
||||||
|
|
||||||
|
@app.post('/api/transfer_coins/')
|
||||||
|
async def transfer_coins_api(
|
||||||
|
username: str = Body(),
|
||||||
|
user_token: str = Body(),
|
||||||
|
dst_username: str = Body(),
|
||||||
|
amount: float = Body(),
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
if not token_check(username, user_token):
|
||||||
|
raise HTTPException(status_code=401, detail='Invalid username or token')
|
||||||
|
return await transfer_coins(token=SYSTEM_API_TOKEN, src_username=username
|
||||||
|
, dst_username=dst_username, amount=amount)
|
||||||
|
|
||||||
|
@app.post('/api/get_stats/')
|
||||||
|
async def get_stats_api(
|
||||||
|
username: str = Body(),
|
||||||
|
user_token: str = Body()
|
||||||
|
):
|
||||||
|
if not token_check(username, user_token):
|
||||||
|
raise HTTPException(status_code=401, detail='Invalid username or token')
|
||||||
|
return await get_stats(token=SYSTEM_API_TOKEN)
|
||||||
|
|
||||||
|
#------------------------- END ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# START
|
||||||
|
#------------------------------------------------------------
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(app, host='0.0.0.0', port=8010)
|
||||||
|
#------------------------- END ------------------------------
|
||||||
Loading…
Reference in New Issue
Block a user