From a36f6d3128207de1d298aa6b983b7c38dfcd5212 Mon Sep 17 00:00:00 2001 From: Brett Williams Date: Sun, 30 Oct 2022 23:59:58 -0700 Subject: [PATCH] Improve dashboard to fetch data async from screen refreshes --- dashboard.py | 93 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/dashboard.py b/dashboard.py index 2826516..311230d 100755 --- a/dashboard.py +++ b/dashboard.py @@ -32,7 +32,7 @@ status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', R categories = [RenderStatus.RUNNING, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED, RenderStatus.COMPLETED, RenderStatus.CANCELLED] -renderer_colors = {'ffmpeg': '[magenta]', 'Blender': '[orange1]', 'aerender': '[purple]'} +renderer_colors = {'ffmpeg': '[magenta]', 'blender': '[orange1]', 'aerender': '[purple]'} local_hostname = socket.gethostname() @@ -132,7 +132,21 @@ def create_jobs_table(all_server_data) -> Table: if job_status == RenderStatus.ERROR and job['worker']['errors']: job_text = job_text + "\n" + "\n".join(job['worker']['errors']) - elapsed_time = job['worker'].get('time_elapsed', 'unknown') + # calculate elapsed time + elapsed_time = 'Unknown' + start_time = None + end_time = None + + if job['worker']['start_time']: + start_time = datetime.datetime.fromisoformat(job['worker']['start_time']) + if job['worker']['end_time']: + end_time = datetime.datetime.fromisoformat(job['worker']['end_time']) + + if start_time: + if end_time: + elapsed_time = str(end_time - start_time) + elif job_status == RenderStatus.RUNNING: + elapsed_time = str(datetime.datetime.now() - start_time) # Project name project_name = job_color + job['name'] @@ -174,20 +188,21 @@ def create_status_panel(all_server_data): return "no status" -class RenderDashboard: +class RenderServerProxy: def __init__(self, server_ip=None, server_port="8080"): - self.server_ip = server_ip - self.server_port = server_port + self.hostname = server_ip + self.port = server_port self.local_hostname = local_hostname + self.fetched_status_data = None def connect(self): status = self.request_data('status') return status - def request_data(self, payload, timeout=2): + def request_data(self, payload, timeout=5): try: - req = requests.get(f'http://{self.server_ip}:{self.server_port}/{payload}', timeout=timeout) + req = requests.get(f'http://{self.hostname}:{self.port}/{payload}', timeout=timeout) if req.ok: return req.json() except Exception as e: @@ -204,8 +219,8 @@ class RenderDashboard: sorted_jobs.extend(found_jobs) return sorted_jobs - def get_data(self): - all_data = self.request_data('full_status', timeout=5) + def get_data(self, timeout=5): + all_data = self.request_data('full_status', timeout=timeout) return all_data @@ -230,23 +245,23 @@ if __name__ == '__main__': get_server_ip = input("Enter server IP or None for local: ") or local_hostname - client = RenderDashboard(get_server_ip, "8080") + server_proxy = RenderServerProxy(get_server_ip, "8080") - if not client.connect(): - if client.server_ip == local_hostname: + if not server_proxy.connect(): + if server_proxy.hostname == local_hostname: start_server_input = input("Local server not running. Start server? (y/n) ") if start_server_input and start_server_input[0].lower() == "y": # Startup the local server start_server(background_thread=True) - test = client.connect() + test = server_proxy.connect() print(f"connected? {test}") else: - print(f"\nUnable to connect to server: {client.server_ip}") + print(f"\nUnable to connect to server: {server_proxy.hostname}") print("\nVerify IP address is correct and server is running") exit(1) # start the Keyboard thread - kthread = KeyboardThread(my_callback) + # kthread = KeyboardThread(my_callback) # Console Layout console = Console() @@ -268,34 +283,42 @@ if __name__ == '__main__': # Server connection header header_text = Text(f"Connected to server: ") - header_text.append(f"{client.server_ip} ", style="green") - if client.server_ip == local_hostname: + header_text.append(f"{server_proxy.hostname} ", style="green") + if server_proxy.hostname == local_hostname: header_text.append("(This Computer)", style="yellow") else: header_text.append("(Remote)", style="magenta") - with Live(console=console, screen=False, refresh_per_second=1, transient=True) as live: - - cached_server_data = None - + # background process to update server data independent of the UI + def fetch_server_data(server): while True: - server_data = client.get_data() - if server_data: - cached_server_data = server_data - server_data['online'] = True - else: - server_data = cached_server_data - if server_data: - server_data['online'] = False + fetched_data = server.get_data(timeout=5) + if fetched_data: + server.fetched_status_data = fetched_data + time.sleep(1) + x = threading.Thread(target=fetch_server_data, args=(server_proxy,)) + x.daemon = True + x.start() + + # draw and update the UI + with Live(console=console, screen=False, refresh_per_second=1, transient=True) as live: + while True: try: - if server_data: - layout["body"].update(create_jobs_table(server_data)) - layout["side_top"].update(Panel(create_node_tree(server_data))) - layout["side_bottom"].update(Panel(create_status_panel(server_data))) + if server_proxy.fetched_status_data: - online_text = "Online" if server_data['online'] else "Offline" - online_color = "green" if server_data['online'] else "red" + server_online = False + if server_proxy.fetched_status_data.get('timestamp', None): + timestamp = datetime.datetime.fromisoformat(server_proxy.fetched_status_data['timestamp']) + time_diff = datetime.datetime.now() - timestamp + server_online = time_diff.seconds < 10 # client is offline if not updated in certain time + + layout["body"].update(create_jobs_table(server_proxy.fetched_status_data)) + layout["side_top"].update(Panel(create_node_tree(server_proxy.fetched_status_data))) + layout["side_bottom"].update(Panel(create_status_panel(server_proxy.fetched_status_data))) + + online_text = "Online" if server_online else "Offline" + online_color = "green" if server_online else "red" layout["header"].update(Panel(Text(f"Zordon Render Client - Version 0.0.1 alpha - {online_text}", justify="center", style=online_color))) live.update(layout, refresh=False)