This commit is contained in:
2025-03-10 15:10:03 +08:00
parent cb388ce6b3
commit 527dad1dc7
17763 changed files with 13421 additions and 1 deletions
View File
+83
View File
@@ -0,0 +1,83 @@
import base64
import hmac
import json
import time
from typing import Optional
from core.basic.character import Character
from fastapi import Header, Request
from api.core.exception import ResponseException
class AlterState:
def __init__(self, alter: str, token: str, charcater: Character, equVersion: str):
self.alter = alter
self.token = token
self.origin = alter.split('.')[-1]
self.character = charcater
self.equVersion = equVersion
def to_dict(self):
return self.__dict__
class Dict(dict):
__setattr__ = dict.__setitem__
__getattr__ = dict.__getitem__
def dict2obj(dictObj):
if not isinstance(dictObj, dict):
return dictObj
d = Dict()
for k, v in dictObj.items():
d[k] = dict2obj(v)
return d
async def createToken(alter: str, equVersion: str, expire=86400 / 24 * 2, redis=None, env=''):
ts_str = str(time.time() + expire)
ts_byte = ts_str.encode('utf-8')
sha1_tshex_str = hmac.new(alter.encode('utf-8'), ts_byte, 'sha1').hexdigest()
token = sha1_tshex_str
token = base64.urlsafe_b64encode(token.encode('utf-8')).decode('utf-8')
# character = createCharacter(alter)
character = {}
await redis.set(f'token:{token}', json.dumps(AlterState(alter, token, character, equVersion).to_dict()), int(expire))
return token
async def readToken(token: str, redis, env) -> AlterState:
info = None
try:
info = dict2obj(json.loads(await redis.get(f'token:{token}')))
except Exception:
ResponseException('登录过期或无效Token,请刷新后重试')
if info is None:
raise ResponseException('登录过期或无效Token,请刷新后重试')
return info
def deleteToken(token, redis, env):
redis.expire(token, 0)
return token
async def authorize(request: Request, access_token: Optional[str] = Header(None)):
if access_token is not None:
info = await readToken(access_token, request.app.state.redis, request.app.state.env)
return info
else:
raise ResponseException('登录过期或无效Token,请刷新后重试')
def unauthorize(request: Request, access_token: Optional[str] = Header(None)):
if access_token is not None:
return deleteToken(access_token, request.app.state.redis, request.app.state.env)
async def uid(request: Request, access_uid: Optional[str] = Header(None)):
try:
return int(access_uid)
except Exception:
return -1
+65
View File
@@ -0,0 +1,65 @@
from datetime import datetime
import logging
import traceback
from fastapi import Request, status
from fastapi.responses import JSONResponse
# from fastapi import Request, status
from api.core.exception import ResponseException
logFormatter = logging.Formatter(
"""
[start]
%(asctime)s
<%(name)s>
%(message)s
[end]
"""
)
async def all_exception_handler(request: Request, ex: Exception):
# api = str(request.url).split("api/")[1]
info = ''
if not isinstance(ex, ResponseException):
info = traceback.format_exc(limit=-1).strip().split('\n')[1:]
info[0] = info[0].split('\\')[-1].replace('"', ':').replace(',', '')
info = '\r'.join(info)
if request.client.host != '127.0.0.1':
from fastapi.logger import logger
logger.setLevel(logging.ERROR)
logger.name = 'dcalc'
log_directory = 'logs'
import os
if not os.path.exists('./logs'):
os.makedirs('./logs')
time_str = datetime.now().strftime('%Y_%m_%d')
fileHandler = logging.FileHandler(f'{log_directory}/{logger.name,}_{time_str}.log', encoding='utf-8')
fileHandler.setFormatter(logFormatter)
fileHandler.setLevel(logging.ERROR)
logger.addHandler(fileHandler)
try:
import pathlib
pathlib.Path(log_directory).mkdir(parents=True, exist_ok=True)
except PermissionError:
print('创建日志目录logs失败,请确认是否限制了基础的运行权限')
logFunc = logger.error
logFunc(info)
info = '服务器内部错误'
else:
info = ex.args[0]
# traceback.print_last(sys.exc_info())
return JSONResponse(
status_code=status.HTTP_200_OK,
# 一定要加
headers={'Access-Control-Allow-Origin': '*'},
content={
'code': 500,
'message': info,
# f"api:{api} \n \r{info}",
'data': [],
},
)
+56
View File
@@ -0,0 +1,56 @@
import gzip
from fastapi import Request, APIRouter, FastAPI
from fastapi.responses import Response
from typing import Callable
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.routing import APIRoute
class GzipRequest(Request):
async def body(self) -> bytes:
if not hasattr(self, '_body'):
body = await super().body()
if 'gzip' in self.headers.getlist('Content-Encoding'):
body = gzip.decompress(body)
if 'application/json;charset=UTF-8' in self.headers.getlist('Content-Type'):
body = body.decode()
pass
self._body = body
return self._body
class GzipRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
request = GzipRequest(request.scope, request.receive)
return await original_route_handler(request)
return custom_route_handler
def register_gzip_request(router: APIRouter):
router.route_class = GzipRoute
pass
def register_gzip_response(app: FastAPI):
app.add_middleware(GZipMiddleware)
pass
def gzip_zip(content):
bytes_com = gzip.compress(str(content).encode('utf-8'))
# base64_data = base64.b64encode(bytes_com)
# back = base64_data.decode()
return bytes_com
def gzip_unzip(content):
if content:
# base64_data = base64.b64decode(content)
bytes_decom = gzip.decompress(content)
str_unzip = bytes_decom.decode()
return str_unzip
else:
return None
+21
View File
@@ -0,0 +1,21 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
def register_cors(app: FastAPI):
"""
支持跨域
:param app:
:return:
"""
app.add_middleware(
CORSMiddleware,
# allow_origins = ["http://127.0.0.1:25252"],
# allow_origin_regex='https?://(127.0.0.1|localhost|.*.skycity.top|.*.dnftools.com):?.*', # 改成用正则就行了
# 改成用正则就行了
allow_origin_regex='https?://(127.0.0.1|localhost|.*.dnftools.com|.*.dcalc.cn):?.*',
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
+22
View File
@@ -0,0 +1,22 @@
import json
from api.core.Gzip import gzip_zip, gzip_unzip
def get_redis_info(redis, key, fun,without_gzip=False):
info = None
if redis:
try:
if without_gzip:
info = json.loads(redis.get(key))
else:
info = json.loads(gzip_unzip(redis.get(key)))
except Exception as ex:
print(ex)
info = None
if info is None:
info = fun()
if redis and info is not None:
if without_gzip:
redis.set(key, json.dumps(info))
else:
redis.set(key, gzip_zip(json.dumps(info)))
return info
+41
View File
@@ -0,0 +1,41 @@
import base64
import json
from typing import Generic, TypeVar, Union
from pydantic.generics import GenericModel
import gzip # 导入 gzip 模块
from io import BytesIO # 从 io 模块导入 BytesIO 类
T = TypeVar('T')
class Return(GenericModel, Generic[T]):
code: int = 200
message: str = ''
data: Union[T, dict, str] = None
# 定义一个函数,将字符串压缩为 gzip 格式,并进行 base64 编码后返回结果
def gzip_str(to_gzip: str) -> str:
out = BytesIO() # 创建一个 BytesIO 对象
with gzip.GzipFile(fileobj=out, mode='w') as f: # 使用 gzip 对象进行数据压缩
f.write(to_gzip.encode()) # 将待压缩的字符串写入 gzip 对象中
return base64.b64encode(out.getvalue()).decode() # 对压缩后的数据使用 base64 编码并返回结果
def response(*, code=200, data: Union[list, dict, str], message='Success', zip=False):
if zip:
import gzip
data = base64.b64encode(gzip.compress(json.dumps(data).encode()))
return Return(code=code, message=message, data=data)
def success(data=None, msg=''):
"""成功返回格式"""
return response(200, msg, data)
def fail(code=-1, msg='', data=None):
"""失败返回格式"""
return response(code, msg, data)
View File
+2
View File
@@ -0,0 +1,2 @@
class ResponseException(Exception):
pass
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
from typing import Annotated
from redis import Redis
from sqlalchemy.orm import Session
from fastapi import Depends
from database.connect import get_db,get_redis
SessionDep = Annotated[Session, Depends(get_db)]
RedisDep = Annotated[Redis, Depends(get_redis)]
+8
View File
@@ -0,0 +1,8 @@
from fastapi import APIRouter
from api.routes import info
api_router = APIRouter()
api_router.include_router(info.router,prefix="/api",tags=["info"])
View File
+41
View File
@@ -0,0 +1,41 @@
from api.core.Auth import createToken
from api.core.Gzip import register_gzip_request
import json
from fastapi import APIRouter,Request
from api.core.Response import Return, response
from api.core.Redis import get_redis_info
from api.dp import RedisDep
router = APIRouter()
register_gzip_request(router)
@router.get('/adventure')
async def get_adventure_info(request: Request,redis:RedisDep):
def get_adventure():
with open('./dataFiles/adventure-info.json', encoding='utf-8') as fp:
return json.load(fp)
adventure_info = get_redis_info(redis, 'dcalc:adventure', get_adventure)
return response(data=adventure_info)
@router.get('/equipment/list')
async def get_equipment_list(request: Request,redis:RedisDep):
def get_equipment_list():
with open('./dataFiles/equipment-list.json', encoding='utf-8') as fp:
return json.load(fp)
equipment_list = get_redis_info(redis, 'dcalc:equipment', get_equipment_list)
return response(data=equipment_list)
@router.get("/token/get/{alter}", response_model=Return[str])
async def getToken(
alter: str, request: Request, version: str = None, equVersion: str = ""
):
if version is not None and version != "default" and version != "":
alter = version + "." + alter
token = createToken(
alter, equVersion, redis=request.app.state.redis, env=request.app.state.env
)
return response(data=token)
View File