Compare commits

..

2 Commits

Author SHA1 Message Date
cxykevin 9736564aab 完成docker部署 2024-07-22 09:03:45 +08:00
cxykevin 8e22ccee40 规范化ezapi 2024-07-18 16:35:05 +08:00
8 changed files with 96 additions and 56 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ config.toml
debug_cmd.lst debug_cmd.lst
venv venv
log.log log.log
*.bak

11
Dockerfile Normal file
View File

@ -0,0 +1,11 @@
FROM python:3.12.4
WORKDIR /myjsondb
RUN python3 -m pip install aiomysql fastapi cryptography -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY ./src /myjsondb/src
COPY ./main.py /myjsondb
COPY ./config.toml.template /myjsondb
RUN mkdir /myjsondb/config
CMD python3 main.py

View File

@ -4,7 +4,6 @@ runmode = "webapi"
host = "127.0.0.1" host = "127.0.0.1"
port = 3032 port = 3032
[[limit]] [[limit]]
enable = true
speed = 5 speed = 5
wait100ms = 6000 wait100ms = 6000
wait1s = 8000 wait1s = 8000

14
config.toml.template Normal file
View File

@ -0,0 +1,14 @@
runmode = "webapi"
[webapi]
host = "127.0.0.1"
port = 3032
[db]
host = "127.0.0.1"
port = 3306
user = "myjsondb"
passwd = "<your passwd>"
dbname = "myjsondb"
minsize = 100
maxsize = 100

0
config/.keep Normal file
View File

View File

@ -1,9 +1,18 @@
import tomllib import tomllib
import os
import shutil
import sys
with open("config.toml", 'rb') as file: if (not os.path.exists("config/config.toml")):
shutil.copyfile("./config.toml.template", "./config/config.toml")
print("Init config. Please config mysql server info.")
sys.exit(0)
with open("config/config.toml", 'rb') as file:
configs: dict = tomllib.load(file) configs: dict = tomllib.load(file)
RUN_MODE: bool = configs.get("runmode", "webapi") RUN_MODE: str = str(os.environ.get("MYJSONDB_RUNMODE", None)
or configs.get("runmode", "webapi"))
LOGPATH: str = configs.get("log", {}).get("path", "log.log") LOGPATH: str = configs.get("log", {}).get("path", "log.log")
LOGLEVEL: str = configs.get("log", {}).get("level", "info") LOGLEVEL: str = configs.get("log", {}).get("level", "info")
@ -11,27 +20,34 @@ if (LOGLEVEL not in ["debug", "info", "warning", "err"]):
LOGLEVEL = "info" LOGLEVEL = "info"
OUTPUT_COLORFUL: bool = configs.get("log", {}).get("color", True) OUTPUT_COLORFUL: bool = configs.get("log", {}).get("color", True)
DB_SERVER: str = configs.get("db", {}).get("host", "127.0.0.1") DB_SERVER: str = str(os.environ.get("MYJSONDB_DB_HOST", None)
DB_PORT: int = configs.get("db", {}).get("port", 3306) or configs.get("db", {}).get("host", "127.0.0.1"))
DB_USER: str = configs.get("db", {}).get("user", "root") DB_PORT: int = int(os.environ.get("MYJSONDB_DB_PORT", None)
DB_PASSWD: str = configs.get("db", {}).get("passwd", "<no password>") or configs.get("db", {}).get("port", 3306))
DB_NAME: str = configs.get("db", {}).get("dbname", "myjsonDB") DB_USER: str = str(os.environ.get("MYJSONDB_DB_USER", None)
DB_MINSIZE: str = configs.get("db", {}).get("minsize", 10) or configs.get("db", {}).get("user", "root"))
DB_MAXSIZE: str = configs.get("db", {}).get("maxsize", 50) DB_PASSWD: str = str(os.environ.get("MYJSONDB_DB_PASSWD", None)
or configs.get("db", {}).get("passwd", "<no password>"))
DB_NAME: str = str(os.environ.get("MYJSONDB_DB_DBNAME", None)
or configs.get("db", {}).get("dbname", "myjsonDB"))
DB_MINSIZE: int = int(os.environ.get("MYJSONDB_DB_MINSIZE", None)
or configs.get("db", {}).get("minsize", 5))
DB_MAXSIZE: int = int(os.environ.get("MYJSONDB_DB_MAXSIZE", None)
or configs.get("db", {}).get("maxsize", 10))
USE_EMACE_MOD: bool = configs.get("console", {}).get("emacsmode", True) USE_EMACE_MOD: bool = configs.get("console", {}).get("emacsmode", True)
SIGTERM_CMD: bool = configs.get("console", {}).get("softstop", True) SIGTERM_CMD: bool = configs.get("console", {}).get("softstop", True)
API_HOST: str = configs.get("webapi", {}).get("host", "127.0.0.1") API_HOST: str = str(os.environ.get("MYJSONDB_API_HOST", None)
API_PORT: int = configs.get("webapi", {}).get("port", 3032) or configs.get("webapi", {}).get("host", "0.0.0.0"))
API_PORT: int = int(os.environ.get("MYJSONDB_API_PORT", None)
or configs.get("webapi", {}).get("port", 3032))
LIM_ENABLE: bool = configs.get("webapi", {}).get(
"limit", {}).get("enable", True)
LIM_SPEED: int = configs.get("webapi", {}).get( LIM_SPEED: int = configs.get("webapi", {}).get(
"limit", {}).get("speed", 5) "limit", {}).get("speed", 5)
LIM_WAIT100MS: int = configs.get("webapi", {}).get( LIM_WAIT100MS: int = configs.get("webapi", {}).get(
"limit", {}).get("wait1ms", 100) "limit", {}).get("wait1ms", 10000)
LIM_WAIT1S: int = configs.get("webapi", {}).get( LIM_WAIT1S: int = configs.get("webapi", {}).get(
"limit", {}).get("wait1s", 200) "limit", {}).get("wait1s", 20000)
LIM_WAIT10S: int = configs.get("webapi", {}).get( LIM_WAIT10S: int = configs.get("webapi", {}).get(
"limit", {}).get("wait10s", 300) "limit", {}).get("wait10s", 50000)

