Origin commit

This commit is contained in:
cxykevin 2024-07-14 20:20:41 +08:00
commit 0974a12f10
13 changed files with 989 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
**/__pycache__
config.toml
debug_cmd.lst
venv

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python 调试程序: 当前文件",
"type": "debugpy",
"request": "launch",
"program": "main.py",
"console": "integratedTerminal"
}
]
}

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"python.analysis.autoImportCompletions": true,
"python.analysis.typeCheckingMode": "off"
}

21
config.toml.sample Normal file
View File

@ -0,0 +1,21 @@
runmode = "webapi"
[webapi]
host = "127.0.0.1"
port = 3032
[console]
emacsmode = true
softstop = true
[db]
host = "127.0.0.1"
port = 3306
user = "root"
passwd = "passwd"
dbname = "myjsonDB"
[log]
path = "log.log"
level = "info"
color = true

7
log.log Normal file
View File

@ -0,0 +1,7 @@
[2024-07-14 20:01:59,825][INFO] Server start
[2024-07-14 20:01:59,825][INFO] Connect database
[2024-07-14 20:01:59,854][INFO] Server version:8.2.0
[2024-07-14 20:01:59,858][INFO] Use database
[2024-07-14 20:01:59,861][INFO] start webapi
[2024-07-14 20:01:59,862][INFO] Search web plugins
[2024-07-14 20:01:59,862][INFO] + Load ezapi.py

35
main.py Normal file
View File

@ -0,0 +1,35 @@
from src import log
from src import core
from src import term
from src import config
from src import webcore
import asyncio
log.log_init()
loop = asyncio.new_event_loop()
async def start_cli():
await log.info("start cli")
await term.debug_term()
async def start_api():
await log.info("start webapi")
await webcore.start()
async def init():
await log.info("Server start")
await core.connect_realdb()
if (config.RUN_MODE == "console"):
await start_cli()
elif (config.RUN_MODE == "webapi"):
await start_api()
else:
await log.err("Unknown run mode: "+str(config.RUN_MODE))
loop.run_until_complete(init())

24
src/config.py Normal file
View File

@ -0,0 +1,24 @@
import tomllib
with open("config.toml", 'rb') as file:
configs: dict = tomllib.load(file)
RUN_MODE: bool = configs.get("runmode", "webapi")
LOGPATH: str = configs.get("log", {}).get("path", "log.log")
LOGLEVEL: str = configs.get("log", {}).get("level", "info")
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", "<no password>")
DB_NAME: str = configs.get("db", {}).get("dbname", "myjsonDB")
USE_EMACE_MOD: bool = configs.get("console", {}).get("emacsmode", True)
SIGTERM_CMD: bool = configs.get("console", {}).get("softstop", True)
API_HOST: bool = configs.get("webapi", {}).get("host", "127.0.0.1")
API_PORT: bool = configs.get("webapi", {}).get("port", 3032)

557
src/core.py Normal file
View File

