231 lines
6.0 KiB
Python
231 lines
6.0 KiB
Python
"""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
|