From 7350e04cf690fa02655c25a8e1c53bb0513b36d2 Mon Sep 17 00:00:00 2001 From: ymq Date: Fri, 14 Aug 2026 11:12:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E7=8E=AF=E5=A2=83=20?= =?UTF-8?q?API=20(get/set/ensure=5Fremote=5Fbwrap)=20+=20deploy=5Faccount?= =?UTF-8?q?=20run=20=E6=94=AF=E6=8C=81=E8=BF=9C=E7=A8=8B=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/api/deploy_account.dspy | 5 ++- wwwroot/api/work_env.dspy | 76 +++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 wwwroot/api/work_env.dspy diff --git a/wwwroot/api/deploy_account.dspy b/wwwroot/api/deploy_account.dspy index 310380a..2a75a29 100644 --- a/wwwroot/api/deploy_account.dspy +++ b/wwwroot/api/deploy_account.dspy @@ -12,6 +12,7 @@ from pipeline_service.deploy_account import ( ensure_account, remove_account, list_accounts, run_in_sandbox, write_file, read_file, list_dir, sanitize_username, ) +from pipeline_service.work_env import run_in_work_env # 查当前用户 username(账号名 ag_) username = user_id @@ -60,7 +61,9 @@ elif action == 'run': account_name = 'ag_' + sanitize_username(username) try: async with get_sor_context(request._run_ns, 'pipeline') as sor: - r = await run_in_sandbox(sor, account_name, command, workdir, timeout, network) + _u = await sor.sqlExe("SELECT orgid FROM users WHERE id=${u}$", {'u': user_id}) + _org = getattr(_u[0], 'orgid', '') if _u else '' + r = await run_in_work_env(sor, account_name, user_id, _org, command, workdir, timeout, network) return json.dumps({'ok': True, **r}, ensure_ascii=False) except Exception as e: return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) diff --git a/wwwroot/api/work_env.dspy b/wwwroot/api/work_env.dspy new file mode 100644 index 0000000..b5d5740 --- /dev/null +++ b/wwwroot/api/work_env.dspy @@ -0,0 +1,76 @@ +# work_env.dspy - 工作环境管理 API(沙箱本地/远程切换 + 目录迁移) +# action: get / set / ensure_remote_bwrap + +user_id = await get_user() +if not user_id: + return json.dumps({'ok': False, 'error': '未登录'}, ensure_ascii=False) + +action = (params_kw or {}).get('action', 'get') + +from pipeline_service.work_env import ( + get_work_env, set_work_env, ensure_remote_bwrap, +) +from pipeline_service.deploy_account import account_name_for, sanitize_username + +# 查用户 username(账号名 ag_)和 org_id +username = user_id +org_id = '' +try: + async with get_sor_context(request._run_ns, 'pipeline') as _sor: + _u = await _sor.sqlExe("SELECT username, orgid FROM users WHERE id=${u}$", {'u': user_id}) + if _u: + username = getattr(_u[0], 'username', user_id) or user_id + org_id = getattr(_u[0], 'orgid', '') or '' +except Exception: + pass + +if action == 'get': + try: + async with get_sor_context(request._run_ns, 'pipeline') as sor: + env = await get_work_env(sor, user_id, org_id) + return json.dumps({'ok': True, 'env': env, 'account_name': account_name_for(username)}, ensure_ascii=False) + except Exception as e: + return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) + +elif action == 'set': + owner_type = (params_kw or {}).get('owner_type', 'user') + mode = (params_kw or {}).get('mode', 'local') + account_name = (params_kw or {}).get('account_name', '') or account_name_for(username) + + # owner_id:user 级用 user_id,org 级用 org_id + owner_id = (params_kw or {}).get('owner_id', '') + if owner_type == 'user': + owner_id = owner_id or user_id + elif owner_type == 'org': + owner_id = owner_id or org_id + + remote_config = { + 'remote_host': (params_kw or {}).get('remote_host', ''), + 'remote_port': (params_kw or {}).get('remote_port', 22), + 'remote_user': (params_kw or {}).get('remote_user', ''), + 'remote_key_path': (params_kw or {}).get('remote_key_path', ''), + 'remote_dir': (params_kw or {}).get('remote_dir', ''), + } + + try: + async with get_sor_context(request._run_ns, 'pipeline') as sor: + r = await set_work_env(sor, owner_type, owner_id, mode, remote_config, account_name) + return json.dumps(r, ensure_ascii=False) + except Exception as e: + return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) + +elif action == 'ensure_remote_bwrap': + remote_config = { + 'remote_host': (params_kw or {}).get('remote_host', ''), + 'remote_port': (params_kw or {}).get('remote_port', 22), + 'remote_user': (params_kw or {}).get('remote_user', ''), + 'remote_key_path': (params_kw or {}).get('remote_key_path', ''), + } + try: + r = await ensure_remote_bwrap(remote_config) + return json.dumps(r, ensure_ascii=False) + except Exception as e: + return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) + +else: + return json.dumps({'ok': False, 'error': '未知 action: ' + str(action)}, ensure_ascii=False)