2026-08-29 12:44:23 +08:00

245 lines
9.9 KiB
Python

# -*- coding: utf-8 -*-
"""script_engine.init -- module initialization and business function registration."""
from ahserver.serverenv import ServerEnv
from sqlor.dbpools import DBPools
from appPublic.uniqueID import getID
from appPublic.timeUtils import curDateString
from script_engine.engine import validate_script as _validate_content, execute_script_content as _execute_content, VALID_SCRIPT_TYPES
_SCRIPT_FIELDS = ('id', 'script_name', 'script_type', 'content', 'description', 'status', 'created_at', 'updated_at')
def _dbname():
return ServerEnv().get_module_dbname('script_engine')
def _ok(data=None, message='ok'):
return {'code': 0, 'message': message, 'field': '', 'detail': '', 'data': data}
def _err(code, message, field='', detail=''):
return {'code': code, 'message': message, 'field': field, 'detail': detail}
def _clean_str(value, default=''):
if value is None:
return default
s = str(value).strip()
return s if s else default
def _row_to_dict(row):
out = {}
for f in _SCRIPT_FIELDS:
out[f] = getattr(row, f, None)
return out
def _validate_input(script_name, script_type, content):
if not script_name:
return False, 'script_name', 'script name must not be empty'
if len(script_name) > 100:
return False, 'script_name', 'script name length must not exceed 100'
if script_type not in VALID_SCRIPT_TYPES:
return False, 'script_type', 'unsupported script type: %s' % script_type
if not content or not content.strip():
return False, 'content', 'script content must not be empty'
if len(content) > 65535:
return False, 'content', 'script content length must not exceed 65535'
ok, err = _validate_content(content, script_type)
if not ok:
return False, 'content', err
return True, '', ''
async def create_script(request, params_kw):
try:
params = params_kw or {}
script_name = _clean_str(params.get('script_name'))
script_type = _clean_str(params.get('script_type'), '0')
content = _clean_str(params.get('content'))
description = _clean_str(params.get('description'))
status = _clean_str(params.get('status'), '1')
ok, field, msg = _validate_input(script_name, script_type, content)
if not ok:
return _err(400, msg, field, 'create_script: input validation failed')
dbname = _dbname()
db = DBPools()
now = curDateString()
new_id = getID()
ns = {'id': new_id, 'script_name': script_name, 'script_type': script_type, 'content': content, 'description': description, 'status': status, 'created_at': now, 'updated_at': now}
async with db.sqlorContext(dbname) as sor:
await sor.C('script', ns)
return _ok({'id': new_id}, 'created')
except Exception as e:
from traceback import format_exc
return _err(500, 'create failed: %s' % str(e), '', format_exc())
async def update_script(request, params_kw):
try:
params = params_kw or {}
script_id = _clean_str(params.get('id'))
if not script_id:
return _err(400, 'script id is required', 'id', 'update_script: id required')
script_name = _clean_str(params.get('script_name'))
script_type = _clean_str(params.get('script_type'), '0')
content = _clean_str(params.get('content'))
description = _clean_str(params.get('description'))
status = _clean_str(params.get('status'), '1')
ok, field, msg = _validate_input(script_name, script_type, content)
if not ok:
return _err(400, msg, field, 'update_script: input validation failed')
dbname = _dbname()
db = DBPools()
async with db.sqlorContext(dbname) as sor:
rows = await sor.R('script', {'id': script_id})
if not rows:
return _err(404, 'script not found', 'id', 'update_script: record missing')
upd = {'id': script_id, 'script_name': script_name, 'script_type': script_type, 'content': content, 'description': description, 'status': status, 'updated_at': curDateString()}
await sor.U('script', upd)
return _ok({'id': script_id}, 'updated')
except Exception as e:
from traceback import format_exc
return _err(500, 'update failed: %s' % str(e), '', format_exc())
async def delete_script(request, params_kw):
try:
params = params_kw or {}
script_id = _clean_str(params.get('id'))
if not script_id:
return _err(400, 'script id is required', 'id', 'delete_script: id required')
dbname = _dbname()
db = DBPools()
async with db.sqlorContext(dbname) as sor:
rows = await sor.R('script', {'id': script_id})
if not rows:
return _err(404, 'script not found', 'id', 'delete_script: record missing')
await sor.D('script', {'id': script_id})
return _ok({'id': script_id}, 'deleted')
except Exception as e:
from traceback import format_exc
return _err(500, 'delete failed: %s' % str(e), '', format_exc())
async def get_script(request, params_kw):
try:
params = params_kw or {}
script_id = _clean_str(params.get('id'))
if not script_id:
return _err(400, 'script id is required', 'id', 'get_script: id required')
dbname = _dbname()
db = DBPools()
async with db.sqlorContext(dbname) as sor:
rows = await sor.R('script', {'id': script_id})
if not rows:
return _err(404, 'script not found', 'id', 'get_script: record missing')
rec = _row_to_dict(rows[0])
return _ok(rec, 'ok')
except Exception as e:
from traceback import format_exc
return _err(500, 'query failed: %s' % str(e), '', format_exc())
async def list_scripts(request, params_kw):
try:
params = params_kw or {}
page = int(params.get('page', 1) or 1)
rows = int(params.get('rows', 20) or 20)
if page < 1:
page = 1
if rows < 1 or rows > 200:
rows = 20
keyword = _clean_str(params.get('script_name'))
script_type = _clean_str(params.get('script_type'))
status = _clean_str(params.get('status'))
conds = []
ns = {'page': page, 'rows': rows, 'sort': 'created_at desc'}
if keyword:
conds.append('script_name like ${keyword}$')
ns['keyword'] = '%%%s%%' % keyword
if script_type:
conds.append('script_type = ${script_type}$')
ns['script_type'] = script_type
if status:
conds.append('status = ${status}$')
ns['status'] = status
where = (' where ' + ' and '.join(conds)) if conds else ''
sql = 'select id, script_name, script_type, description, status, created_at, updated_at from script%s' % where
dbname = _dbname()
db = DBPools()
async with db.sqlorContext(dbname) as sor:
result = await sor.sqlPaging(sql, ns)
total = result.get('total', 0)
rows_data = result.get('rows', []) or []
data = [_row_to_dict(r) for r in rows_data]
return _ok({'list': data, 'total': total}, 'ok')
except Exception as e:
from traceback import format_exc
return _err(500, 'list failed: %s' % str(e), '', format_exc())
async def execute_script(request, params_kw):
try:
params = params_kw or {}
script_id = _clean_str(params.get('id'))
content = None
script_type = '0'
if script_id:
dbname = _dbname()
db = DBPools()
async with db.sqlorContext(dbname) as sor:
rows = await sor.R('script', {'id': script_id})
if not rows:
return _err(404, 'script not found', 'id', 'execute_script: record missing')
content = rows[0].content
script_type = str(rows[0].script_type or '0')
else:
content = _clean_str(params.get('content'))
script_type = _clean_str(params.get('script_type'), '0')
if not content:
return _err(400, 'script content must not be empty', 'content', 'execute_script: no content')
ok, field, msg = _validate_input('t', script_type, content)
if not ok:
return _err(400, msg, field, 'execute_script: validation failed, not executed')
run_params = params.get('params') or {}
result = _execute_content(content, script_type, run_params)
return _ok(result, 'executed')
except NotImplementedError as e:
return _err(501, str(e), 'script_type', 'execute_script: type not supported')
except Exception as e:
from traceback import format_exc
return _err(500, 'execute failed: %s' % str(e), '', format_exc())
async def validate_script_api(request, params_kw):
try:
params = params_kw or {}
content = _clean_str(params.get('content'))
script_type = _clean_str(params.get('script_type'), '0')
if not content:
return _err(400, 'script content must not be empty', 'content', 'validate_script: no content')
ok, field, msg = _validate_input('t', script_type, content)
if not ok:
return _err(400, msg, field, 'validate_script: validation failed')
return _ok({'valid': True}, 'valid')
except Exception as e:
from traceback import format_exc
return _err(500, 'validate failed: %s' % str(e), '', format_exc())
def load_script_engine():
env = ServerEnv()
env.create_script = create_script
env.update_script = update_script
env.delete_script = delete_script
env.get_script = get_script
env.list_scripts = list_scripts
env.execute_script = execute_script
env.validate_script_api = validate_script_api
env.create_scripts = create_script
env.update_scripts = update_script
env.delete_scripts = delete_script
return env