@ -0,0 +1,557 @@
from src import log
from src import sqllink
from src import config
import re
import sys
import pickle
from typing import Any, Tuple
async def connect_realdb() -> None:
"""
Connect to a mysql database and save connect.
"""
global connects
await log.info("Connect database")
try:
connects = await sqllink.connect_db()
except:
await log.break_err("Connect error")
sys.exit(2)
async with connects.acquire() as conn:
await log.info("Server version:"+str(conn.server_version))
async with conn.cursor() as cursor:
await cursor.execute("SHOW TABLES LIKE 'sys_db_list';")
result = await cursor.fetchall()
if (len(result) == 0):
await log.info("Init database")
await cursor.execute("""
CREATE TABLE sys_db_list(
name VARCHAR(50) PRIMARY KEY NOT NULL
);
""")
await cursor.execute("""
CREATE TABLE sys_config(
name VARCHAR(50) PRIMARY KEY NOT NULL,
val VARCHAR(200) NOT NULL
);
""")
else:
await log.info("Use database")
async def check_jsondb(name: str) -> bool | None:
"""
Check a jsondb if it has been created.
@return: True(created) | False(not create) | None(error)
"""
await log.info("Check jsondb: "+str(name))
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Check database name error: "+str(name))
return None
async def callback(result):
if (len(result) == 0):
return False
else:
return True
async def err_callback(err_info):
await log.warn("Other error on create database: "+str(err_info))
return None
return await sqllink.execute_cmd(connects, command="SELECT * FROM sys_db_list WHERE name='"+name+"';", callback=callback, err_callback=err_callback)
async def list_jsondb() -> Tuple[str] | None:
"""
## List all jsondb(s).
@return: `tuple | None(error)`
"""
await log.info("list jsondb")
async def callback(result):
return [i[0] for i in result]
async def err_callback(err_info):
await log.warn("Other error on list databases: "+str(err_info))
return None
return await sqllink.execute_cmd(connects, command="SELECT * FROM sys_db_list;", callback=callback, err_callback=err_callback)
async def create_jsondb(name: str) -> tuple[int, str | None]:
"""
## Create a jsondb.
@return: `tuple[errorlevel:int, errormsg:str|None]`
"""
await log.info("Create jsondb: "+str(name))
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Create database name error: "+str(name))
return (1, "Name error: "+str(name))
async def callback():
return (0, None)
async def err_callback(err_info):
if ("sys_db_list.PRIMARY" in err_info):
await log.warn("Duplicate database names: "+str(name))
return (1, "Duplicate database names: "+str(name))
else:
await log.warn("Other error on create database: "+str(err_info))
return (2, "Other error: "+str(err_info))
return await sqllink.execute_cmd(connects, command="INSERT INTO sys_db_list (name) VALUES ('"+name+"');", commit=True, callback=callback, err_callback=err_callback)
async def create_table(dbname: str, name: str) -> tuple[int, str | None]:
"""
## Create a table in a jsondb.
@return: `tuple[errorlevel:int, errormsg:str|None]`
"""
await log.info("Create table '"+str(name)+"' in '"+str(dbname)+"'")
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, "DB name error"+str(dbname))
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Create table database name error: "+str(name))
return (2, "Name error: "+str(name))
checks = await check_jsondb(dbname)
if checks == None:
return (3, "Other check error")
elif checks == False:
await log.warn("Create table cannot find database: "+str(dbname))
return (3, "Cannot find database: "+str(dbname))
async def callback():
return (0, None)
async def err_callback(err_info):
if ("sys_db_list.PRIMARY" in err_info):
await log.warn("Duplicate database names: "+str(name))
return (4, "Duplicate database names: "+str(name))
else:
await log.warn("Other error on create table: "+str(err_info))
return (4, "Other error: "+str(err_info))
return await sqllink.execute_cmd(connects,
command=f"""
CREATE TABLE `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}`(
`key` VARCHAR(40) PRIMARY KEY NOT NULL,
`value` MEDIUMBLOB
);""",
commit=True, callback=callback, err_callback=err_callback)
async def list_table(dbname: str) -> Tuple[str] | None:
"""
## List all tables from a jsondb.
@return: `tuple | None(error)`
"""
await log.info("List table in: "+str(dbname))
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 None
async def callback(result):
return (i[0][len(f"user_{dbname.replace("_", "__")}_"):] for i in result)
async def err_callback(err_info):
await log.warn("Other error on list database: "+str(err_info))
return None
return await sqllink.execute_cmd(connects,
command=f"SHOW TABLES LIKE 'user_{
dbname.replace("_", "__")}_%%';",
callback=callback, err_callback=err_callback)
async def rm_jsondb(dbname: str) -> tuple[int, str | None]:
"""
## Remove a jsondb and all tables in it.
@return: `tuple[errorlevel:int, errormsg:str|None]`
"""
await log.info("Remove database in: "+str(dbname))
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, "DB name error"+str(dbname))
checks = await check_jsondb(dbname)
if checks == None:
return (2, "Other check error")
elif checks == False:
await log.warn("Create table cannot find database: "+str(dbname))
return (2, "Cannot find database: "+str(dbname))
async def callback() -> tuple[int, str | None]:
return (0, None)
async def err_callback(err_info: str) -> tuple[int, str | None]:
await log.warn("Other error on list database: "+str(err_info))
return (3, str(err_info))
await log.debug("mysql remove db")
try:
async with connects.acquire() as conn:
async with conn.cursor() as cursor: # thank for chatglm
await cursor.execute(f"""
SELECT *
FROM information_schema.tables
WHERE table_schema = '{config.DB_NAME}' AND table_name LIKE 'user_{dbname.replace("_", "__")}_%%'
""")
tables_to_drop = await cursor.fetchall()
for table_info in tables_to_drop:
await cursor.execute(f"DROP TABLE {table_info[2]};")
await conn.commit()
except Exception as exp:
return await err_callback(repr(exp))
return await sqllink.execute_cmd(connects,
command=f"DELETE FROM sys_db_list WHERE `name`='{
dbname}';",
commit=True, callback=callback, err_callback=err_callback)
async def rm_table(dbname: str, name: str) -> tuple[int, str | None]:
"""
## Remove a table.
@return: `tuple[errorlevel:int, errormsg:str|None]`
"""
await log.info("Remove table '"+str(name)+"' in '"+str(dbname)+"'")
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, "DB name error"+str(dbname))
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Create table database name error: "+str(name))
return (2, "Name error: "+str(name))
checks = await check_jsondb(dbname)
if checks == None:
return (3, "Other check error")
elif checks == False:
await log.warn("Create table cannot find database: "+str(dbname))
return (3, "Cannot find database: "+str(dbname))
async def callback():
return (0, None)
async def err_callback(err_info):
if ("Unknown table" in err_info):
await log.warn("Unknown table name: "+str(name))
return (4, "Unknown table name: "+str(name))
else:
await log.warn("Other error on create table: "+str(err_info))
return (4, "Other error: "+str(err_info))
return await sqllink.execute_cmd(connects,
command=f"DROP TABLE `user_" +
f"{dbname.replace("_", "__")}_" +
f"{name.replace("_", "__")}`;",
commit=True,
callback=callback,
err_callback=err_callback)
async def check_table(dbname: str, name: str) -> bool | None:
"""
## Check a table if it has been created.
@return: True(created) | False(not create) | None(error)
"""
await log.info("Check table '"+str(name)+"' in '"+str(dbname)+"'")
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 None
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Create table database name error: "+str(name))
return None
checks = await check_jsondb(dbname)
if checks == None:
return None
elif checks == False:
await log.warn("Create table cannot find database: "+str(dbname))
return None
async def callback(result):
if (len(result) > 0):
return True
else:
return False
async def err_callback(err_info):
await log.warn("Other error on check table: "+str(err_info))
return None
return await sqllink.execute_cmd(connects,
command=f"SHOW TABLES LIKE 'user_" +
f"{dbname.replace("_", "__")}_" +
f"{name.replace("_", "__")}';",
callback=callback,
err_callback=err_callback)
async def create_key(dbname: str, name: str, key: str | int | tuple, vl: Any) -> tuple[int, str | None]:
"""
## Create a key.
@return: `tuple[errorlevel:int, errormsg:str|None]`
"""
await log.info("Create key in '"+str(name)+"."+str(dbname)+"'")
if (vl is None):
await log.warn("Value is None")
return (6, "Value is None")
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))
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))
checks = await check_table(dbname, name)
if checks == None:
return (3, "Other error")
elif checks == False:
await log.warn("Unknown table: "+str(name))
return (4, "Unknown table: "+str(name))
async def callback():
return (0, None)
async def err_callback(err_info):
await log.warn("Other error on create key: "+str(err_info))
return (5, "Other error on create key: "+str(err_info))
return await sqllink.execute_cmd(connects,
command=f"""
INSERT INTO `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}`(
`key`,
`value`
) VALUE (
%s,
%s
)
""",
args=(str(key), pickle.dumps(vl)),
commit=True,
callback=callback,
err_callback=err_callback)
async def get_key(dbname: str, name: str, key: str | int | tuple) -> Any | None:
"""
## Get a key.
@return: `Any | None(error)`
"""
await log.info("Get key in '"+str(name)+"."+str(dbname)+"'")
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 None
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Get key table name error: "+str(name))
return None
checks = await check_table(dbname, name)
if checks == None:
await log.warn("Other error")
return None
elif checks == False:
await log.warn("Unknown table: "+str(name))
return None
async def callback(result):
if (len(result) > 0):
return pickle.loads(result[0][1])
else:
return None
async def err_callback(err_info):
await log.warn("Other error on get key: "+str(err_info))
return None
return await sqllink.execute_cmd(connects,
command=f"""
SELECT * FROM `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` WHERE `key`=%s;""",
args=(str(key),),
callback=callback,
err_callback=err_callback)
async def check_key(dbname: str, name: str, key: str | int | tuple) -> Any | None:
"""
## Check a key.
@return: True(created) | False(not create) | None(error)
"""
await log.info("Check key in '"+str(name)+"."+str(dbname)+"'")
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 None
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Check key table name error: "+str(name))
return None
checks = await check_table(dbname, name)
if checks == None:
await log.warn("Other error")
return None
elif checks == False:
await log.warn("Unknown table: "+str(name))
return None
async def callback(result):
if (len(result) > 0):
return True
else:
return False
async def err_callback(err_info):
await log.warn("Other error on check key: "+str(err_info))
return None
return await sqllink.execute_cmd(connects,
command=f"""
SELECT * FROM `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` WHERE `key`=%s;""",
args=(str(key),),
callback=callback,
err_callback=err_callback)
async def remove_key(dbname: str, name: str, key: str | int | tuple) -> Any | None:
"""
## Remove a key.
@return: True(created) | False(not create) | None(error)
"""
await log.info("Remove key in '"+str(name)+"."+str(dbname)+"'")
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))
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("Remove key table name error: "+str(name))
return (2, "Remove key table name error: "+str(name))
checks = await check_key(dbname, name, key)
if checks == None:
await log.warn("Other error")
return (3, "Other error")
elif checks == False:
await log.warn("Unknown key: "+str(key))
return (4, "Unknown key: "+str(key))
async def callback():
return (0, None)
async def err_callback(err_info):
await log.warn("Other error on remove key: "+str(err_info))
return (5, "Other error on remove key: "+str(err_info))
return await sqllink.execute_cmd(connects,
command=f"""
DELETE FROM `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}` WHERE `key`=%s;""",
args=(str(key),),
commit=True,
callback=callback,
err_callback=err_callback)
async def change_key(dbname: str, name: str, key: str | int | tuple, vl: Any) -> Any | None:
"""
## Change a key.
@return: True(created) | False(not create) | None(error)
"""
await log.info("Change key in '"+str(name)+"."+str(dbname)+"'")
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))
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))
checks = await check_key(dbname, name, key)
if checks == None:
await log.warn("Other error")
return (3, "Other error")
elif checks == False:
await log.warn("Unknown key: "+str(name))
return (4, "Unknown key: "+str(name))
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 list_key(dbname: str, name: str) -> Tuple[tuple[str, Any]] | None:
"""
## List keys.
@return: `tuple | None(error)`
"""
await log.info("List keys in '"+str(name)+"."+str(dbname)+"'")
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 None
res = re.search(r'[0-9A-Za-z_]{2,20}', name)
if res is None or res.group() != name:
await log.warn("List key table name error: "+str(name))
return None
checks = await check_table(dbname, name)
if checks == None:
await log.warn("Other error")
return None
elif checks == False:
await log.warn("Unknown table: "+str(name))
return None
async def callback(result):
return ((i[0], pickle.loads(i[1])) for i in result)
async def err_callback(err_info):
await log.warn("Other error on list key: "+str(err_info))
return None
return await sqllink.execute_cmd(connects,
command=f"""
SELECT * FROM `user_{dbname.replace("_", "__")}_{name.replace("_", "__")}`""",
callback=callback,
err_callback=err_callback)

