def check_downgrade(self, obj_id: str, owner: str) -> None: """Check if lock can be downgraded to single object lock.""" raise_msg = f"{obj_id} lock is not owned by {owner}." if obj_id not in self.write: raise LockingException(raise_msg) if owner != self.write[obj_id]: raise LockingException(raise_msg) if not self.tree: raise LockingException( f"Nothing to downgrade for {obj_id} and owner {owner}.")
def check_upgrade(self, obj_id: str, owner: str) -> None: """Check if lock can be upgraded to whole locked tree.""" raise_msg = f"{obj_id} lock is not owned by {owner}." if obj_id not in self.write: raise LockingException(raise_msg) if len(self.write) > 1: raise LockingException(raise_msg) if owner != self.write[obj_id]: raise LockingException(raise_msg) if self.tree: raise LockingException( f"Nothing to upgrade for {obj_id} and owner {owner}.")
async def ensure_read_locked(obj_id: str, owner: str, locked_tree: bool = False) -> None: """Check if object is read locked.""" if not await glob.LOCK.is_read_locked(obj_id, owner): raise LockingException("Object is not write locked.")
async def start_scene_cb(req: srpc.s.StartScene.Request, ui: WsClient) -> None: scene = glob.LOCK.scene_or_exception() if get_scene_state( ).data.state != sevts.s.SceneState.Data.StateEnum.Stopped: raise Arcor2Exception("Scene not stopped.") # online scene can't be modified so we demand that UIs free all their locks first # when editing project, changes can be done both online and offline if not glob.LOCK.project and await glob.LOCK.get_write_locks_count(): raise LockingException(glob.LOCK.ErrMessages.SOMETHING_LOCKED.value) if await glob.LOCK.is_write_locked(glob.LOCK.SpecialValues.SCENE_NAME, glob.LOCK.SpecialValues.SERVER_NAME): raise Arcor2Exception("Scene locked.") if await glob.LOCK.is_write_locked(glob.LOCK.SpecialValues.PROJECT_NAME, glob.LOCK.SpecialValues.SERVER_NAME): raise Arcor2Exception("Project locked.") if req.dry_run: return asyncio.ensure_future(start_scene(scene))
async def close_scene_cb(req: srpc.s.CloseScene.Request, ui: WsClient) -> None: """Closes scene on the server. :param req: :return: """ async with ctx_write_lock(glob.LOCK.SpecialValues.SCENE_NAME, glob.USERS.user_name(ui), dry_run=req.dry_run): scene = glob.LOCK.scene_or_exception() if glob.LOCK.project: raise Arcor2Exception("Project has to be closed first.") if not req.args.force and scene.has_changes: raise Arcor2Exception("Scene has unsaved changes.") can_modify_scene() # can't close scene while started if await glob.LOCK.get_locked_roots_count() > 1: raise LockingException( glob.LOCK.ErrMessages.SOMETHING_LOCKED.value) if req.dry_run: return None scene_id = scene.id glob.LOCK.scene = None glob.OBJECTS_WITH_UPDATED_POSE.clear() asyncio.ensure_future(notify_scene_closed(scene_id))
async def ensure_locked(obj_id: str, ui: WsClient, locked_tree: bool = False) -> None: """Check if object is write locked. Read lock check not needed yet. """ if not await glob.LOCK.is_write_locked(obj_id, glob.USERS.user_name(ui), locked_tree): raise LockingException(glob.LOCK.ErrMessages.NOT_LOCKED.value)
async def update_lock(self, obj_id: str, owner: str, upgrade_type: UpdateType) -> None: """Upgrades lock to locked whole tree or downgrades lock to simple object lock. :param obj_id: objects which is locked and updated :param owner: owner of current lock :param upgrade_type: one of available type """ root_id = await self.get_root_id(obj_id) async with self._lock: if root_id not in self._locked_objects: raise LockingException(self.ErrMessages.NOT_LOCKED.value) lock_record = self._get_lock_record(root_id) if upgrade_type == UpdateType.TREE: lock_record.check_upgrade(obj_id, owner) lock_record.tree = True to_notify = self.get_all_children(root_id) to_notify.add(root_id) to_notify.remove(obj_id) evt = LockEventData(to_notify, owner, True) self._upsert_user_locked_objects(owner, to_notify) elif upgrade_type == UpdateType.OBJECT: lock_record.check_downgrade(obj_id, owner) lock_record.tree = False to_notify = self.get_all_children(root_id) to_notify.add(root_id) to_notify -= {obj_id} evt = LockEventData(to_notify, owner) self._remove_user_locked_objects(owner, to_notify) else: raise Arcor2Exception("Unknown type of lock upgrade") self.notifications_q.put_nowait(evt)