From 93d50ac56b8baf147978fbf7b1127e4d2741ed87 Mon Sep 17 00:00:00 2001 From: Swann Date: Thu, 22 Apr 2021 10:04:38 +0200 Subject: [PATCH] refactor: porcail api --- multi_user/operators.py | 151 +++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 81 deletions(-) diff --git a/multi_user/operators.py b/multi_user/operators.py index 5cdd59e..4cfdbc8 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -59,6 +59,7 @@ background_execution_queue = Queue() deleyables = [] stop_modal_executor = False + def session_callback(name): """ Session callback wrapper @@ -89,7 +90,7 @@ def initialize_session(): logging.error(f"Can't construct node {node}") elif node_ref.state == FETCHED: node_ref.resolve() - + # Step 2: Load nodes logging.info("Loading nodes") for node in session.repository.list_ordered(): @@ -140,7 +141,8 @@ def on_connection_end(reason="none"): if isinstance(handler, logging.FileHandler): logger.removeHandler(handler) if reason != "user": - bpy.ops.session.notify('INVOKE_DEFAULT', message=f"Disconnected from session. Reason: {reason}. ") + bpy.ops.session.notify( + 'INVOKE_DEFAULT', message=f"Disconnected from session. Reason: {reason}. ") # OPERATORS @@ -190,8 +192,8 @@ class SessionStartOperator(bpy.types.Operator): handler.setFormatter(formatter) bpy_protocol = io_bpy.get_data_translation_protocol() - - # Check if supported_datablocks are up to date before starting the + + # Check if supported_datablocks are up to date before starting the # the session for impl in bpy_protocol.implementations.values(): if impl.__name__ not in settings.supported_datablocks: @@ -205,78 +207,61 @@ class SessionStartOperator(bpy.types.Operator): else: python_binary_path = bpy.app.binary_path_python - # Host a session + # HOST if self.host: if settings.init_method == 'EMPTY': utils.clean_scene() - try: - # Init repository - for scene in bpy.data.scenes: - porcelain.add(repo, scene) - - # Create an empty repository - repo = Repository( - data_protocol=bpy_protocol) + # Start the server locally + server = porcelain.serve(port=settings.port, + timeout=settings.connection_timeout, + admin_password=admin_pass, + log_directory=settings.cache_directory) - session.host( - repository= repo, - id=settings.username, - port=settings.port, - timeout=settings.connection_timeout, - password=admin_pass, - cache_directory=settings.cache_directory, - server_log_level=logging.getLevelName( - logging.getLogger().level), - ) - except Exception as e: - self.report({'ERROR'}, repr(e)) - logging.error(f"Error: {e}") - traceback.print_exc() - # Join a session + # Init repository + repo = porcelain.init(bare=False, + data_protocol=bpy_protocol) + + # Add the existing scenes + for scene in bpy.data.scenes: + porcelain.add(repo, scene) + + porcelain.remote_add(repo, + 'server', + '127.0.0.1', + settings.port) + porcelain.sync(repo, 'server') + porcelain.push(repo, 'server') + # JOIN else: - if not runtime_settings.admin: - utils.clean_scene() - # regular session, no password needed - admin_pass = None + utils.clean_scene() - try: - session.connect( - repository= repo, - id=settings.username, - address=settings.ip, - port=settings.port, - timeout=settings.connection_timeout, - password=admin_pass - ) - except Exception as e: - self.report({'ERROR'}, str(e)) - logging.error(str(e)) + repo = porcelain.clone(settings.ip, settings.ip) # Background client updates service - deleyables.append(timers.ClientUpdate()) - deleyables.append(timers.DynamicRightSelectTimer()) - deleyables.append(timers.ApplyTimer(timeout=settings.depsgraph_update_rate)) + # deleyables.append(timers.ClientUpdate()) + # deleyables.append(timers.DynamicRightSelectTimer()) + # deleyables.append(timers.ApplyTimer( + # timeout=settings.depsgraph_update_rate)) # deleyables.append(timers.PushTimer( # queue=stagging, # timeout=settings.depsgraph_update_rate # )) - session_update = timers.SessionStatusUpdate() - session_user_sync = timers.SessionUserSync() - session_background_executor = timers.MainThreadExecutor( - execution_queue=background_execution_queue) - session_listen = timers.SessionListenTimer(timeout=0.001) + # session_update = timers.SessionStatusUpdate() + # session_user_sync = timers.SessionUserSync() + # session_background_executor = timers.MainThreadExecutor( + # execution_queue=background_execution_queue) + # session_listen = timers.SessionListenTimer(timeout=0.001) - session_listen.register() - session_update.register() - session_user_sync.register() - session_background_executor.register() + # session_listen.register() + # session_update.register() + # session_user_sync.register() + # session_background_executor.register() - deleyables.append(session_background_executor) - deleyables.append(session_update) - deleyables.append(session_user_sync) - deleyables.append(session_listen) - + # deleyables.append(session_background_executor) + # deleyables.append(session_update) + # deleyables.append(session_user_sync) + # deleyables.append(session_listen) self.report( {'INFO'}, @@ -589,20 +574,20 @@ class SessionApply(bpy.types.Operator): try: node_ref = session.repository.get_node(self.target) porcelain.apply(session.repository, - self.target, - force=True, - force_dependencies=self.reset_dependencies) + self.target, + force=True, + force_dependencies=self.reset_dependencies) if node_ref.bl_reload_parent: for parent in session.repository.get_parents(self.target): logging.debug(f"Refresh parent {parent}") porcelain.apply(session.repository, - parent.uuid, - force=True) + parent.uuid, + force=True) except Exception as e: self.report({'ERROR'}, repr(e)) traceback.print_exc() - return {"CANCELLED"} + return {"CANCELLED"} return {"FINISHED"} @@ -628,6 +613,7 @@ class SessionCommit(bpy.types.Operator): self.report({'ERROR'}, repr(e)) return {"CANCELED"} + class ApplyArmatureOperator(bpy.types.Operator): """Operator which runs its self from a timer""" bl_idname = "session.apply_armature_operator" @@ -699,6 +685,7 @@ class SessionClearCache(bpy.types.Operator): row = self.layout row.label(text=f" Do you really want to remove local cache ? ") + class SessionPurgeOperator(bpy.types.Operator): "Remove node with lost references" bl_idname = "session.purge" @@ -743,7 +730,6 @@ class SessionNotifyOperator(bpy.types.Operator): layout = self.layout layout.row().label(text=self.message) - def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self) @@ -789,6 +775,7 @@ class SessionSaveBackupOperator(bpy.types.Operator, ExportHelper): def poll(cls, context): return session.state == STATE_ACTIVE + class SessionStopAutoSaveOperator(bpy.types.Operator): bl_idname = "session.cancel_autosave" bl_label = "Cancel auto-save" @@ -829,15 +816,13 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper): except OSError as e: f = open(self.filepath, "rb") db = pickle.load(f) - + if db: logging.info(f"Reading {self.filepath}") nodes = db.get("nodes") logging.info(f"{len(nodes)} Nodes to load") - - # init the factory with supported types bpy_protocol = DataTranslationProtocol() for type in io_bpy.types_to_register(): @@ -846,11 +831,10 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper): type_impl_name = 'Bl'+''.join(name) type_module_class = getattr(type_module, type_impl_name) - bpy_protocol.register_type( type_module_class.bl_class, type_module_class) - + graph = Repository() for node, node_data in nodes: @@ -866,7 +850,7 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper): data=node_data['data']) graph.do_commit(instance) instance.state = FETCHED - + logging.info("Graph succefully loaded") utils.clean_scene() @@ -879,15 +863,16 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper): for node in graph.list_ordered(): graph[node].apply() - return {'FINISHED'} @classmethod def poll(cls, context): return True + def menu_func_import(self, context): - self.layout.operator(SessionLoadSaveOperator.bl_idname, text='Multi-user session snapshot (.db)') + self.layout.operator(SessionLoadSaveOperator.bl_idname, + text='Multi-user session snapshot (.db)') classes = ( @@ -910,6 +895,7 @@ classes = ( SessionPurgeOperator, ) + def update_external_dependencies(): nodes_ids = session.list(filter=io_bpy.bl_file.BlFile) for node_id in nodes_ids: @@ -919,6 +905,7 @@ def update_external_dependencies(): porcelain.commit(session.repository, node_id) session.push(node_id, check_data=False) + def sanitize_deps_graph(remove_nodes: bool = False): """ Cleanup the replication graph """ @@ -950,6 +937,7 @@ def resolve_deps_graph(dummy): if session and session.state == STATE_ACTIVE: sanitize_deps_graph(remove_nodes=True) + @persistent def load_pre_handler(dummy): if session and session.state in [STATE_ACTIVE, STATE_SYNCING]: @@ -980,7 +968,7 @@ def depsgraph_evaluation(scene): if update.id.uuid: # Retrieve local version node = session.repository.get_node(update.id.uuid) - + # Check our right on this update: # - if its ours or ( under common and diff), launch the # update process @@ -994,12 +982,12 @@ def depsgraph_evaluation(scene): except ReferenceError: logging.debug(f"Reference error {node.uuid}") except ContextError as e: - logging.debug(e) + logging.debug(e) except Exception as e: logging.error(e) else: continue - # A new scene is created + # A new scene is created elif isinstance(update.id, bpy.types.Scene): ref = session.repository.get_node_by_datablock(update.id) if ref: @@ -1008,13 +996,14 @@ def depsgraph_evaluation(scene): scn_uuid = porcelain.add(session.repository, update.id) porcelain.commit(session.repository, scn_uuid) porcelain.push(session.repository) + + def register(): from bpy.utils import register_class - for cls in classes: + for cls in classes: register_class(cls) - bpy.app.handlers.undo_post.append(resolve_deps_graph) bpy.app.handlers.redo_post.append(resolve_deps_graph)