fastapi / src /fileservice.py
Beracles's picture
update
08cd4f3
raw
history blame
4.8 kB
from fastapi import APIRouter
from pgsoft.pgdate.date_utils import beijing
from pgsoft.pghash.md5 import md5
import pgsoft.pgfile as pgfile
from time import sleep
import json
import os
router = APIRouter(prefix="/file", tags=["File Service"])
dataset_id = "pgsoft/game"
tempdir = "game"
pgai_code = os.environ.get("pgai_code")
db_token = os.environ.get("db_token")
if db_token:
print(db_token[:5])
@router.get("/download")
def download_file(game: str, token: str, gamecode: str):
if token != pgai_code:
print(f"[{beijing()}][download file] failed")
return {"status": "Failure", "detail": "Invalid token"}
game = game.strip().lower()
filename = gamecode.strip() + ".json"
remotepath = "/".join([game, filename[:2], filename])
res = pgfile.download(
dataset_id,
remotepath=remotepath,
repo_type="dataset",
localdir=tempdir,
token=db_token,
)
if not res:
print(f"[{beijing()}][download file] failed")
return {"status": "Failure", "detail": "File not found or server error"}
with open(res, "r") as f:
outp = json.load(f)
print(f"[{beijing()}][download file] OK")
return {"status": "OK", "result": outp}
@router.post("/upload")
def upload_file(game: str, token: str, content: str):
if token != pgai_code:
print(f"[{beijing()}][upload file] failed")
return {"status": "Failure", "detail": "Invalid token"}
game = game.strip().lower()
try:
content_dict = json.loads(content)
except json.JSONDecodeError as e:
print(f"[{beijing()}][upload file] failed, {type(e)}: {e}")
return {"status": "Failure", "detail": "Invalid JSON"}
if not isinstance(content_dict, dict):
print(f"[{beijing()}][upload file] failed, not a dict")
return {"status": "Failure", "detail": "not a dict"}
needed_keys = ["game-file", "device-id"]
for key in needed_keys:
if key not in content_dict:
print(f'[{beijing()}][upload file] failed, missed "{key}"')
return {"status": "Failure", "detail": f'missed "{key}"'}
if not isinstance(content_dict["device-id"], str):
print(f'[{beijing()}][upload file] failed, "device-id" is not a str')
return {"status": "Failure", "detail": '"device-id" is not a str'}
if not isinstance(content_dict["game-file"], dict):
print(f'[{beijing()}][upload file] failed, "game-file" is not a dict')
return {"status": "Failure", "detail": '"game-file" is not a dict'}
obj = {
"upload-time": beijing().__str__(),
"game-file": content_dict["game-file"],
}
maxtry = 5
for retry in range(maxtry):
md5code = md5(obj)
remotepath = "/".join([game, md5code[:2], md5code + ".json"])
if not pgfile.api.file_exists(
repo_id=dataset_id,
filename=remotepath,
repo_type="dataset",
token=db_token,
):
break
sleep(0.1)
obj["upload-time"] = beijing().__str__()
maxtry -= 1
if not maxtry and pgfile.api.file_exists(
repo_id=dataset_id,
filename=remotepath,
repo_type="dataset",
token=db_token,
):
print(f"[{beijing()}][upload file] failed, timeout, please retry")
return {"status": "Failure", "detail": "timeout, please retry"}
filedir = os.path.join(tempdir, game, md5code[:2])
if not os.path.exists(filedir):
os.makedirs(filedir)
filepath = os.path.join(filedir, md5code + ".json")
content_indented = json.dumps(content_dict, indent=4)
with open(filepath, "w") as f:
f.write(content_indented)
res = pgfile.upload(
filepath,
remotepath,
dataset_id,
"dataset",
db_token,
f"Updated at {beijing()}",
)
if not res:
print(f"[{beijing()}][upload file] failed")
return {"status": "Failure", "detail": "server error"}
print(f"[{beijing()}][upload file] OK")
return {"status": "OK", "result": md5code}
@router.get("/list")
def list_files(game: str, token: str):
if token != pgai_code:
print(f"[{beijing()}][list files] failed")
return {"status": "Failure", "detail": "Invalid token"}
game = game.strip().lower()
games = pgfile.list_files(
repo_id=dataset_id,
repo_type="dataset",
token=db_token,
)
if games is None:
print(f"[{beijing()}][list files] failed")
return {"status": "Failure", "detail": "server error"}
games = {
item.split(".")[0][-32:]: item
for item in games
if item.endswith(".json") and item.startswith(game)
}
print(f"[{beijing()}][list files] OK")
return {"status": "OK", "result": games}