Files
controller-wisetopdataserver/python/biopro/devlib/lock.py
T

231 lines
6.0 KiB
Python
Raw Normal View History

2021-12-20 14:52:55 +08:00
"""Device lock.
This module provide device lock let user can lock device(s). User can control the device if he/she own the lock.
Otherwise, others just only view/read the device setting and data.
Device Lock Level
=================
1. Experimental lock
2. General lock
3. Timeout lock
4. Public lock
"""
import abc
from time import time
from typing import Optional
class AbstractDeviceLock(metaclass=abc.ABCMeta):
LOCK_EXPERIMENTAL = 1
LOCK_GENERAL = 2
LOCK_TIMEOUT = 3
LOCK_PUBLIC = 4
TIMEOUT_MIN = 10
@property
@abc.abstractmethod
def experimental(self) -> Optional[str]:
pass
@property
@abc.abstractmethod
def user_name(self) -> Optional[str]:
pass
@property
@abc.abstractmethod
def priority(self) -> int:
pass
@abc.abstractmethod
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
pass
@abc.abstractmethod
def flush(self, touch: bool) -> 'AbstractDeviceLock':
pass
class DeviceLock(AbstractDeviceLock):
__slots__ = '__last_access_time', '__lock'
def __init__(self):
self.__last_access_time = time()
self.__lock: AbstractDeviceLock = PublicLock()
@property
def experimental(self) -> Optional[str]:
return self.__lock.experimental
@property
def user_name(self) -> Optional[str]:
return self.__lock.user_name
@property
def priority(self) -> int:
return self.__lock.priority
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
return self.__lock.validate(lock, user_name=user_name, experimental=experimental)
def gain_priority(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
if self.__lock.validate(lock, user_name=user_name, experimental=experimental):
if self.__lock.priority == lock:
return True
elif lock == self.LOCK_EXPERIMENTAL:
self.__lock = ExperimentalLock(experimental, user_name)
return True
elif lock == self.LOCK_GENERAL:
self.__lock = GeneralLock(user_name)
return True
return False
def flush(self, touch: bool) -> 'AbstractDeviceLock':
self.__lock: AbstractDeviceLock = self.__lock.flush(touch)
return self
def release(self, user_name: str, experimental: str) -> bool:
if self.__lock.validate(self.LOCK_EXPERIMENTAL, user_name=user_name, experimental=experimental):
self.__lock = GeneralLock(user_name)
return True
else:
return False
def public(self):
if self.__lock == self.LOCK_EXPERIMENTAL:
raise RuntimeError('experimental lock not release')
else:
self.__lock = PublicLock()
class ExperimentalLock(AbstractDeviceLock):
PRIORITY = DeviceLock.LOCK_EXPERIMENTAL
__slots__ = '__experimental', '__user_name'
def __init__(self, experiment: str, user_name: str):
"""
:param experiment: experimental protocol ID
:param user_name: user name
"""
self.__experimental = experiment
self.__user_name = user_name
@property
def experimental(self) -> str:
return self.__experimental
@property
def user_name(self) -> str:
return self.__user_name
@property
def priority(self) -> int:
return self.LOCK_EXPERIMENTAL
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
if lock > self.LOCK_EXPERIMENTAL:
return False
return self.__experimental == experimental and self.__user_name == user_name
def flush(self, touch: bool) -> 'AbstractDeviceLock':
return self
class GeneralLock(AbstractDeviceLock):
__slots__ = '__user_name', '__last_access'
def __init__(self, user_name: str):
"""
:param user_name: user name
"""
self.__user_name = user_name
self.__last_access = time()
@property
def experimental(self) -> Optional[str]:
return None
@property
def user_name(self) -> str:
return self.__user_name
@property
def priority(self) -> int:
return self.LOCK_GENERAL
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
if lock == self.LOCK_EXPERIMENTAL:
return self.__user_name == user_name
elif lock == self.LOCK_GENERAL:
return self.__user_name == user_name
return False
def flush(self, touch: bool) -> 'AbstractDeviceLock':
t = time()
if touch:
self.__last_access = t
return self
else:
if t - self.__last_access > self.TIMEOUT_MIN * 60:
return TimeoutLock(self.__user_name)
else:
return self
class TimeoutLock(AbstractDeviceLock):
__slots__ = '__user_name',
def __init__(self, user_name: str):
"""
:param user_name: user name
"""
self.__user_name = user_name
@property
def experimental(self) -> Optional[str]:
return None
@property
def user_name(self) -> str:
return self.__user_name
@property
def priority(self) -> int:
return self.LOCK_TIMEOUT
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
return lock <= self.LOCK_TIMEOUT
def flush(self, touch: bool) -> 'AbstractDeviceLock':
return self
class PublicLock(AbstractDeviceLock):
@property
def experimental(self) -> Optional[str]:
return None
@property
def user_name(self) -> Optional[str]:
return None
@property
def priority(self) -> int:
return self.LOCK_PUBLIC
def validate(self, lock: int, *, user_name: str = None, experimental: str = None) -> bool:
return True
def flush(self, touch: bool) -> 'AbstractDeviceLock':
return self