See progress of uploads in client

This commit is contained in:
Brett Williams
2023-06-05 19:30:47 -05:00
parent 0cf18da67e
commit 9ec7ef48c2
3 changed files with 126 additions and 58 deletions

View File

@@ -6,13 +6,11 @@ import pathlib
import socket import socket
from tkinter import * from tkinter import *
from tkinter import filedialog, messagebox from tkinter import filedialog, messagebox
from tkinter.simpledialog import askstring from tkinter.ttk import Frame, Label, Entry, Combobox, Progressbar
from tkinter.ttk import Frame, Label, Entry, Combobox
import psutil import psutil
import requests import requests
import sys import threading
sys.path.append('../../')
from lib.render_workers.blender_worker import Blender from lib.render_workers.blender_worker import Blender
from lib.server.server_proxy import RenderServerProxy from lib.server.server_proxy import RenderServerProxy
@@ -67,6 +65,7 @@ class NewJobWindow(Frame):
def __init__(self, parent=None, clients=None): def __init__(self, parent=None, clients=None):
super().__init__(parent) super().__init__(parent)
self.root = parent
self.clients = clients or [] self.clients = clients or []
self.server_proxy = RenderServerProxy(hostname=clients[0] if clients else None) self.server_proxy = RenderServerProxy(hostname=clients[0] if clients else None)
self.chosen_file = None self.chosen_file = None
@@ -158,6 +157,11 @@ class NewJobWindow(Frame):
self.custom_args_entry = None self.custom_args_entry = None
self.submit_frame = None self.submit_frame = None
self.progress_frame = None
self.progress_label = None
self.progress_bar = None
self.upload_status = None
self.fetch_server_data() self.fetch_server_data()
def client_picked(self, event=None): def client_picked(self, event=None):
@@ -249,10 +253,20 @@ class NewJobWindow(Frame):
self.submit_frame.forget() self.submit_frame.forget()
self.submit_frame = Frame(self) self.submit_frame = Frame(self)
self.submit_frame.pack(fill=BOTH, expand=True) self.submit_frame.pack(fill=BOTH, expand=True)
Label(self.submit_frame, text="").pack(fill=BOTH, expand=True) # Label(self.submit_frame, text="").pack(fill=BOTH, expand=True)
submit_button = Button(self.submit_frame, text="Submit", command=self.submit_job) submit_button = Button(self.submit_frame, text="Submit", command=self.submit_job)
submit_button.pack(fill=Y, anchor="s", pady=header_padding) submit_button.pack(fill=Y, anchor="s", pady=header_padding)
def draw_progress_frame(self):
if hasattr(self, 'progress_frame') and self.progress_frame:
self.progress_frame.forget()
self.progress_frame = LabelFrame(self, text="Job Submission")
self.progress_frame.pack(side=TOP, fill=X, expand=False, padx=5, pady=5)
self.progress_bar = Progressbar(self.progress_frame, length=300, mode="determinate")
self.progress_bar.pack()
self.progress_label = Label(self.progress_frame, text="Starting Up")
self.progress_label.pack(pady=5, padx=5)
def draw_blender_settings(self): def draw_blender_settings(self):
scene_data = None scene_data = None
@@ -263,8 +277,7 @@ class NewJobWindow(Frame):
# blender settings # blender settings
self.blender_frame = LabelFrame(self, text="Blender Settings") self.blender_frame = LabelFrame(self, text="Blender Settings")
self.blender_frame.pack(fill=X, padx=5, pady=5) self.blender_frame.pack(fill=X, padx=5)
blender_engine_frame = Frame(self.blender_frame) blender_engine_frame = Frame(self.blender_frame)
blender_engine_frame.pack(fill=X) blender_engine_frame.pack(fill=X)
@@ -318,56 +331,98 @@ class NewJobWindow(Frame):
def submit_job(self): def submit_job(self):
client = self.client_combo.get() def submit_job_worker():
renderer = self.renderer_combo.get() self.draw_progress_frame()
job_json = {'owner': psutil.Process().username() + '@' + socket.gethostname(), self.progress_bar['value'] = 0
'renderer': renderer, self.progress_bar.configure(mode='determinate')
'client': client, self.progress_bar.start()
'output_path': os.path.join(os.path.dirname(self.chosen_file), self.output_entry.get()), self.progress_label.configure(text="Preparing files...")
'args': {'raw': self.custom_args_entry.get()},
'name': None}
job_list = []
input_path = self.chosen_file # start the progress UI
client = self.client_combo.get()
temp_files = [] renderer = self.renderer_combo.get()
if renderer == 'blender': job_json = {'owner': psutil.Process().username() + '@' + socket.gethostname(),
if self.blender_pack_textures.get(): 'renderer': renderer,
new_path = Blender.pack_project_file(project_path=input_path) 'client': client,
if new_path: 'output_path': os.path.join(os.path.dirname(self.chosen_file), self.output_entry.get()),
logger.info(f'Packed Blender file successfully: {new_path}') 'args': {'raw': self.custom_args_entry.get()},
input_path = new_path 'name': None}
temp_files.append(new_path) job_list = []
input_path = self.chosen_file
temp_files = []
if renderer == 'blender':
if self.blender_pack_textures.get():
self.progress_label.configure(text="Packing Blender file...")
new_path = Blender.pack_project_file(project_path=input_path)
if new_path:
logger.info(f"New Path is now {new_path}")
input_path = new_path
temp_files.append(new_path)
else:
err_msg = f'Failed to pack Blender file: {input_path}'
messagebox.showinfo("Error", err_msg)
return
# add all Blender args
job_json['args']['engine'] = self.blender_engine.get()
job_json['args']['render_all_frames'] = self.blender_render_all_frames.get()
job_json['args']['export_format'] = self.output_format.get()
# multiple camera rendering
if self.blender_cameras_list and self.blender_multiple_cameras.get():
selected_cameras = self.blender_cameras_list.getCheckedItems()
for cam in selected_cameras:
job_copy = copy.deepcopy(job_json)
job_copy['args']['camera'] = cam.rsplit('-', 1)[0].strip()
job_copy['name'] = pathlib.Path(input_path).stem.replace(' ', '_') + "-" + cam.replace(' ', '')
job_list.append(job_copy)
# Submit to server
job_list = job_list or [job_json]
self.progress_label.configure(text="Posting to server...")
self.progress_bar.stop()
self.progress_bar.configure(mode='determinate')
self.progress_bar.start()
def create_callback(encoder):
encoder_len = encoder.len
def callback(monitor):
percent = f"{monitor.bytes_read / encoder_len * 100:.0f}"
self.progress_label.configure(text=f"Transferring to {client} - {percent}%")
self.progress_bar['value'] = int(percent)
return callback
result = self.server_proxy.post_job_to_server(input_path=input_path, job_list=job_list,
callback=create_callback)
self.progress_bar.stop()
# clean up
for temp in temp_files:
os.remove(temp)
def finish_on_main():
if result.ok:
message = "Job successfully submitted to server."
self.progress_label.configure(text=message)
messagebox.showinfo("Success", message)
logger.info(message)
else: else:
err_msg = f'Failed to pack Blender file: {input_path}' message = result.text or "Unknown error"
messagebox.showinfo("Error", err_msg) self.progress_label.configure(text=message)
return logger.warning(message)
# add all Blender args messagebox.showinfo("Error", message)
job_json['args']['engine'] = self.blender_engine.get() self.progress_label.configure(text="")
job_json['args']['render_all_frames'] = self.blender_render_all_frames.get() self.progress_frame.forget()
job_json['args']['export_format'] = self.output_format.get()
# multiple camera rendering self.root.after(0, finish_on_main)
if self.blender_cameras_list and self.blender_multiple_cameras.get():
selected_cameras = self.blender_cameras_list.getCheckedItems()
for cam in selected_cameras:
job_copy = copy.deepcopy(job_json)
job_copy['args']['camera'] = cam.rsplit('-', 1)[0].strip()
job_copy['name'] = pathlib.Path(input_path).stem.replace(' ', '_') + "-" + cam.replace(' ', '')
job_list.append(job_copy)
# Submit to server # Start the job submit task as a bg thread
job_list = job_list or [job_json] bg_thread = threading.Thread(target=submit_job_worker)
result = self.server_proxy.post_job_to_server(input_path=input_path, job_list=job_list) bg_thread.start()
if result.ok:
messagebox.showinfo("Success", "Job successfully submitted to server.")
else:
messagebox.showinfo("Error", result.text or "Unknown error")
# clean up
for temp in temp_files:
os.remove(temp)
def main(): def main():

