feat: 重构
This commit is contained in:
BIN
backend/data.db
Normal file
BIN
backend/data.db
Normal file
Binary file not shown.
@@ -1,14 +1,36 @@
|
||||
import json
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, HTTPException, Query
|
||||
from peewee import SqliteDatabase, Model, CharField, TextField
|
||||
|
||||
from fastapi import FastAPI
|
||||
db_path = os.path.join(os.path.dirname(__file__), "data.db")
|
||||
db = SqliteDatabase(db_path)
|
||||
|
||||
from modules import example
|
||||
from modules import voxy_import
|
||||
|
||||
app = FastAPI(title="ARinera Minecraft TUI Backend")
|
||||
class BaseModel(Model):
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
app.include_router(example.router, prefix="/api/v1")
|
||||
app.include_router(voxy_import.router, prefix="/api/v1")
|
||||
|
||||
class Tool(BaseModel):
|
||||
code = CharField(max_length=4, unique=True)
|
||||
step = TextField()
|
||||
desp = TextField(default="")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
db.connect()
|
||||
db.create_tables([Tool])
|
||||
yield
|
||||
if not db.is_closed():
|
||||
db.close()
|
||||
|
||||
|
||||
app = FastAPI(title="ARinera Minecraft TUI Backend", lifespan=lifespan)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
@@ -16,6 +38,16 @@ async def health():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.get("/tools")
|
||||
async def get_tools(
|
||||
code: str = Query(..., min_length=4, max_length=4, pattern=r"^\d{4}$"),
|
||||
):
|
||||
tool = Tool.get_or_none(Tool.code == code)
|
||||
if tool is None:
|
||||
raise HTTPException(status_code=404, detail=f"code {code} not found")
|
||||
return json.loads(tool.step)
|
||||
|
||||
|
||||
def main():
|
||||
uvicorn.run("main:app", reload=True, port=3131)
|
||||
|
||||
|
||||
165
backend/manage.py
Normal file
165
backend/manage.py
Normal file
@@ -0,0 +1,165 @@
|
||||
"""AMT 数据库管理脚本 - 交互式管理 Tool 表"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from peewee import SqliteDatabase, Model, CharField, TextField
|
||||
|
||||
db_path = os.path.join(os.path.dirname(__file__), "data.db")
|
||||
db = SqliteDatabase(db_path)
|
||||
|
||||
|
||||
class BaseModel(Model):
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
|
||||
class Tool(BaseModel):
|
||||
code = CharField(max_length=4, unique=True)
|
||||
step = TextField()
|
||||
desp = TextField(default="")
|
||||
|
||||
|
||||
def init_db():
|
||||
db.connect()
|
||||
db.create_tables([Tool])
|
||||
|
||||
|
||||
def list_tools():
|
||||
tools = Tool.select().order_by(Tool.code)
|
||||
if not tools:
|
||||
print("\n (空)")
|
||||
return
|
||||
print()
|
||||
for t in tools:
|
||||
print(f" [{t.code}] {t.desp or '(无描述)'}")
|
||||
|
||||
|
||||
def show_tool():
|
||||
code = input("输入 code: ").strip()
|
||||
tool = Tool.get_or_none(Tool.code == code)
|
||||
if tool is None:
|
||||
print(f" code {code} 不存在")
|
||||
return
|
||||
print(f"\n code: {tool.code}")
|
||||
print(f" desp: {tool.desp or '(无描述)'}")
|
||||
print(f" step:")
|
||||
print(json.dumps(json.loads(tool.step), indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
def add_tool():
|
||||
code = input("输入 code (4位数字): ").strip()
|
||||
if len(code) != 4 or not code.isdigit():
|
||||
print(" code 必须是4位数字")
|
||||
return
|
||||
if Tool.get_or_none(Tool.code == code):
|
||||
print(f" code {code} 已存在,请用编辑功能修改")
|
||||
return
|
||||
|
||||
desp = input("输入描述: ").strip()
|
||||
print("输入 step JSON (输入空行结束):")
|
||||
lines = []
|
||||
while True:
|
||||
line = input()
|
||||
if line == "":
|
||||
break
|
||||
lines.append(line)
|
||||
|
||||
raw = "\n".join(lines)
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f" JSON 解析失败: {e}")
|
||||
return
|
||||
|
||||
Tool.create(code=code, step=json.dumps(parsed, ensure_ascii=False), desp=desp)
|
||||
print(f" 已添加 [{code}]")
|
||||
|
||||
|
||||
def edit_tool():
|
||||
code = input("输入要编辑的 code: ").strip()
|
||||
tool = Tool.get_or_none(Tool.code == code)
|
||||
if tool is None:
|
||||
print(f" code {code} 不存在")
|
||||
return
|
||||
|
||||
print(f" 当前描述: {tool.desp or '(无描述)'}")
|
||||
desp = input("新描述 (回车跳过): ").strip()
|
||||
if desp:
|
||||
tool.desp = desp
|
||||
|
||||
print(f" 当前 step:")
|
||||
print(json.dumps(json.loads(tool.step), indent=2, ensure_ascii=False))
|
||||
choice = input("修改 step? (y/N): ").strip().lower()
|
||||
if choice == "y":
|
||||
print("输入新的 step JSON (输入空行结束):")
|
||||
lines = []
|
||||
while True:
|
||||
line = input()
|
||||
if line == "":
|
||||
break
|
||||
lines.append(line)
|
||||
raw = "\n".join(lines)
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f" JSON 解析失败: {e}")
|
||||
return
|
||||
tool.step = json.dumps(parsed, ensure_ascii=False)
|
||||
|
||||
tool.save()
|
||||
print(f" 已更新 [{code}]")
|
||||
|
||||
|
||||
def delete_tool():
|
||||
code = input("输入要删除的 code: ").strip()
|
||||
tool = Tool.get_or_none(Tool.code == code)
|
||||
if tool is None:
|
||||
print(f" code {code} 不存在")
|
||||
return
|
||||
|
||||
print(f" [{tool.code}] {tool.desp or '(无描述)'}")
|
||||
confirm = input("确认删除? (y/N): ").strip().lower()
|
||||
if confirm == "y":
|
||||
tool.delete_instance()
|
||||
print(f" 已删除 [{code}]")
|
||||
else:
|
||||
print(" 已取消")
|
||||
|
||||
|
||||
MENU = {
|
||||
"1": ("列出所有", list_tools),
|
||||
"2": ("查看详情", show_tool),
|
||||
"3": ("添加", add_tool),
|
||||
"4": ("编辑", edit_tool),
|
||||
"5": ("删除", delete_tool),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
init_db()
|
||||
print("=== AMT 数据库管理 ===")
|
||||
while True:
|
||||
print()
|
||||
for k, (label, _) in MENU.items():
|
||||
print(f" {k}. {label}")
|
||||
print(" q. 退出")
|
||||
|
||||
choice = input("\n> ").strip().lower()
|
||||
if choice == "q":
|
||||
break
|
||||
action = MENU.get(choice)
|
||||
if action:
|
||||
try:
|
||||
action[1]()
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
else:
|
||||
print(" 无效选项")
|
||||
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,18 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter(prefix="/example", tags=["example"])
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_items():
|
||||
return {"items": ["a", "b", "c"]}
|
||||
|
||||
|
||||
@router.get("/{item_id}")
|
||||
async def get_item(item_id: int):
|
||||
return {"id": item_id, "name": f"item_{item_id}"}
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def create_item():
|
||||
return {"status": "created"}
|
||||
@@ -1,12 +0,0 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter(prefix="/voxy_import", tags=["voxy_import"])
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_urls():
|
||||
return {
|
||||
"default": "https://dav.arinera.fun/voxy.zip",
|
||||
"cf": "https://oss.arinera.space/voxy.zip",
|
||||
"test": "http://local.arinera.fun:9000/oss/voxy.zip",
|
||||
}
|
||||
@@ -6,6 +6,6 @@ readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"fastapi>=0.136.3",
|
||||
"httpx>=0.28.1",
|
||||
"peewee>=4.0.6",
|
||||
"uvicorn>=0.48.0",
|
||||
]
|
||||
|
||||
52
backend/uv.lock
generated
52
backend/uv.lock
generated
@@ -1,5 +1,5 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
revision = 2
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
@@ -8,14 +8,14 @@ version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "fastapi" },
|
||||
{ name = "httpx" },
|
||||
{ name = "peewee" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "fastapi", specifier = ">=0.136.3" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "peewee", specifier = ">=4.0.6" },
|
||||
{ name = "uvicorn", specifier = ">=0.48.0" },
|
||||
]
|
||||
|
||||
@@ -50,15 +50,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2026.5.20"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.4.1"
|
||||
@@ -105,34 +96,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.16"
|
||||
@@ -142,6 +105,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peewee"
|
||||
version = "4.0.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9f/09/a3b2a32ce498f405dce4320267e99b1b076c1ea39ad01151a353bc7f81d7/peewee-4.0.6.tar.gz", hash = "sha256:ea2f78f24ff9e3660281dc5b0be8bc00d9a9514bdc40c98e416fcd042b66ac6a", size = 724591, upload-time = "2026-05-20T13:18:17.26Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/69/6a/e1455b94ee48f5666f2e7831b6247098794bfe9747da457111be4d0bea10/peewee-4.0.6-py3-none-any.whl", hash = "sha256:5fa665913c410f0b5faef1469ed0aa9eceb9fef262665ebbb6f29408f826eeeb", size = 146222, upload-time = "2026-05-20T13:18:15.694Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.13.4"
|
||||
|
||||
Reference in New Issue
Block a user