From 43ab957c1a30f8311f0a84e80b4d194ef45719a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= <78488229+viktor138irk@users.noreply.github.com> Date: Tue, 12 May 2026 01:35:05 +0900 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BF=D1=83=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D1=8E=20OTA=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20Flutter=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/runtime_api.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/backend/runtime_api.py b/backend/runtime_api.py index 314274c..e84bf96 100644 --- a/backend/runtime_api.py +++ b/backend/runtime_api.py @@ -11,12 +11,15 @@ from fastapi.responses import StreamingResponse from pydantic import BaseModel from backend.android_tools import find_apks +from backend.ota_publish import publish_project_ota from backend.runtime_logs import get_logs, add_log from backend.shell_runner import run_command router = APIRouter(prefix='/api/runtime', tags=['runtime']) ACTIVE_PROCESSES: dict[str, subprocess.Popen] = {} +PUBLISH_AFTER_COMMANDS = {'flutter_build_apk', 'flutter_run_profile'} + def _runtime_env_prefix() -> str: runtime_home = os.getenv('DEVCONSOLE_RUNTIME_HOME') or os.getenv('HOME') or '/home/devconsole' @@ -75,7 +78,21 @@ def _event(payload: dict) -> str: return json.dumps(payload, ensure_ascii=False) + '\n' -def _stream_command(command: str, cwd: str, timeout: int): +def _publish_events(workspace: str): + yield _event({'type': 'line', 'message': 'OTA publish: preparing latest.json and APK upload'}) + try: + result = publish_project_ota(workspace) + if result.get('success'): + yield _event({'type': 'line', 'message': 'OTA publish: completed'}) + yield _event({'type': 'publish', 'success': True, 'result': result}) + else: + yield _event({'type': 'line', 'message': f"OTA publish skipped: {result.get('message')}"}) + yield _event({'type': 'publish', 'success': False, 'result': result}) + except Exception as exc: + yield _event({'type': 'error', 'message': f'OTA publish failed: {exc}'}) + + +def _stream_command(command_id: str, command: str, cwd: str, timeout: int): task_id = uuid.uuid4().hex process = subprocess.Popen( command, @@ -111,6 +128,10 @@ def _stream_command(command: str, cwd: str, timeout: int): returncode = -1 finally: ACTIVE_PROCESSES.pop(task_id, None) + + if returncode == 0 and command_id in PUBLISH_AFTER_COMMANDS: + yield from _publish_events(cwd) + yield _event({'type': 'done', 'task_id': task_id, 'returncode': returncode}) @@ -142,6 +163,8 @@ async def runtime_command(payload: RuntimeCommandRequest): add_log(f"Runtime command started: {config['label']}") result = run_command(command, cwd, timeout=int(config.get('timeout', 900))) add_log(f"Runtime command finished: {config['label']} (exit {result['returncode']})") + if result['returncode'] == 0 and payload.command in PUBLISH_AFTER_COMMANDS: + result['ota_publish'] = publish_project_ota(cwd) return {'success': result['returncode'] == 0, 'command': payload.command, 'label': config['label'], 'result': result} @@ -154,7 +177,7 @@ async def runtime_command_stream(payload: RuntimeCommandRequest): cwd = _workspace_cwd(payload.workspace) command = _with_device(config['command'], payload.device, bool(config.get('device'))) add_log(f"Runtime stream started: {config['label']}") - return StreamingResponse(_stream_command(command, cwd, int(config.get('timeout', 900))), media_type='application/x-ndjson') + return StreamingResponse(_stream_command(payload.command, command, cwd, int(config.get('timeout', 900))), media_type='application/x-ndjson') @router.post('/stop') @@ -166,7 +189,6 @@ async def runtime_stop(payload: RuntimeStopRequest): targets.append((payload.task_id, process)) else: targets = list(ACTIVE_PROCESSES.items()) - stopped = [] for task_id, process in targets: try: @@ -179,7 +201,6 @@ async def runtime_stop(payload: RuntimeStopRequest): stopped.append(task_id) except Exception as exc: add_log(f'Runtime stop error: {exc}') - add_log(f'Runtime stop requested: {stopped}') return {'success': True, 'stopped': stopped}