236 lines
9.6 KiB
Python

# -*- coding: utf-8 -*-
"""script_engine.init —— 模块初始化与业务函数注册。"""
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
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 _validate_input(script_name, script_type, content):
if not script_name:
return False, 'script_name', '脚本名称不能为空'
if len(script_name) > 100:
return False, 'script_name', '脚本名称长度不能超过 100'
if script_type not in VALID_SCRIPT_TYPES:
return False, 'script_type', '不支持的脚本类型: %s' % script_type
if not content or not content.strip():
return False, 'content', '脚本内容不能为空'
if len(content) > 65535:
return False, 'content', '脚本内容长度不能超过 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: 参数校验失败')
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}, '创建成功')
except Exception as e:
from traceback import format_exc
return _err(500, '创建失败: %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, '缺少脚本ID', 'id', 'update_script: id 必填')
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: 参数校验失败')
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, '脚本不存在', 'id', 'update_script: 记录不存在')
upd = {'script_name': script_name, 'script_type': script_type, 'content': content, 'description': description, 'status': status, 'updated_at': curDateString()}
upd['id'] = script_id
await sor.U('script', upd)
return _ok({'id': script_id}, '更新成功')
except Exception as e:
from traceback import format_exc
return _err(500, '更新失败: %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, '缺少脚本ID', 'id', 'delete_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, '脚本不存在', 'id', 'delete_script: 记录不存在')
await sor.D('script', {'id': script_id})
return _ok({'id': script_id}, '删除成功')
except Exception as e:
from traceback import format_exc
return _err(500, '删除失败: %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, '缺少脚本ID', 'id', 'get_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, '脚本不存在', 'id', 'get_script: 记录不存在')
rec = dict(rows[0])
return _ok(rec, '查询成功')
except Exception as e:
from traceback import format_exc
return _err(500, '查询失败: %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.sqlExe(sql, ns)
total = result.get('total', 0) if isinstance(result, dict) else len(result or [])
data = result.get('rows', []) if isinstance(result, dict) else (result or [])
return _ok({'list': data, 'total': total}, '查询成功')
except Exception as e:
from traceback import format_exc
return _err(500, '列表查询失败: %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, '脚本不存在', 'id', 'execute_script: 记录不存在')
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, '脚本内容不能为空', 'content', 'execute_script: 无脚本内容')
ok, field, msg = _validate_input('t', script_type, content)
if not ok:
return _err(400, msg, field, 'execute_script: 校验失败,不执行')
run_params = params.get('params') or {}
result = _execute_content(content, script_type, run_params)
return _ok(result, '执行成功')
except NotImplementedError as e:
return _err(501, str(e), 'script_type', 'execute_script: 该类型暂不支持执行')
except Exception as e:
from traceback import format_exc
return _err(500, '执行失败: %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, '脚本内容不能为空', 'content', 'validate_script: 无脚本内容')
ok, field, msg = _validate_input('t', script_type, content)
if not ok:
return _err(400, msg, field, 'validate_script: 校验失败')
return _ok({'valid': True}, '校验通过')
except Exception as e:
from traceback import format_exc
return _err(500, '校验失败: %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