diff --git a/.gitignore b/.gitignore index 41fb1b2..9cddce0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ config.toml debug_cmd.lst venv -log.log \ No newline at end of file +log.log +*.bak diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fe3ea90 --- /dev/null +++ b/Dockerfile @@ -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 diff --git a/config.toml.sample b/config.toml.full similarity index 96% rename from config.toml.sample rename to config.toml.full index 323b5af..868b3da 100644 --- a/config.toml.sample +++ b/config.toml.full @@ -4,7 +4,6 @@ runmode = "webapi" host = "127.0.0.1" port = 3032 [[limit]] -enable = true speed = 5 wait100ms = 6000 wait1s = 8000 diff --git a/config.toml.template b/config.toml.template new file mode 100644 index 0000000..87d3847 --- /dev/null +++ b/config.toml.template @@ -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 = "" +dbname = "myjsondb" +minsize = 100 +maxsize = 100 diff --git a/config/.keep b/config/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/config.py b/src/config.py index d135e5b..f2134d3 100644 --- a/src/config.py +++ b/src/config.py @@ -1,9 +1,18 @@ 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) -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") LOGLEVEL: str = configs.get("log", {}).get("level", "info") @@ -11,27 +20,34 @@ if (LOGLEVEL not in ["debug", "info", "warning", "err"]): LOGLEVEL = "info" OUTPUT_COLORFUL: bool = configs.get("log", {}).get("color", True) -DB_SERVER: str = configs.get("db", {}).get("host", "127.0.0.1") -DB_PORT: int = configs.get("db", {}).get("port", 3306) -DB_USER: str = configs.get("db", {}).get("user", "root") -DB_PASSWD: str = configs.get("db", {}).get("passwd", "") -DB_NAME: str = configs.get("db", {}).get("dbname", "myjsonDB") -DB_MINSIZE: str = configs.get("db", {}).get("minsize", 10) -DB_MAXSIZE: str = configs.get("db", {}).get("maxsize", 50) +DB_SERVER: str = str(os.environ.get("MYJSONDB_DB_HOST", None) + or configs.get("db", {}).get("host", "127.0.0.1")) +DB_PORT: int = int(os.environ.get("MYJSONDB_DB_PORT", None) + or configs.get("db", {}).get("port", 3306)) +DB_USER: str = str(os.environ.get("MYJSONDB_DB_USER", None) + or configs.get("db", {}).get("user", "root")) +DB_PASSWD: str = str(os.environ.get("MYJSONDB_DB_PASSWD", None) + or configs.get("db", {}).get("passwd", "")) +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) SIGTERM_CMD: bool = configs.get("console", {}).get("softstop", True) -API_HOST: str = configs.get("webapi", {}).get("host", "127.0.0.1") -API_PORT: int = configs.get("webapi", {}).get("port", 3032) +API_HOST: str = str(os.environ.get("MYJSONDB_API_HOST", None) + 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( "limit", {}).get("speed", 5) LIM_WAIT100MS: int = configs.get("webapi", {}).get( - "limit", {}).get("wait1ms", 100) + "limit", {}).get("wait1ms", 10000) LIM_WAIT1S: int = configs.get("webapi", {}).get( - "limit", {}).get("wait1s", 200) + "limit", {}).get("wait1s", 20000) LIM_WAIT10S: int = configs.get("webapi", {}).get( - "limit", {}).get("wait10s", 300) + "limit", {}).get("wait10s", 50000) diff --git a/src/core.py b/src/core.py index bf35968..f8f0966 100644 --- a/src/core.py +++ b/src/core.py @@ -370,35 +370,35 @@ async def create_key(dbname: str, name: str, key: str | int | tuple, vl: Any) -> if (vl 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) if res is None or res.group() != 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) if res is None or res.group() != 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) if checks == None: - return (3, "Other error") + return (3, "Other error", 1) elif checks == False: await log.warn("Unknown table: "+str(name)) - return (4, "Unknown table: "+str(name)) + return (4, "Unknown table: "+str(name), 1) async def callback(): - return (0, None) + return (0, None, 1) async def err_callback(err_info): if (".PRIMARY" in err_info): await log.warn("Duplicate key: "+str(key)) - return (5, "Duplicate key: "+str(key)) + return (5, "Duplicate key: "+str(key), 1) else: 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, command=f""" 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: """ - ## Change a key. + ## Create or change a key. @return: True(created) | False(not create) | None(error) """ await log.info("Change key in '"+str(name)+"."+str(dbname)+"'") @@ -549,34 +549,33 @@ 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) if res is None or res.group() != 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) if res is None or res.group() != 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) if checks == None: await log.warn("Other error") - return (3, "Other error") + return (3, "Other error", 0) elif checks == False: - await log.warn("Unknown key: "+str(name)) - return (4, "Unknown key: "+str(name)) + return await create_key(dbname, name, key, vl) + else: + async def callback(): + return (0, None, 0) - async def callback(): - return (0, None) - - async def err_callback(err_info): - await log.warn("Other error on change key: "+str(err_info)) - return (5, "Other error on change key: "+str(err_info)) - return await sqllink.execute_cmd(connects, - command=f""" - UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""", - args=(pickle.dumps(vl), str(key)), - commit=True, - callback=callback, - err_callback=err_callback) + async def err_callback(err_info): + await log.warn("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, + command=f""" + UPDATE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` SET `value`=%s WHERE `key`=%s;""", + 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: diff --git a/src/web/ezapi.py b/src/web/ezapi.py index af27ed9..68ba503 100644 --- a/src/web/ezapi.py +++ b/src/web/ezapi.py @@ -91,7 +91,7 @@ async def list_key(database_name: str, table_name: str): 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 check_key(database_name: str, table_name: str, key_name: int | str): await reqlim.get_req() ret = await core.check_key(database_name, table_name, key_name) @@ -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) -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() if (data.data is None): 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): - return {"status": 200} - return {"status": 400+ret[0], "errormsg": ret[1]} + return {"status": 200, "create": bool(ret[2])} + 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) @@ -127,8 +127,8 @@ async def update_key(database_name: str, table_name: str, key_name: int | str, d return {"status": 400, "errormsg": "No data"} ret = await core.change_key(database_name, table_name, key_name, data.data) if (ret[0] == 0): - return {"status": 200} - return {"status": 400+ret[0], "errormsg": ret[1]} + return {"status": 200, "create": bool(ret[2])} + 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)