View File

@@ -3,6 +3,7 @@ import os
import json import json
import requests import requests
from lib.render_workers.base_worker import RenderStatus from lib.render_workers.base_worker import RenderStatus
from requests_toolbelt.multipart import MultipartEncoder, MultipartEncoderMonitor
status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', RenderStatus.COMPLETED: 'green', status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', RenderStatus.COMPLETED: 'green',
RenderStatus.NOT_STARTED: "yellow", RenderStatus.SCHEDULED: 'purple', RenderStatus.NOT_STARTED: "yellow", RenderStatus.SCHEDULED: 'purple',
@@ -69,10 +70,21 @@ class RenderServerProxy:
all_data = self.request_data('full_status', timeout=timeout) all_data = self.request_data('full_status', timeout=timeout)
return all_data return all_data
def post_job_to_server(self, input_path, job_list): def post_job_to_server(self, input_path, job_list, callback=None):
# Pack job data and submit to server # Prepare the form data
job_files = {'file': (os.path.basename(input_path), open(input_path, 'rb'), 'application/octet-stream'), encoder = MultipartEncoder({
'json': (None, json.dumps(job_list), 'application/json')} 'file': (os.path.basename(input_path), open(input_path, 'rb'), 'application/octet-stream'),
'json': (None, json.dumps(job_list), 'application/json'),
})
req = requests.post(f'http://{self.hostname}:{self.port}/api/add_job', files=job_files) # Create a monitor that will track the upload progress
return req if callback:
monitor = MultipartEncoderMonitor(encoder, callback(encoder))
else:
monitor = MultipartEncoderMonitor(encoder)
# Send the request
headers = {'Content-Type': monitor.content_type}
response = requests.post(f'http://{self.hostname}:{self.port}/api/add_job', data=monitor, headers=headers)
return response

View File

@@ -11,4 +11,5 @@ future==0.18.3
json2html~=1.3.0 json2html~=1.3.0
SQLAlchemy~=2.0.15 SQLAlchemy~=2.0.15
Pillow~=9.3.0 Pillow~=9.3.0
zeroconf~=0.63.0 zeroconf~=0.63.0
requests-toolbelt~=1.0