Files
controller-wisetopdataserver/python/biopro/server/debug.py
T
2021-12-20 14:52:55 +08:00

191 lines
6.0 KiB
Python

from pathlib import Path
from typing import List
from biopro.device.manager import DeviceManager, DeviceManagerOptions, DeviceHardwareInterface
from biopro.devlib.device import DeviceInfo, DeviceResponseInfo
from biopro.file.manager import FileManager, FileOptions
from biopro.file.user.setting import AbstractUserSetting, DummyUserSetting
from biopro.util.address import EMPTY_ADDRESS
from biopro.util.cli_base import CliOptions
from biopro.util.console import RED
from biopro.util.json import JSON_OBJECT
from biopro.util.logger import logging_info
from .controller import ControlServerOptions, ControlServerAPI, HardwareInfo, to_device_info
from .socket import *
_RUNTIME_COMPILE = False
class DebugControllerOptions(CliOptions):
def __init__(self):
self.user_validation = True
self.allow_task_thread = False
self.task_thread_pool_size = 4
self.allow_routine_thread = False
if _RUNTIME_COMPILE:
DebugControllerServer = None
else:
# noinspection PyAbstractClass
class DebugControllerServer(LoggerFlag, ControlServerAPI):
def __init__(self, *options: CliOptions):
super().__init__('Debug', RED)
self.log_verbose('init')
self._debug_options = o = DebugControllerOptions.get_options(*options)
# controller options
self._controller_options = c = ControlServerOptions.get_options(*options)
# file manager
f = FileOptions.with_default_structure(Path(c.storage_root).absolute())
f.debug_account_system = True
self._file_manager = FileManager(f)
# device manager
d = DeviceManagerOptions.get_options(*options)
if d is None:
d = DeviceManagerOptions()
d.interface = DeviceHardwareInterface.INTERFACE_NULL
self._device_manager = DeviceManager(d, self)
# setup
self.log_verbose('setup file manager')
self._file_manager.setup_storage()
self.log_verbose('setup device manager')
self._device_manager.setup()
# setup
if o.allow_task_thread:
self.log_verbose('setup task thread pool')
self._executor = ThreadPoolExecutor(max_workers=o.task_thread_pool_size)
if o.allow_routine_thread:
self.log_verbose('setup routine thread manager')
self._routine: List[ServerThread] = []
self.log_verbose('done')
@property
def options(self) -> ControlServerOptions:
return self._controller_options
@property
def file_manager(self) -> FileManager:
return self._file_manager
@property
def device_manager(self) -> DeviceManager:
return self._device_manager
def hardware_info(self) -> HardwareInfo:
return HardwareInfo("debug")
def hardware_device_found(self, content: Union[str, JSON_OBJECT, DeviceInfo], *,
scan: Union[str, bool] = False) -> Optional[DeviceResponseInfo]:
if isinstance(content, DeviceInfo):
response = content
else:
response = to_device_info(content)
ret = super().hardware_device_found(response, scan=scan)
if ret is not None:
# if found, just return
return ret
if not scan:
# if not scan mode, return result
return None
if response.mac_address == EMPTY_ADDRESS:
# create demo device
return self.device_manager.create_demo_device(response.device_name)
return None
def user_info(self, user: str, *, user_session: Optional[str] = None) -> Optional[AbstractUserSetting]:
if self._debug_options.user_validation:
return super().user_info(user, user_session=user_session)
elif user in self.user_all():
self.log_verbose('use user', user)
return super().user_info(user, user_session=user_session)
else:
self.log_verbose('use dummy user', ':', user)
ret = DummyUserSetting(user)
self.file_manager.user_setting._user_add(ret)
return ret
@logging_info
def submit_thread(self, f, *args):
if self._debug_options.allow_task_thread:
self._executor.submit(f, *args)
else:
raise RuntimeError('cannot submit task thread')
@logging_info
def run_thread(self, thread: T_ServerThread) -> T_ServerThread:
if self._debug_options.allow_routine_thread:
thread.log_verbose('start')
Thread(target=self._run_thread,
name=thread.log_name,
args=(thread,),
daemon=True).start()
return thread
else:
raise RuntimeError('cannot run routine thread')
def _run_thread(self, thread: ServerThread):
try:
self._routine.append(thread)
thread.log_verbose('setup')
thread.setup()
if not thread.is_closed:
thread.log_verbose('routine')
while not thread.is_closed:
thread.routine()
except ServerShutdownException as e:
self.interrupt(e)
except ServerThreadClosedInterrupt:
pass
except:
print_exception(self)
finally:
try:
thread.log_verbose('closing')
thread.shutdown()
except KeyboardInterrupt:
thread.log_warn('closing interrupt')
finally:
try:
self._routine.remove(thread)
except ValueError:
pass
thread.log_verbose('closed')