mirror of
https://github.com/blw1138/Zordon.git
synced 2025-12-17 08:48:13 +00:00
Add timeouts to engine processes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
/server_state.json
|
/server_state.json
|
||||||
/.scheduler_prefs
|
/.scheduler_prefs
|
||||||
|
/database.db
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class AERender(BaseRenderEngine):
|
|||||||
try:
|
try:
|
||||||
render_path = cls.renderer_path()
|
render_path = cls.renderer_path()
|
||||||
if render_path:
|
if render_path:
|
||||||
ver_out = subprocess.check_output([render_path, '-version'])
|
ver_out = subprocess.check_output([render_path, '-version'], timeout=SUBPROCESS_TIMEOUT)
|
||||||
version = ver_out.decode('utf-8').split(" ")[-1].strip()
|
version = ver_out.decode('utf-8').split(" ")[-1].strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Failed to get {cls.name()} version: {e}')
|
logger.error(f'Failed to get {cls.name()} version: {e}')
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
SUBPROCESS_TIMEOUT = 5
|
||||||
|
|
||||||
|
|
||||||
class BaseRenderEngine(object):
|
class BaseRenderEngine(object):
|
||||||
@@ -18,7 +19,7 @@ class BaseRenderEngine(object):
|
|||||||
def renderer_path(cls):
|
def renderer_path(cls):
|
||||||
path = None
|
path = None
|
||||||
try:
|
try:
|
||||||
path = subprocess.check_output(['which', cls.name()]).decode('utf-8').strip()
|
path = subprocess.check_output(['which', cls.name()], timeout=SUBPROCESS_TIMEOUT).decode('utf-8').strip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
for p in cls.install_paths:
|
for p in cls.install_paths:
|
||||||
if os.path.exists(p):
|
if os.path.exists(p):
|
||||||
@@ -36,7 +37,8 @@ class BaseRenderEngine(object):
|
|||||||
path = cls.renderer_path()
|
path = cls.renderer_path()
|
||||||
if not path:
|
if not path:
|
||||||
raise FileNotFoundError("renderer path not found")
|
raise FileNotFoundError("renderer path not found")
|
||||||
help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT).decode('utf-8')
|
help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT,
|
||||||
|
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
|
||||||
return help_doc
|
return help_doc
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Blender(BaseRenderEngine):
|
|||||||
try:
|
try:
|
||||||
render_path = cls.renderer_path()
|
render_path = cls.renderer_path()
|
||||||
if render_path:
|
if render_path:
|
||||||
ver_out = subprocess.check_output([render_path, '-v'])
|
ver_out = subprocess.check_output([render_path, '-v'], timeout=SUBPROCESS_TIMEOUT)
|
||||||
version = ver_out.decode('utf-8').splitlines()[0].replace('Blender', '').strip()
|
version = ver_out.decode('utf-8').splitlines()[0].replace('Blender', '').strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Failed to get Blender version: {e}')
|
logger.error(f'Failed to get Blender version: {e}')
|
||||||
@@ -30,11 +30,11 @@ class Blender(BaseRenderEngine):
|
|||||||
return formats
|
return formats
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run_python_expression(cls, project_path, python_expression):
|
def run_python_expression(cls, project_path, python_expression, timeout=None):
|
||||||
if os.path.exists(project_path):
|
if os.path.exists(project_path):
|
||||||
try:
|
try:
|
||||||
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python-expr', python_expression],
|
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python-expr', python_expression],
|
||||||
capture_output=True)
|
capture_output=True, timeout=timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error running python expression in blender: {e}")
|
logger.warning(f"Error running python expression in blender: {e}")
|
||||||
pass
|
pass
|
||||||
@@ -42,11 +42,11 @@ class Blender(BaseRenderEngine):
|
|||||||
raise FileNotFoundError(f'Project file not found: {project_path}')
|
raise FileNotFoundError(f'Project file not found: {project_path}')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run_python_script(cls, project_path, script_path):
|
def run_python_script(cls, project_path, script_path, timeout=None):
|
||||||
if os.path.exists(project_path) and os.path.exists(script_path):
|
if os.path.exists(project_path) and os.path.exists(script_path):
|
||||||
try:
|
try:
|
||||||
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python', script_path],
|
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python', script_path],
|
||||||
capture_output=True)
|
capture_output=True, timeout=timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error running python expression in blender: {e}")
|
logger.warning(f"Error running python expression in blender: {e}")
|
||||||
pass
|
pass
|
||||||
@@ -57,11 +57,11 @@ class Blender(BaseRenderEngine):
|
|||||||
raise Exception("Uncaught exception")
|
raise Exception("Uncaught exception")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_scene_info(cls, project_path):
|
def get_scene_info(cls, project_path, timeout=10):
|
||||||
scene_info = None
|
scene_info = None
|
||||||
try:
|
try:
|
||||||
results = cls.run_python_script(project_path, os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
results = cls.run_python_script(project_path, os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
||||||
'scripts', 'get_blender_info.py'))
|
'scripts', 'get_blender_info.py'), timeout=timeout)
|
||||||
result_text = results.stdout.decode()
|
result_text = results.stdout.decode()
|
||||||
for line in result_text.splitlines():
|
for line in result_text.splitlines():
|
||||||
if line.startswith('SCENE_DATA:'):
|
if line.startswith('SCENE_DATA:'):
|
||||||
@@ -73,16 +73,17 @@ class Blender(BaseRenderEngine):
|
|||||||
return scene_info
|
return scene_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def pack_project_file(cls, project_path):
|
def pack_project_file(cls, project_path, timeout=30):
|
||||||
# Credit to L0Lock for pack script - https://blender.stackexchange.com/a/243935
|
# Credit to L0Lock for pack script - https://blender.stackexchange.com/a/243935
|
||||||
pack_expression = "import bpy\n" \
|
pack_expression = "import bpy\n" \
|
||||||
"bpy.ops.file.pack_all()\n" \
|
"bpy.ops.file.pack_all()\n" \
|
||||||
|
"bpy.ops.file.make_paths_absolute()\n" \
|
||||||
"myPath = bpy.data.filepath\n" \
|
"myPath = bpy.data.filepath\n" \
|
||||||
"myPath = str(myPath)\n" \
|
"myPath = str(myPath)\n" \
|
||||||
"bpy.ops.wm.save_as_mainfile(filepath=myPath[:-6]+'_packed'+myPath[-6:])"
|
"bpy.ops.wm.save_as_mainfile(filepath=myPath[:-6]+'_packed'+myPath[-6:])"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = Blender.run_python_expression(project_path, pack_expression)
|
results = Blender.run_python_expression(project_path, pack_expression, timeout=timeout)
|
||||||
|
|
||||||
result_text = results.stdout.decode()
|
result_text = results.stdout.decode()
|
||||||
dir_name = os.path.dirname(project_path)
|
dir_name = os.path.dirname(project_path)
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ class FFMPEG(BaseRenderEngine):
|
|||||||
def version(cls):
|
def version(cls):
|
||||||
version = None
|
version = None
|
||||||
try:
|
try:
|
||||||
ver_out = subprocess.check_output([cls.renderer_path(), '-version']).decode('utf-8')
|
ver_out = subprocess.check_output([cls.renderer_path(), '-version'],
|
||||||
|
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
|
||||||
match = re.match(".*version\s*(\S+)\s*Copyright", ver_out)
|
match = re.match(".*version\s*(\S+)\s*Copyright", ver_out)
|
||||||
if match:
|
if match:
|
||||||
version = match.groups()[0]
|
version = match.groups()[0]
|
||||||
@@ -21,14 +22,16 @@ class FFMPEG(BaseRenderEngine):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_encoders(cls):
|
def get_encoders(cls):
|
||||||
encoders_raw = subprocess.check_output([cls.renderer_path(), '-encoders'], stderr=subprocess.DEVNULL).decode('utf-8')
|
encoders_raw = subprocess.check_output([cls.renderer_path(), '-encoders'], stderr=subprocess.DEVNULL,
|
||||||
|
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
|
||||||
pattern = '(?P<type>[VASFXBD.]{6})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
|
pattern = '(?P<type>[VASFXBD.]{6})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
|
||||||
encoders = [m.groupdict() for m in re.finditer(pattern, encoders_raw)]
|
encoders = [m.groupdict() for m in re.finditer(pattern, encoders_raw)]
|
||||||
return encoders
|
return encoders
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all_formats(cls):
|
def get_all_formats(cls):
|
||||||
formats_raw = subprocess.check_output([cls.renderer_path(), '-formats'], stderr=subprocess.DEVNULL).decode('utf-8')
|
formats_raw = subprocess.check_output([cls.renderer_path(), '-formats'], stderr=subprocess.DEVNULL,
|
||||||
|
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
|
||||||
pattern = '(?P<type>[DE]{1,2})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
|
pattern = '(?P<type>[DE]{1,2})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
|
||||||
formats = [m.groupdict() for m in re.finditer(pattern, formats_raw)]
|
formats = [m.groupdict() for m in re.finditer(pattern, formats_raw)]
|
||||||
return formats
|
return formats
|
||||||
|
|||||||
Reference in New Issue
Block a user