Compare commits

..

No commits in common. "9736564aab1535bcff57e2fe9003c383f3db180a" and "087457393583400b7442b9de7bde6cf674b650a5" have entirely different histories.

8 changed files with 56 additions and 96 deletions

1
.gitignore vendored
View File

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

View File

@ -1,11 +0,0 @@
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,6 +4,7 @@ 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

View File

@ -1,14 +0,0 @@
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

View File

View File

@ -1,18 +1,9 @@
import tomllib import tomllib
import os
import shutil
import sys
if (not os.path.exists("config/config.toml")): with open("config.toml", 'rb') as file:
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: str = str(os.environ.get("MYJSONDB_RUNMODE", None) RUN_MODE: bool = configs.get("runmode", "webapi")
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")
@ -20,34 +11,27 @@ 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 = str(os.environ.get("MYJSONDB_DB_HOST", None) DB_SERVER: str = configs.get("db", {}).get("host", "127.0.0.1")
or configs.get("db", {}).get("host", "127.0.0.1")) DB_PORT: int = configs.get("db", {}).get("port", 3306)
DB_PORT: int = int(os.environ.get("MYJSONDB_DB_PORT", None) DB_USER: str = configs.get("db", {}).get("user", "root")
or configs.get("db", {}).get("port", 3306)) DB_PASSWD: str = configs.get("db", {}).get("passwd", "<no password>")
DB_USER: str = str(os.environ.get("MYJSONDB_DB_USER", None) DB_NAME: str = configs.get("db", {}).get("dbname", "myjsonDB")
or configs.get("db", {}).get("user", "root")) DB_MINSIZE: str = configs.get("db", {}).get("minsize", 10)
DB_PASSWD: str = str(os.environ.get("MYJSONDB_DB_PASSWD", None) DB_MAXSIZE: str = configs.get("db", {}).get("maxsize", 50)
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 = str(os.environ.get("MYJSONDB_API_HOST", None) API_HOST: str = configs.get("webapi", {}).get("host", "127.0.0.1")
or configs.get("webapi", {}).get("host", "0.0.0.0")) API_PORT: int = configs.get("webapi", {}).get("port", 3032)
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", 10000) "limit", {}).get("wait1ms", 100)
LIM_WAIT1S: int = configs.get("webapi", {}).get( LIM_WAIT1S: int = configs.get("webapi", {}).get(
"limit", {}).get("wait1s", 20000) "limit", {}).get("wait1s", 200)
LIM_WAIT10S: int = configs.get("webapi", {}).get( LIM_WAIT10S: int = configs.get("webapi", {}).get(
"limit", {}).get("wait10s", 50000) "limit", {}).get("wait10s", 300)

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", 1) return (6, "Value is None")
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), 1) return (1, "Database name error: "+str(dbname))
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), 1) return (2, "Create key table name error: "+str(name))
checks = await check_table(dbname, name) checks = await check_table(dbname, name)
if checks == None: if checks == None:
return (3, "Other error", 1) return (3, "Other error")
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), 1) return (4, "Unknown table: "+str(name))
async def callback(): async def callback():
return (0, None, 1) return (0, None)
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), 1) return (5, "Duplicate key: "+str(key))
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), 1) return (5, "Other error on create key: "+str(err_info))
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:
""" """
## Create or change a key. ## 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,33 +549,34 @@ 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), 0) return (1, "Database name error: "+str(dbname))
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), 0) return (2, "Change key table name error: "+str(name))
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", 0) return (3, "Other error")
elif checks == False: elif checks == False:
return await create_key(dbname, name, key, vl) await log.warn("Unknown key: "+str(name))
else: return (4, "Unknown key: "+str(name))
async def callback():
return (0, None, 0)
async def err_callback(err_info): async def callback():
await log.warn("Other error on change key: "+str(err_info)) return (0, None)
return (5, "Other error on change key: "+str(err_info), 0)
return await sqllink.execute_cmd(connects, async def err_callback(err_info):
command=f""" await log.warn("Other error on change key: "+str(err_info))
UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""", return (5, "Other error on change key: "+str(err_info))
args=(pickle.dumps(vl), str(key)), return await sqllink.execute_cmd(connects,
commit=True, command=f"""
callback=callback, UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""",
err_callback=err_callback) args=(pickle.dumps(vl), str(key)),
commit=True,
callback=callback,
err_callback=err_callback)
async def list_key(dbname: str, name: str) -> Tuple[tuple[str, Any]] | None: async def list_key(dbname: str, name: str) -> Tuple[tuple[str, Any]] | None:

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_table(database_name: str, table_name: str): async def check_database(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.head("/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}/check", status_code=200)
async def check_key(database_name: str, table_name: str, key_name: int | str): async def create_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 check_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_or_change_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem): # will remove async def create_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.create_key(database_name, table_name, key_name, data.data)
if (ret[0] == 0): if (ret[0] == 0):
return {"status": 200, "create": bool(ret[2])} return {"status": 200}
return {"status": 400+ret[0], "errormsg": ret[1], "create": bool(ret[2])} return {"status": 400+ret[0], "errormsg": ret[1]}
@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 update_key(database_name: str, table_name: str, key_name: int | str, data: KeyItem): async def create_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, "create": bool(ret[2])} return {"status": 200}
return {"status": 400+ret[0], "errormsg": ret[1], "create": bool(ret[2])} return {"status": 400+ret[0], "errormsg": ret[1]}
@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 get_key(database_name: str, table_name: str, key_name: int | str): async def create_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):