from __future__ import annotations from clients._path_setup import ensure_paths ensure_paths() import time from threading import Lock from fastapi import FastAPI from pydantic import BaseModel from typing import Optional from clients.movej_client import MoveJClient, action_music,action_air,action_drive_comfort,action_drive_economy,action_hello app = FastAPI(title="Humanoid Robot Control API (Blocking + Mutex + Ignore)") class ActionResponse(BaseModel): code: int msg: str action: Optional[str] = None ignored: bool = False class StatusResponse(BaseModel): running: bool current_action: Optional[str] last_action: Optional[str] last_finished_at: Optional[float] # 🔒 全局唯一互斥锁:保证同一时间只能执行一个 action action_lock = Lock() # 状态变量(简单可用;多线程更严谨可再加锁,这里够用) running = False current_action = None last_action = None last_finished_at = None def run_action_blocking_ignore_if_busy(action_func, action_name: str) -> ActionResponse: """ 通用执行模板: - 忙:直接忽略(立即返回,不执行) - 空闲:阻塞执行,执行完再返回 """ global running, current_action, last_action, last_finished_at # 忙就忽略(静默丢弃动作) if not action_lock.acquire(blocking=False): return ActionResponse( code=0, msg=f"{action_name} ignored: robot busy", action=action_name, ignored=True, ) client = MoveJClient() # client = 0 running = True current_action = action_name try: action_func(client) # ✅ 阻塞到动作执行结束 last_action = action_name last_finished_at = time.time() return ActionResponse( code=0, msg=f"{action_name} finished", action=action_name, ignored=False, ) except Exception as e: return ActionResponse( code=1, msg=f"{action_name} failed: {e}", action=action_name, ignored=False, ) finally: try: # print("closing action") client.close() finally: running = False current_action = None action_lock.release() # @app.post("/action/one", response_model=ActionResponse) # def call_action_one(): # return run_action_blocking_ignore_if_busy(action_one, "action_one") @app.post("/action/music", response_model=ActionResponse) def call_action_music(): return run_action_blocking_ignore_if_busy(action_music, "action_music") @app.post("/action/air", response_model=ActionResponse) def call_action_air(): return run_action_blocking_ignore_if_busy(action_air, "action_air") @app.post("/action/hello", response_model=ActionResponse) def call_action_hello(): return run_action_blocking_ignore_if_busy(action_hello, "action_hello") # @app.post("/action/drive_comfort", response_model=ActionResponse) # def call_action_drive_comfort(): # return run_action_blocking_ignore_if_busy(action_drive_comfort, "action_drive_comfort") # # @app.post("/action/drive_economy", response_model=ActionResponse) # def call_action_drive_economy(): # return run_action_blocking_ignore_if_busy(action_drive_economy, "action_drive_economy") # # @app.post("/action/two", response_model=ActionResponse) # def call_action_two(): # return run_action_blocking_ignore_if_busy(action_two, "action_two") # @app.post("/action/two", response_model=ActionResponse) # def call_action_two(): # return run_action_blocking_ignore_if_busy(action_two, "action_two") @app.get("/status", response_model=StatusResponse) def get_status(): return StatusResponse( running=running, current_action=current_action, last_action=last_action, last_finished_at=last_finished_at, ) if __name__ == "__main__": import uvicorn uvicorn.run( "http_server:app", host="0.0.0.0", port=8000, reload=False )