diff --git a/src/api/server_proxy.py b/src/api/server_proxy.py index 6c8fcc1..e2ba538 100644 --- a/src/api/server_proxy.py +++ b/src/api/server_proxy.py @@ -10,7 +10,6 @@ from urllib.parse import urljoin from src.utilities.misc_helper import is_localhost from src.utilities.status_utils import RenderStatus -from src.utilities.zeroconf_server import ZeroconfServer status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', RenderStatus.COMPLETED: 'green', RenderStatus.NOT_STARTED: "yellow", RenderStatus.SCHEDULED: 'purple', @@ -26,15 +25,8 @@ LOOPBACK = '127.0.0.1' class RenderServerProxy: - """ - The ServerProxy class is responsible for interacting with a remote server. - It provides methods to request data from the server and store the status of the server. - - Attributes: - system_cpu (str): The CPU type of the system. - system_cpu_count (int): The number of CPUs in the system. - system_os (str): The operating system of the system. - system_os_version (str): The version of the operating system. + """The ServerProxy class is responsible for interacting with a remote server. + It provides convenience methods to request data from the server and store the status of the server. """ def __init__(self, hostname, server_port="8080"): @@ -55,6 +47,10 @@ class RenderServerProxy: self.system_os = None self.system_os_version = None + # -------------------------------------------- + # Basics / Connection: + # -------------------------------------------- + def __repr__(self): return f"" @@ -73,6 +69,10 @@ class RenderServerProxy: running_jobs = [x for x in self.__jobs_cache if x['status'] == 'running'] if self.__jobs_cache else [] return f"{len(running_jobs)} running" if running_jobs else "Ready" + # -------------------------------------------- + # Requests: + # -------------------------------------------- + def request_data(self, payload, timeout=5): try: req = self.request(payload, timeout) @@ -103,6 +103,10 @@ class RenderServerProxy: hostname = LOOPBACK if self.is_localhost else self.hostname return requests.get(f'http://{hostname}:{self.port}/api/{payload}', timeout=timeout) + # -------------------------------------------- + # Background Updates: + # -------------------------------------------- + def start_background_update(self): if self.__update_in_background: return @@ -119,17 +123,6 @@ class RenderServerProxy: self.__background_thread.daemon = True self.__background_thread.start() - def stop_background_update(self): - self.__update_in_background = False - - def get_job_info(self, job_id, timeout=5): - return self.request_data(f'job/{job_id}', timeout=timeout) - - def get_all_jobs(self, timeout=5, ignore_token=False): - if not self.__update_in_background or ignore_token: - self.__update_job_cache(timeout, ignore_token) - return self.__jobs_cache.copy() if self.__jobs_cache else None - def __update_job_cache(self, timeout=40, ignore_token=False): if self.__offline_flags: # if we're offline, don't bother with the long poll @@ -147,15 +140,21 @@ class RenderServerProxy: self.__jobs_cache = sorted_jobs self.__jobs_cache_token = status_result['token'] + def stop_background_update(self): + self.__update_in_background = False + + # -------------------------------------------- + # Get System Info: + # -------------------------------------------- + + def get_all_jobs(self, timeout=5, ignore_token=False): + if not self.__update_in_background or ignore_token: + self.__update_job_cache(timeout, ignore_token) + return self.__jobs_cache.copy() if self.__jobs_cache else None + def get_data(self, timeout=5): return self.request_data('full_status', timeout=timeout) - def cancel_job(self, job_id, confirm=False): - return self.request_data(f'job/{job_id}/cancel?confirm={confirm}') - - def delete_job(self, job_id, confirm=False): - return self.request_data(f'job/{job_id}/delete?confirm={confirm}') - def get_status(self): status = self.request_data('status') if status and not self.system_cpu: @@ -165,26 +164,19 @@ class RenderServerProxy: self.system_os_version = status['system_os_version'] return status - def is_engine_available(self, engine_name): - return self.request_data(f'{engine_name}/is_available') + # -------------------------------------------- + # Get Job Info: + # -------------------------------------------- - def get_all_engines(self): - return self.request_data('all_engines') + def get_job_info(self, job_id, timeout=5): + return self.request_data(f'job/{job_id}', timeout=timeout) - def send_subjob_update_notification(self, parent_id, subjob): - """ - Notifies the parent job of an update in a subjob. + def get_job_files_list(self, job_id): + return self.request_data(f"job/{job_id}/file_list") - Args: - parent_id (str): The ID of the parent job. - subjob (Job): The subjob that has updated. - - Returns: - Response: The response from the server. - """ - hostname = LOOPBACK if self.is_localhost else self.hostname - return requests.post(f'http://{hostname}:{self.port}/api/job/{parent_id}/send_subjob_update_notification', - json=subjob.json()) + # -------------------------------------------- + # Job Lifecycle: + # -------------------------------------------- def post_job_to_server(self, file_path, job_list, callback=None): """ @@ -232,29 +224,36 @@ class RenderServerProxy: except Exception as e: logger.error(f"An error occurred: {e}") - def get_job_files_list(self, job_id): - return self.request_data(f"job/{job_id}/file_list") + def cancel_job(self, job_id, confirm=False): + return self.request_data(f'job/{job_id}/cancel?confirm={confirm}') - def download_all_job_files(self, job_id, save_path): + def delete_job(self, job_id, confirm=False): + return self.request_data(f'job/{job_id}/delete?confirm={confirm}') + + def send_subjob_update_notification(self, parent_id, subjob): + """ + Notifies the parent job of an update in a subjob. + + Args: + parent_id (str): The ID of the parent job. + subjob (Job): The subjob that has updated. + + Returns: + Response: The response from the server. + """ hostname = LOOPBACK if self.is_localhost else self.hostname - url = f"http://{hostname}:{self.port}/api/job/{job_id}/download_all" - return self.__download_file_from_url(url, output_filepath=save_path) + return requests.post(f'http://{hostname}:{self.port}/api/job/{parent_id}/send_subjob_update_notification', + json=subjob.json()) - def download_job_file(self, job_id, job_filename, save_path): - hostname = LOOPBACK if self.is_localhost else self.hostname - url = f"http://{hostname}:{self.port}/api/job/{job_id}/download?filename={job_filename}" - return self.__download_file_from_url(url, output_filepath=save_path) + # -------------------------------------------- + # Renderers: + # -------------------------------------------- - @staticmethod - def __download_file_from_url(url, output_filepath): - with requests.get(url, stream=True) as r: - r.raise_for_status() - with open(output_filepath, 'wb') as f: - for chunk in r.iter_content(chunk_size=8192): - f.write(chunk) - return output_filepath + def is_engine_available(self, engine_name): + return self.request_data(f'{engine_name}/is_available') - # --- Renderer --- # + def get_all_engines(self): + return self.request_data('all_engines') def get_renderer_info(self, response_type='standard', timeout=5): """ @@ -285,3 +284,26 @@ class RenderServerProxy: form_data = {'engine': engine, 'version': version, 'system_cpu': system_cpu} hostname = LOOPBACK if self.is_localhost else self.hostname return requests.post(f'http://{hostname}:{self.port}/api/delete_engine', json=form_data) + + # -------------------------------------------- + # Download Files: + # -------------------------------------------- + + def download_all_job_files(self, job_id, save_path): + hostname = LOOPBACK if self.is_localhost else self.hostname + url = f"http://{hostname}:{self.port}/api/job/{job_id}/download_all" + return self.__download_file_from_url(url, output_filepath=save_path) + + def download_job_file(self, job_id, job_filename, save_path): + hostname = LOOPBACK if self.is_localhost else self.hostname + url = f"http://{hostname}:{self.port}/api/job/{job_id}/download?filename={job_filename}" + return self.__download_file_from_url(url, output_filepath=save_path) + + @staticmethod + def __download_file_from_url(url, output_filepath): + with requests.get(url, stream=True) as r: + r.raise_for_status() + with open(output_filepath, 'wb') as f: + for chunk in r.iter_content(chunk_size=8192): + f.write(chunk) + return output_filepath