diff --git a/lib/job_server.py b/lib/job_server.py index 0641740..dc06096 100755 --- a/lib/job_server.py +++ b/lib/job_server.py @@ -14,7 +14,7 @@ from flask import Flask, request, render_template, send_file, after_this_request from werkzeug.utils import secure_filename from lib.render_job import RenderJob -from lib.render_queue import RenderQueue +from lib.render_queue import RenderQueue, JobNotFoundError from lib.server_helper import post_job_to_server, generate_thumbnail_for_job from utilities.render_worker import RenderWorkerFactory, string_to_status, RenderStatus @@ -53,22 +53,20 @@ def index(): @server.route('/ui/job//full_details') def job_detail(job_id): found_job = RenderQueue.job_with_id(job_id) - if found_job: - table_html = json2html.json2html.convert(json=found_job.json(), - table_attributes='class="table is-narrow is-striped is-fullwidth"') - media_url = None - if found_job.file_list() and found_job.render_status() == RenderStatus.COMPLETED: - media_basename = os.path.basename(found_job.file_list()[0]) - media_url = f"/api/job/{job_id}/file/{media_basename}" - return render_template('details.html', detail_table=table_html, media_url=media_url, - hostname=RenderQueue.host_name, job_status=found_job.render_status().value.title(), - job=found_job, renderer_info=renderer_info()) - return f'Cannot find job with ID {job_id}', 400 + table_html = json2html.json2html.convert(json=found_job.json(), + table_attributes='class="table is-narrow is-striped is-fullwidth"') + media_url = None + if found_job.file_list() and found_job.render_status() == RenderStatus.COMPLETED: + media_basename = os.path.basename(found_job.file_list()[0]) + media_url = f"/api/job/{job_id}/file/{media_basename}" + return render_template('details.html', detail_table=table_html, media_url=media_url, + hostname=RenderQueue.host_name, job_status=found_job.render_status().value.title(), + job=found_job, renderer_info=renderer_info()) @server.route('/ui/job//thumbnail') def job_thumbnail(job_id): - found_job = RenderQueue.job_with_id(job_id) + found_job = RenderQueue.job_with_id(job_id, none_ok=True) if found_job: os.makedirs(server.config['THUMBS_FOLDER'], exist_ok=True) @@ -112,27 +110,25 @@ def filtered_jobs_json(status_val): return f'Cannot find jobs with status {status_val}', 400 +@server.errorhandler(JobNotFoundError) +def handle_job_not_found(job_error): + return f'Cannot find job with ID {job_error.job_id}', 400 + + @server.get('/api/job/') def get_job_status(job_id): - found_job = RenderQueue.job_with_id(job_id) - if found_job: - return found_job.json() - else: - return f'Cannot find job with ID {job_id}', 400 + return RenderQueue.job_with_id(job_id).json() @server.get('/api/job//logs') def get_job_logs(job_id): found_job = RenderQueue.job_with_id(job_id) - if found_job: - log_path = found_job.worker.log_path - log_data = None - if log_path and os.path.exists(log_path): - with open(log_path) as file: - log_data = file.read() - return Response(log_data, mimetype='text/plain') - else: - return f'Cannot find job with ID {job_id}', 400 + log_path = found_job.worker.log_path + log_data = None + if log_path and os.path.exists(log_path): + with open(log_path) as file: + log_data = file.read() + return Response(log_data, mimetype='text/plain') @server.get('/api/job//file_list') @@ -155,19 +151,16 @@ def download_all(job_id): return response found_job = RenderQueue.job_with_id(job_id) - if found_job: - output_dir = os.path.dirname(found_job.worker.output_path) - if os.path.exists(output_dir): - zip_filename = os.path.join('/tmp', pathlib.Path(found_job.worker.input_path).stem + '.zip') - with ZipFile(zip_filename, 'w') as zipObj: - for f in os.listdir(output_dir): - zipObj.write(filename=os.path.join(output_dir, f), - arcname=os.path.basename(f)) - return send_file(zip_filename, mimetype="zip", as_attachment=True, ) - else: - return f'Cannot find project files for job {job_id}', 500 + output_dir = os.path.dirname(found_job.worker.output_path) + if os.path.exists(output_dir): + zip_filename = os.path.join('/tmp', pathlib.Path(found_job.worker.input_path).stem + '.zip') + with ZipFile(zip_filename, 'w') as zipObj: + for f in os.listdir(output_dir): + zipObj.write(filename=os.path.join(output_dir, f), + arcname=os.path.basename(f)) + return send_file(zip_filename, mimetype="zip", as_attachment=True, ) else: - return f'Cannot find job with ID {job_id}', 400 + return f'Cannot find project files for job {job_id}', 500 @server.post('/api/register_client') @@ -364,13 +357,10 @@ def add_job(job_params, remove_job_dir_on_failure=False): @server.get('/api/job//cancel') def cancel_job(job_id): - found_job = RenderQueue.job_with_id(job_id) - if not found_job: - return f'Cannot find job with ID {job_id}', 400 - elif not request.args.get('confirm', False): + if not request.args.get('confirm', False): return 'Confirmation required to cancel job', 400 - if RenderQueue.cancel_job(found_job): + if RenderQueue.cancel_job(RenderQueue.job_with_id(job_id)): if request.args.get('redirect', False): return redirect(url_for('index')) else: @@ -382,13 +372,11 @@ def cancel_job(job_id): @server.route('/api/job//delete', methods=['POST', 'GET']) def delete_job(job_id): try: - found_job = RenderQueue.job_with_id(job_id) - if not found_job: - return f'Cannot find job with ID {job_id}', 400 - elif not request.args.get('confirm', False): + if not request.args.get('confirm', False): return 'Confirmation required to delete job', 400 # First, remove all render files and logs + found_job = RenderQueue.job_with_id(job_id) files_to_delete = found_job.file_list() files_to_delete.append(found_job.log_path()) for d in files_to_delete: diff --git a/lib/render_queue.py b/lib/render_queue.py index e351e19..9fbe061 100755 --- a/lib/render_queue.py +++ b/lib/render_queue.py @@ -16,6 +16,12 @@ JSON_FILE = 'server_state.json' #todo: move history to sqlite db +class JobNotFoundError(Exception): + def __init__(self, job_id, *args): + super().__init__(args) + self.job_id = job_id + + class RenderQueue: job_queue = [] render_clients = [] @@ -61,8 +67,10 @@ class RenderQueue: return found_jobs @classmethod - def job_with_id(cls, job_id): + def job_with_id(cls, job_id, none_ok=False): found_job = next((x for x in cls.job_queue if x.id == job_id), None) + if not found_job and not none_ok: + raise JobNotFoundError(job_id) return found_job @classmethod