71
src/log.py Normal file
View File

@ -0,0 +1,71 @@
# ------ cxykevin log moudle ------
import logging
import sys
from src import config
levels = {
"debug": logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARN,
'err': logging.ERROR
}
def log_init() -> None:
logging.basicConfig(filename=config.LOGPATH,
format='[%(asctime)s][%(levelname)s] %(message)s',
level=levels[config.LOGLEVEL], filemode='w')
async def info(msg: str) -> None:
if (20 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[34mINFO\033[0m]" if config.OUTPUT_COLORFUL else "[INFO]") + msg + "\n")
logging.info(msg)
async def info(msg: str) -> None:
if (20 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[34mINFO\033[0m]" if config.OUTPUT_COLORFUL else "[INFO]") + msg + "\n")
logging.info(msg)
async def warn(msg: str) -> None:
if (30 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[33mWARNING\033[0m]" if config.OUTPUT_COLORFUL else "[WARNING]") + msg + "\n")
logging.warn(msg)
async def err(msg: str) -> None:
if (40 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n")
logging.error(msg)
async def break_err(msg: str) -> None:
if (40 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n")
logging.error(msg)
async def debug(*args, end="\n") -> None:
msg = ' '.join(map(str, args))
if (10 >= levels[config.LOGLEVEL]):
sys.stdout.write(
("[\033[32mDEBUG\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + end)
logging.debug(msg)
async def print(*args, end="\n") -> None:
msg = ' '.join(map(str, args))
if (10 >= levels[config.LOGLEVEL]):
sys.stdout.write(msg + end)
logging.debug(msg)
async def trace_sys(msg: str) -> None:
logging.info(msg)

54
src/sqllink.py Normal file
View File

@ -0,0 +1,54 @@
from src import log
from src import config
import aiomysql
import traceback
import textwrap
from typing import Any, Callable
async def connect_db() -> aiomysql.pool.Pool:
"""
Connect to a mysql database.
@return: Pool(aiomysql.pool.Pool)
"""
try:
connects = await aiomysql.create_pool(
host=config.DB_SERVER,
port=config.DB_PORT,
user=config.DB_USER,
password=config.DB_PASSWD,
db=config.DB_NAME
)
except Exception as exp:
await log.err("Connect MYSQL server error")
await log.err(repr(exp))
for i in traceback.format_exc().split("\n"):
firstlen_flag = "* "
lastlen = ""
for j in textwrap.wrap(i, width=60):
await log.err(" "+firstlen_flag+" " *
(len(lastlen)-len(lastlen.lstrip()))+j)
lastlen = " " * (len(lastlen)-len(lastlen.lstrip()))+j
firstlen_flag = " "
raise
return connects
async def execute_cmd(connects: aiomysql.pool.Pool, command: str, callback: Callable[..., Any] = lambda: None, commit=False, args: list | tuple = [], err_callback: Callable[[str], Any] = lambda err: log.warn("Default execute error: "+str(err))) -> Any:
"""
Execute a sql command on mysql database.
Return from callback function.
"""
await log.debug("mysql> "+command+" "+str(args))
try:
async with connects.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute(command, args)
if (commit):
await conn.commit()
return await callback()
else:
result = await cursor.fetchall()
return await callback(result)
except Exception as exp:
return await err_callback(repr(exp))

147
src/term.py Normal file
View File

@ -0,0 +1,147 @@
from src import core
import sys
import readline
import asyncio
from src import config
import signal
async def do_cmd(cmd: str) -> None:
"""
Do a command.
Only for debug.
"""
args = cmd.split(" ")
match args[0]:
case "mkdb":
if (len(args) != 2):
sys.stderr.write("* dbname\n")
else:
ret = await core.create_jsondb(args[1])
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "checkdb":
if (len(args) != 2):
sys.stderr.write("* dbname\n")
else:
ret = await core.check_jsondb(args[1])
sys.stdout.write(str(ret)+"\n")
case "lsdb":
if (len(args) != 1):
sys.stderr.write("no args\n")
else:
ret = await core.list_jsondb()
if (ret is not None):
for i in ret:
sys.stdout.write("+ "+str(i)+"\n")
case "rmdb":
if (len(args) != 2):
sys.stderr.write("* dbname\n")
else:
ret = await core.rm_jsondb(args[1])
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "mktable":
if (len(args) != 3):
sys.stderr.write("* dbname\n* tablename\n")
else:
ret = await core.create_table(args[1], args[2])
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "lstable":
if (len(args) != 2):
sys.stderr.write("* dbname\n")
else:
ret = await core.list_table(args[1])
if (ret is not None):
for i in ret:
sys.stdout.write("+ "+str(i)+"\n")
case "rmtable":
if (len(args) != 3):
sys.stderr.write("* dbname\n* tablename\n")
else:
ret = await core.rm_table(args[1], args[2])
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "checktable":
if (len(args) != 3):
sys.stderr.write("* dbname\n* tablename\n")
else:
ret = await core.check_table(args[1], args[2])
sys.stdout.write(str(ret)+"\n")
case "ckey":
if (len(args) != 5):
sys.stderr.write(
"* dbname\n* tablename\n* key\n* value(eval)\n")
else:
ret = await core.create_key(args[1], args[2], args[3], eval(args[4]))
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "gkey":
if (len(args) != 4):
sys.stderr.write("* dbname\n* tablename\n* key\n")
else:
ret = await core.get_key(args[1], args[2], args[3])
sys.stdout.write(repr(ret)+"\n")
case "ikey":
if (len(args) != 4):
sys.stderr.write("* dbname\n* tablename\n* key\n")
else:
ret = await core.check_key(args[1], args[2], args[3])
sys.stdout.write(repr(ret)+"\n")
case "rkey":
if (len(args) != 4):
sys.stderr.write("* dbname\n* tablename\n* key\n")
else:
ret = await core.remove_key(args[1], args[2], args[3])
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "ekey":
if (len(args) != 5):
sys.stderr.write(
"* dbname\n* tablename\n* key\n* value(eval)\n")
else:
ret = await core.change_key(args[1], args[2], args[3], eval(args[4]))
if (ret[0] != 0):
sys.stderr.write("err: "+str(ret[1])+'\n')
case "lskey":
if (len(args) != 3):
sys.stderr.write("* dbname\n* tablename\n")
else:
ret = await core.list_key(args[1], args[2])
if (ret is not None):
for i in ret:
sys.stdout.write("+ "+str(i[0])+"="+str(i[1])+"\n")
case "help":
if (len(args) != 1):
sys.stderr.write("no args\n")
else:
sys.stderr.write(
"mkdb lsdb checkdb rmdb mktable lstable rmtable checktable ckey gkey rkey ekey lskey\n")
case "exit":
sys.stderr.write("Bye\n")
sys.exit(0)
case _:
sys.stderr.write("Unknown command\n")
async def debug_term() -> None:
"""
Start a command line.
Only for debug.
"""
if (config.USE_EMACE_MOD):
readline.parse_and_bind('tab: complete')
readline.parse_and_bind('set editing-mode emacs')
if (config.SIGTERM_CMD):
def exit(signum, frame):
sys.stderr.write("\nBye\n")
sys.exit()
signal.signal(signal.SIGINT, exit)
signal.signal(signal.SIGTERM, exit)
sys.stderr.write(
" -- Welcome to the cli tools. -- \nType 'exit' to quit.\n")
while (1):
inp = await asyncio.get_event_loop().run_in_executor(None, input, "db> ")
await do_cmd(inp)

21
src/web/ezapi.py Normal file
View File

@ -0,0 +1,21 @@
from src.webcore import app
from src import core
from fastapi import Response
version = "v1"
@app.post("/api/"+version+"/database/{database_name}", status_code=201)
async def create_database(database_name: str):
ret = await core.create_jsondb(database_name)
if (ret[0] == 0):
return {"status": 200}
return {"status": 400+ret[0], "errormsg": ret[1]}
@app.delete("/api/"+version+"/database/{database_name}", status_code=200)
async def create_database(database_name: str):
ret = await core.rm_jsondb(database_name)
if (ret[0] == 0):
return {"status": 200}
return {"status": 400+ret[0], "errormsg": ret[1]}

29
src/webcore.py Normal file
View File

@ -0,0 +1,29 @@
from fastapi import FastAPI
import uvicorn
from src import config
from src import log
import os
app = FastAPI()
@app.get("/")
async def root_hello():
return "Welcome to myjsonDB!"
async def start():
await log.info("Search web plugins")
plugs = []
for i in os.listdir("src"+os.sep+"web"):
if (i.split(".")[-1] != "py"):
continue
await log.info(" + Load "+i)
plugs.append(__import__("src.web."+i.split(".")[0]))
sconfig = uvicorn.Config(
app, loop="none", host=config.API_HOST, port=config.API_PORT)
server = uvicorn.Server(sconfig)
await server.serve()