From 58e9807a702b53cdca5cf5e20e9e1690e0771387 Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Sun, 3 Dec 2023 17:17:25 +0800 Subject: [PATCH 1/3] automate vm ip address --- desktop_env/envs/desktop_env.py | 14 ++++++++++++-- main.py | 2 -- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/desktop_env/envs/desktop_env.py b/desktop_env/envs/desktop_env.py index b4347cb..b06abbb 100644 --- a/desktop_env/envs/desktop_env.py +++ b/desktop_env/envs/desktop_env.py @@ -15,6 +15,7 @@ def _execute_command(command: List[str]) -> None: result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=60, text=True) if result.returncode != 0: raise Exception("\033[91m" + result.stdout + result.stderr + "\033[0m") + return result.stdout class DesktopEnv(gym.Env): @@ -23,18 +24,17 @@ class DesktopEnv(gym.Env): def __init__( self, path_to_vm: str, - host: str = "192.168.7.128:5000", snapshot_path: str = "base", action_space: str = "pyautogui", ): # Initialize environment variables self.path_to_vm = path_to_vm - self.host = host self.snapshot_path = snapshot_path # todo: handling the logic of snapshot directory # Initialize emulator and controller print("Initializing...") self._start_emulator() + self.host = self._get_vm_ip() self.controller = PythonController(http_server=self.host) # mode: human or machine @@ -57,6 +57,16 @@ class DesktopEnv(gym.Env): except subprocess.CalledProcessError as e: print(f"Error executing command: {e.output.decode().strip()}") + def _get_vm_ip(self): + max_retries = 3 + for _ in range(max_retries): + try: + output = _execute_command(["vmrun", "-T", "ws", "getGuestIPAddress", self.path_to_vm]) + return output.strip() + except: + time.sleep(2) + print("Retrying...") + def _save_state(self): _execute_command(["vmrun", "-T", "ws" "snapshot", self.path_to_vm, self.snapshot_path]) diff --git a/main.py b/main.py index 9ef3982..bbfd8d2 100644 --- a/main.py +++ b/main.py @@ -8,8 +8,6 @@ def human_agent(): env = DesktopEnv( path_to_vm=r"""C:\Users\tianbaox\Documents\Virtual Machines\Win10\Win10.vmx""", # path_to_vm="/home/yuri/vmware/Ubuntu 64-bit/Ubuntu 64-bit.vmx", - # host="192.168.7.128", - host="http://192.168.13.128:5000", snapshot_path="base3", ) From b10908b4faa4f808c7dad16bbf0172a095cf5ba7 Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Sun, 3 Dec 2023 17:24:44 +0800 Subject: [PATCH 2/3] add longer retries --- desktop_env/envs/desktop_env.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/desktop_env/envs/desktop_env.py b/desktop_env/envs/desktop_env.py index b06abbb..e2f8376 100644 --- a/desktop_env/envs/desktop_env.py +++ b/desktop_env/envs/desktop_env.py @@ -53,19 +53,22 @@ class DesktopEnv(gym.Env): else: print("Starting VM...") _execute_command(["vmrun", "-T", "ws", "start", self.path_to_vm]) - time.sleep(10) + time.sleep(3) except subprocess.CalledProcessError as e: print(f"Error executing command: {e.output.decode().strip()}") def _get_vm_ip(self): - max_retries = 3 + max_retries = 10 + print("Getting IP Address...") for _ in range(max_retries): try: - output = _execute_command(["vmrun", "-T", "ws", "getGuestIPAddress", self.path_to_vm]) - return output.strip() + output = _execute_command(["vmrun", "-T", "ws", "getGuestIPAddress", self.path_to_vm]).strip() + print(f"IP address: {output}") + return output except: - time.sleep(2) + time.sleep(5) print("Retrying...") + raise Exception("Failed to get VM IP address!") def _save_state(self): _execute_command(["vmrun", "-T", "ws" "snapshot", self.path_to_vm, self.snapshot_path]) From e808cf84a7edef549f435dc046b029b0bf1c3b15 Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Sun, 3 Dec 2023 21:09:05 +0800 Subject: [PATCH 3/3] setup controller --- desktop_env/controllers/setup.py | 40 ++++++++++++++++++++++++++++++++ desktop_env/envs/desktop_env.py | 7 +++++- desktop_env/server/main.py | 29 +++++++++++++++++++++++ main.py | 3 +++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 desktop_env/controllers/setup.py diff --git a/desktop_env/controllers/setup.py b/desktop_env/controllers/setup.py new file mode 100644 index 0000000..d2abc97 --- /dev/null +++ b/desktop_env/controllers/setup.py @@ -0,0 +1,40 @@ +import requests +import json + +class SetupController: + def __init__(self, http_server: str): + self.http_server = http_server + "/setup" + + def setup(self, config): + """ + Setup Config: + { + download: list[tuple[string]], # a list of tuples of url of file to download and the save path + ... + } + """ + self._download_setup(config) + # can add other setup steps + + + def _download_setup(self, config): + if not 'download' in config: + return + for url, path in config['download']: + if not url or not path: + raise Exception(f"Setup Download - Invalid URL ({url}) or path ({path}).") + + payload = json.dumps({"url": url, "path": path}) + headers = { + 'Content-Type': 'application/json' + } + + # send request to server to download file + try: + response = requests.post(self.http_server + "/download_file", headers=headers, data=payload) + if response.status_code == 200: + print("Command executed successfully:", response.text) + else: + print("Failed to download file. Status code:", response.text) + except requests.exceptions.RequestException as e: + print("An error occurred while trying to send the request:", e) diff --git a/desktop_env/envs/desktop_env.py b/desktop_env/envs/desktop_env.py index e2f8376..99a9a26 100644 --- a/desktop_env/envs/desktop_env.py +++ b/desktop_env/envs/desktop_env.py @@ -9,6 +9,7 @@ from typing import List import gymnasium as gym from desktop_env.controllers.python import PythonController +from desktop_env.controllers.setup import SetupController def _execute_command(command: List[str]) -> None: @@ -34,8 +35,9 @@ class DesktopEnv(gym.Env): # Initialize emulator and controller print("Initializing...") self._start_emulator() - self.host = self._get_vm_ip() + self.host = f"http://{self._get_vm_ip()}:5000" self.controller = PythonController(http_server=self.host) + self.setup_controller = SetupController(http_server=self.host) # mode: human or machine assert action_space in ["computer_13", "pyautogui"] @@ -118,6 +120,9 @@ class DesktopEnv(gym.Env): done = False # todo: Define episode termination condition for each example info = {} return observation, reward, done, info + + def setup(self, config: dict): + self.setup_controller.setup(config) def render(self, mode='rgb_array'): if mode == 'rgb_array': diff --git a/desktop_env/server/main.py b/desktop_env/server/main.py index f9e8dcd..93884ca 100644 --- a/desktop_env/server/main.py +++ b/desktop_env/server/main.py @@ -1,4 +1,5 @@ import os +from pathlib import Path import platform import subprocess import requests @@ -83,6 +84,34 @@ def get_platform(): def get_cursor_position(): return pyautogui.position().x, pyautogui.position().y +@app.route("/setup/download_file", methods=['POST']) +def download_file(): + data = request.json + url = data.get('url', None) + path = data.get('path', None) + + if not url or not path: + return "Path or URL not supplied!", 400 + + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + + max_retries = 3 + for i in range(max_retries): + try: + response = requests.get(url, stream=True) + response.raise_for_status() + + with open(path, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + return "File downloaded successfully" + + except requests.RequestException as e: + print(f"Failed to download {url}. Retrying... ({max_retries - i - 1} attempts left)") + + return f"Failed to download {url}. No retries left. Error: {e}", 500 if __name__ == '__main__': app.run(debug=True, host="0.0.0.0") diff --git a/main.py b/main.py index bbfd8d2..7b993f2 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,9 @@ def human_agent(): # path_to_vm="/home/yuri/vmware/Ubuntu 64-bit/Ubuntu 64-bit.vmx", snapshot_path="base3", ) + # example setup + env.setup({"download": [("https://images.unsplash.com/photo-1683009427051-00a2fe827a2c", "C:/Users/Yuri/Desktop/1.jpg")]}) + # reset the environment to certain snapshot observation = env.reset()