View File

@ -370,35 +370,35 @@ async def create_key(dbname: str, name: str, key: str | int | tuple, vl: Any) ->
if (vl is None): if (vl is None):
await log.warn("Value is None") await log.warn("Value is None")
return (6, "Value is None") return (6, "Value is None", 1)
res = re.search(r'[0-9A-Za-z_]{2,20}', dbname) res = re.search(r'[0-9A-Za-z_]{2,20}', dbname)
if res is None or res.group() != dbname: if res is None or res.group() != dbname:
await log.warn("Database name error: "+str(dbname)) await log.warn("Database name error: "+str(dbname))
return (1, "Database name error: "+str(dbname)) return (1, "Database name error: "+str(dbname), 1)
res = re.search(r'[0-9A-Za-z_]{2,20}', name) res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name: if res is None or res.group() != name:
await log.warn("Create key table name error: "+str(name)) await log.warn("Create key table name error: "+str(name))
return (2, "Create key table name error: "+str(name)) return (2, "Create key table name error: "+str(name), 1)
checks = await check_table(dbname, name) checks = await check_table(dbname, name)
if checks == None: if checks == None:
return (3, "Other error") return (3, "Other error", 1)
elif checks == False: elif checks == False:
await log.warn("Unknown table: "+str(name)) await log.warn("Unknown table: "+str(name))
return (4, "Unknown table: "+str(name)) return (4, "Unknown table: "+str(name), 1)
async def callback(): async def callback():
return (0, None) return (0, None, 1)
async def err_callback(err_info): async def err_callback(err_info):
if (".PRIMARY" in err_info): if (".PRIMARY" in err_info):
await log.warn("Duplicate key: "+str(key)) await log.warn("Duplicate key: "+str(key))
return (5, "Duplicate key: "+str(key)) return (5, "Duplicate key: "+str(key), 1)
else: else:
await log.warn("Other error on create key: "+str(err_info)) await log.warn("Other error on create key: "+str(err_info))
return (5, "Other error on create key: "+str(err_info)) return (5, "Other error on create key: "+str(err_info), 1)
return await sqllink.execute_cmd(connects, return await sqllink.execute_cmd(connects,
command=f""" command=f"""
INSERT INTO `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}`( INSERT INTO `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}`(
@ -541,7 +541,7 @@ async def remove_key(dbname: str, name: str, key: str | int | tuple) -> Any | No
async def change_key(dbname: str, name: str, key: str | int | tuple, vl: Any) -> Any | None: async def change_key(dbname: str, name: str, key: str | int | tuple, vl: Any) -> Any | None:
""" """
## Change a key. ## Create or change a key.
@return: True(created) | False(not create) | None(error) @return: True(created) | False(not create) | None(error)
""" """
await log.info("Change key in '"+str(name)+"."+str(dbname)+"'") await log.info("Change key in '"+str(name)+"."+str(dbname)+"'")
@ -549,27 +549,26 @@ async def change_key(dbname: str, name: str, key: str | int | tuple, vl: Any) ->
res = re.search(r'[0-9A-Za-z_]{2,20}', dbname) res = re.search(r'[0-9A-Za-z_]{2,20}', dbname)
if res is None or res.group() != dbname: if res is None or res.group() != dbname:
await log.warn("Database name error: "+str(dbname)) await log.warn("Database name error: "+str(dbname))
return (1, "Database name error: "+str(dbname)) return (1, "Database name error: "+str(dbname), 0)
res = re.search(r'[0-9A-Za-z_]{2,20}', name) res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name: if res is None or res.group() != name:
await log.warn("Change key table name error: "+str(name)) await log.warn("Change key table name error: "+str(name))
return (2, "Change key table name error: "+str(name)) return (2, "Change key table name error: "+str(name), 0)
checks = await check_key(dbname, name, key) checks = await check_key(dbname, name, key)
if checks == None: if checks == None:
await log.warn("Other error") await log.warn("Other error")
return (3, "Other error") return (3, "Other error", 0)
elif checks == False: elif checks == False:
await log.warn("Unknown key: "+str(name)) return await create_key(dbname, name, key, vl)
return (4, "Unknown key: "+str(name)) else:
async def callback(): async def callback():
return (0, None) return (0, None, 0)
async def err_callback(err_info): async def err_callback(err_info):
await log.warn("Other error on change key: "+str(err_info)) await log.warn("Other error on change key: "+str(err_info))
return (5, "Other error on change key: "+str(err_info)) return (5, "Other error on change key: "+str(err_info), 0)
return await sqllink.execute_cmd(connects, return await sqllink.execute_cmd(connects,
command=f""" command=f"""
UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""", UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""",

View File

@ -56,7 +56,7 @@ async def list_table(database_name: str):
@app.get("/api/"+version+"/database/{database_name}/table/{table_name}", status_code=200) @app.get("/api/"+version+"/database/{database_name}/table/{table_name}", status_code=200)
async def check_database(database_name: str, table_name: str): async def check_table(database_name: str, table_name: str):
await reqlim.get_req() await reqlim.get_req()
ret = await core.check_table(database_name, table_name) ret = await core.check_table(database_name, table_name)
if (ret is not None): if (ret is not None):
@ -91,8 +91,8 @@ async def list_key(database_name: str, table_name: str):
return {"status": 400, "errormsg": "Unknown Error"} return {"status": 400, "errormsg": "Unknown Error"}
@app.get("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}/check", status_code=200) @app.head("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200)
async def create_key(database_name: str, table_name: str, key_name: int | str): async def check_key(database_name: str, table_name: str, key_name: int | str):
await reqlim.get_req() await reqlim.get_req()
ret = await core.check_key(database_name, table_name, key_name) ret = await core.check_key(database_name, table_name, key_name)
if (ret is not None): if (ret is not None):
@ -101,14 +101,14 @@ async def create_key(database_name: str, table_name: str, key_name: int | str):
@app.post("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200) @app.post("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200)
async def create_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem): async def create_or_change_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem): # will remove
await reqlim.get_req() await reqlim.get_req()
if (data.data is None): if (data.data is None):
return {"status": 400, "errormsg": "No data"} return {"status": 400, "errormsg": "No data"}
ret = await core.create_key(database_name, table_name, key_name, data.data) ret = await core.change_key(database_name, table_name, key_name, data.data)
if (ret[0] == 0): if (ret[0] == 0):
return {"status": 200} return {"status": 200, "create": bool(ret[2])}
return {"status": 400+ret[0], "errormsg": ret[1]} return {"status": 400+ret[0], "errormsg": ret[1], "create": bool(ret[2])}
@app.delete("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200) @app.delete("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200)
@ -121,18 +121,18 @@ async def delete_key(database_name: str, table_name: str, key_name: int | str):
@app.patch("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200) @app.patch("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200)
async def create_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem): async def update_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem):
await reqlim.get_req() await reqlim.get_req()
if (data.data is None): if (data.data is None):
return {"status": 400, "errormsg": "No data"} return {"status": 400, "errormsg": "No data"}
ret = await core.change_key(database_name, table_name, key_name, data.data) ret = await core.change_key(database_name, table_name, key_name, data.data)
if (ret[0] == 0): if (ret[0] == 0):
return {"status": 200} return {"status": 200, "create": bool(ret[2])}
return {"status": 400+ret[0], "errormsg": ret[1]} return {"status": 400+ret[0], "errormsg": ret[1], "create": bool(ret[2])}
@app.get("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200) @app.get("/api/"+version+"/database/{database_name}/table/{table_name}/key/{key_name}", status_code=200)
async def create_key(database_name: str, table_name: str, key_name: int | str): async def get_key(database_name: str, table_name: str, key_name: int | str):
await reqlim.get_req() await reqlim.get_req()
ret = await core.get_key(database_name, table_name, key_name) ret = await core.get_key(database_name, table_name, key_name)
if (ret is not None): if (ret is not None):