diff --git a/platformio/commands/home/rpc/handlers/ide.py b/platformio/commands/home/rpc/handlers/ide.py index 44286dd8..ad3cf063 100644 --- a/platformio/commands/home/rpc/handlers/ide.py +++ b/platformio/commands/home/rpc/handlers/ide.py @@ -20,33 +20,63 @@ from platformio.compat import aio_get_running_loop class IDERPC: + + COMMAND_TIMEOUT = 1.5 # in seconds + def __init__(self): - self._cmd_queue = [] - self._result_queue = {} + self._ide_queue = [] + self._cmd_queue = {} async def listen_commands(self): - self._cmd_queue.append(aio_get_running_loop().create_future()) - return await self._cmd_queue[-1] + f = aio_get_running_loop().create_future() + self._ide_queue.append(f) + self._process_commands() + return await f async def send_command(self, command, params=None): - if not self._cmd_queue: - raise JSONRPC20DispatchException( - code=4005, message="PIO Home IDE agent is not started" - ) - cmd_id = None - while self._cmd_queue: - cmd_id = f"ide-{command}-{time.time()}" - self._cmd_queue.pop().set_result( - { - "id": cmd_id, - "method": command, - "params": params, - } - ) - if not cmd_id: - return - self._result_queue[cmd_id] = aio_get_running_loop().create_future() - return await self._result_queue[cmd_id] + cmd_id = f"ide-{command}-{time.time()}" + self._cmd_queue[cmd_id] = { + "method": command, + "params": params, + "time": time.time(), + "future": aio_get_running_loop().create_future(), + } + self._process_commands() + # in case if IDE agent has not been started + aio_get_running_loop().call_later( + self.COMMAND_TIMEOUT + 0.1, self._process_commands + ) + return await self._cmd_queue[cmd_id]["future"] def on_command_result(self, cmd_id, value): - self._result_queue[cmd_id].set_result(value) + if cmd_id not in self._cmd_queue: + return + self._cmd_queue[cmd_id]["future"].set_result(value) + del self._cmd_queue[cmd_id] + + def _process_commands(self): + for cmd_id in list(self._cmd_queue): + cmd_data = self._cmd_queue[cmd_id] + if cmd_data["future"].done(): + del self._cmd_queue[cmd_id] + continue + + if ( + not self._ide_queue + and (time.time() - cmd_data["time"]) > self.COMMAND_TIMEOUT + ): + cmd_data["future"].set_exception( + JSONRPC20DispatchException( + code=4005, message="PIO Home IDE agent is not started" + ) + ) + continue + + while self._ide_queue: + self._ide_queue.pop().set_result( + { + "id": cmd_id, + "method": cmd_data["method"], + "params": cmd_data["params"], + } + )