162 lines
4.9 KiB
Python
162 lines
4.9 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
import logging
|
|
import queue
|
|
from typing import Tuple
|
|
|
|
import bpy
|
|
from bpy.app.handlers import persistent
|
|
|
|
from . import utils
|
|
|
|
|
|
bk_logger = logging.getLogger(__name__)
|
|
|
|
|
|
@persistent
|
|
def scene_load(context):
|
|
if bpy.app.background is True:
|
|
return
|
|
if not (bpy.app.timers.is_registered(queue_worker)):
|
|
bpy.app.timers.register(queue_worker)
|
|
|
|
|
|
def get_queue():
|
|
# we pick just a random one of blender types, to try to get a persistent queue
|
|
t = bpy.types.Scene
|
|
if not hasattr(t, "task_queue"):
|
|
t.task_queue = queue.Queue()
|
|
return t.task_queue
|
|
|
|
|
|
class task_object:
|
|
def __init__(
|
|
self,
|
|
command="",
|
|
arguments=(),
|
|
wait=0,
|
|
only_last=False,
|
|
fake_context=False,
|
|
fake_context_area="VIEW_3D",
|
|
):
|
|
self.command = command
|
|
self.arguments = arguments
|
|
self.wait = wait
|
|
self.only_last = only_last
|
|
self.fake_context = fake_context
|
|
self.fake_context_area = fake_context_area
|
|
|
|
|
|
def add_task(
|
|
task: Tuple,
|
|
wait=0,
|
|
only_last=False,
|
|
fake_context=False,
|
|
fake_context_area="VIEW_3D",
|
|
):
|
|
q = get_queue()
|
|
taskob = task_object(
|
|
task[0],
|
|
task[1],
|
|
wait=wait,
|
|
only_last=only_last,
|
|
fake_context=fake_context,
|
|
fake_context_area=fake_context_area,
|
|
)
|
|
q.put(taskob)
|
|
|
|
|
|
# @bpy.app.handlers.persistent
|
|
def queue_worker():
|
|
# utils.p('start queue worker timer')
|
|
|
|
# bk_logger.debug('timer queue worker')
|
|
time_step = 0.3
|
|
q = get_queue()
|
|
# save some performance by returning early
|
|
if q.empty():
|
|
return time_step
|
|
back_to_queue = [] # delayed events
|
|
stashed = {}
|
|
# first round we get all tasks that are supposed to be stashed and run only once (only_last option)
|
|
# stashing finds tasks with the property only_last and same command and executes only the last one.
|
|
while not q.empty():
|
|
task = q.get()
|
|
if task.only_last:
|
|
# this now makes the keys not only by task, but also two arguments.
|
|
# by now stashing is only used for ratings, where the first argument is url, second rating type.
|
|
# This enables fast rating of multiple assets while allowing larger delay for uploading of ratings.
|
|
# this avoids a duplicate request error on the server
|
|
stashed[f"{task.command}-{task.arguments[0]}-{task.arguments[1]}"] = task
|
|
else:
|
|
back_to_queue.append(task)
|
|
# return tasks to que except for stashed
|
|
for task in back_to_queue:
|
|
q.put(task)
|
|
# return stashed tasks to queue
|
|
for k in stashed.keys():
|
|
q.put(stashed[k])
|
|
# second round, execute or put back waiting tasks.
|
|
back_to_queue = []
|
|
while not q.empty():
|
|
# print('window manager', bpy.context.window_manager)
|
|
task = q.get()
|
|
|
|
if task.wait > 0:
|
|
task.wait -= time_step
|
|
back_to_queue.append(task)
|
|
else:
|
|
bk_logger.debug(
|
|
"task queue task:" + str(task.command) + str(task.arguments)
|
|
)
|
|
try:
|
|
if task.fake_context:
|
|
fc = utils.get_fake_context(
|
|
bpy.context, area_type=task.fake_context_area
|
|
)
|
|
if bpy.app.version < (4, 0, 0):
|
|
task.command(fc, *task.arguments)
|
|
else:
|
|
with bpy.context.temp_override(**fc):
|
|
task.command(*task.arguments)
|
|
else:
|
|
task.command(*task.arguments)
|
|
except Exception as e:
|
|
bk_logger.error(
|
|
"task queue failed task:"
|
|
+ str(task.command)
|
|
+ str(task.arguments)
|
|
+ str(e)
|
|
)
|
|
# bk_logger.exception('Got exception on main handler')
|
|
# raise
|
|
# print('queue while 2')
|
|
for task in back_to_queue:
|
|
q.put(task)
|
|
# utils.p('end queue worker timer')
|
|
return time_step
|
|
|
|
|
|
def register():
|
|
bpy.app.handlers.load_post.append(scene_load)
|
|
|
|
|
|
def unregister():
|
|
bpy.app.handlers.load_post.remove(scene_load)
|