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

485 lines
15 KiB
Python

"""program main.
Server Options
--------------
Options Files
~~~~~~~~~~~~~
* ``/etc/BPS/default.config``
* ``$HOME/.default.config``
Options (main)
~~~~~~~~~~~~~~
::
./BioProController/RaspBerryPi3/python/biopro/main.py [OPTIONS] COMMANDS
OPTIONS
-h, --help print help document
--version print version
COMMANDS
controller controller server
data data server
export file service
Options (controller)
~~~~~~~~~~~~~~~~~~~~
::
./BioProController/RaspBerryPi3/python/biopro/main.py controller [OPTIONS]
OPTIONS
-O, --option-file FILE load options from file
-h, --help print help document
--version print version
Cache Manager
--cache-size SIZE cache size limit. default : None
--cache-time SEC cache data time. default : 10
--disable-cache-server disable cache server process
Control Server Options
--disable-sha-check disable sha checking
--user-session-expire DAYS set user session expire days
Data Server Options
--disable-data-server disable data server process
--disable-data-statistics disable data lost statistics
--spi-mode VALUE spi mode. could be:
disable :
single : use ExtMemSpiInterface
selector : use MultiExtMemSpiInterface (default)
Device Manager Options
-L, --library PATH
-i, --interface INT hardware interface. could be:
CC2650 : Bluetooth Low Energy CC2650 with multiple board
CC2650_S : Bluetooth Low Energy CC2650 with single board
NULL : null hardware (debug use).
Dummy : Dummy hardware
fallback:INT,... : try using interface (default: fallback:CC2650,Dummy)
--device-log-level LEVEL device log level. could be (case insensitive):
verbose
info
warn
error
disable, quiet
--disable-data-length-extension CC2650 master device options. disable BLE feature about data length extension
--expected-channel CH,...
--selector DEVICE,... only use certain selector channel, it can reduce the controller setup times.
--shutdown-if-reset-fail shutdown the controller if device reset fail
Experimental Protocol Options
-P PATH experimental resource path
--disable-exp-manager disable experimental protocol
File Manager Options
-C, --root PATH change the storage root
-E, --export PATH change the export root
-M, --external-map NAME:PATH map external storage path
--disable-external-storage disable use external storage device
--disable-routine-trash disable routine trashing
--expire-remove DAYS the expire time for file in trash to be removed
--expire-trash DAYS the expire time for file to be trashed
--routine-trash HOURS routine period for trash files
LED control
--disable-led-control disable LED control
--disable-led-refresh disable LED refresh simple color
--led-count COUNT set led count
Profile Options (DEBUG)
--profile [METHOD] enable profiling and choose profile method. could be:
profile : use cProfile
yappi : use yappi (default, require yappi)
--profile-output PATH profiling file output path
--profile-output-type FORMAT profiling file format. could be:
raw :
text : (default)
dot : (required gprof2dot)
--profile-sorting FIELDs the sorting method of the field in profiling state.
detail : https://docs.python.org/3.5/library/profile.html#pstats.Stats.sort_stats
Remote System
--disable-remote-server disable remote server connecting
--remote-server-address IP:PORT change the remote server IP
UPS control
--disable-ups-detect disable UPS power use detect
--ups-wait-time MIN ups wait time when low power
Websocket Server
--websocket-address URL[:PORT] set the websocket address and port
--websocket-port PORT set the websocket port
Options (data)
~~~~~~~~~~~~~~
::
./BioProController/RaspBerryPi3/python/biopro/main.py data [OPTIONS]
OPTIONS
-h, --help print help document
Data Server Options
-L, --library PATH
--disable-data-statistics disable data lost statistics
--spi-mode VALUE spi mode. could be:
disable :
single : use ExtMemSpiInterface
selector : use MultiExtMemSpiInterface (default)
Profile Options (DEBUG)
--profile [METHOD] enable profiling and choose profile method. could be:
profile : use cProfile
yappi : use yappi (default, require yappi)
--profile-output PATH profiling file output path
--profile-output-type FORMAT profiling file format. could be:
raw :
text : (default)
dot : (required gprof2dot)
--profile-sorting FIELDs the sorting method of the field in profiling state.
detail : https://docs.python.org/3.5/library/profile.html#pstats.Stats.sort_stats
Options (export)
~~~~~~~~~~~~~~~~
::
./BioProController/RaspBerryPi3/python/biopro/main.py export [OPTIONS] PATH
OPTIONS
-A, --async async export
-C, --root PATH change the storage root
-E, --export PATH change the export root
-T, --type FORMAT export type
-U, --user-repository PATH change the user repository
-f, --overwrite overwrite output file if it existed
-h, --help print help document or export function
-o, --output PATH export to PATH.
-q, --quiet quiet output
--[KEY=VALUE] export parameter
--strict strict mode
ARGUMENTS
PATH source PATH
Export Function
txt raw text
csv Comma-Separated Values
"""
import abc
import re
import sys
from pathlib import Path
from typing import List, TypeVar, Optional, Callable
from biopro import NAME, VERSION, REV_VERSION, COPYRIGHT
from biopro.server import SocketServer
from biopro.util.cli import *
from biopro.util.logger import Logger
_RUNTIME_COMPILE = False
# noinspection PyUnusedLocal
class Main(CliMain):
def __init__(self):
super().__init__()
self.extend_options(Logger.OPTIONS)
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_flags('--version', force_return=True)
def _version(self, opt: str):
"""print version"""
print(NAME, ', version', VERSION)
print(COPYRIGHT)
print('git-rev', REV_VERSION)
@cli_command('controller')
def _controller_server(self, command: str, argv: List[str]):
"""controller server"""
return _ControlServer
@cli_command('data')
def _data_server(self, command: str, argv: List[str]):
"""data server"""
return _DataServer
@cli_command('export')
def _export_file_service(self, command: str, argv: List[str]):
"""file service"""
from biopro.file.export import FileExportMain
return FileExportMain(command)
@cli_command('led')
def _led_control_service(self, command: str, argv: List[str]):
"""led control"""
from biopro.impl.led import LEDControlMain
return LEDControlMain(command)
def run(self):
self.print_help()
S = TypeVar('S', bound=SocketServer)
# noinspection PyUnusedLocal
class _ServerMain(CliSubCommandMain, metaclass=abc.ABCMeta):
def __init__(self, command: str):
from biopro.util.profile import ProfileOptions
super().__init__(command)
self.extend_options(Logger.OPTIONS)
if not _RUNTIME_COMPILE:
# profile
self.profiling_options = self.extend_options(ProfileOptions(),
help_section='Profile Options (DEBUG)')
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@abc.abstractmethod
def create_server(self) -> SocketServer:
pass
def run(self):
exit_code = 1
server = self.create_server()
if _RUNTIME_COMPILE:
exit_code = server.main()
else:
with self.profiling_options.generate_profile_context():
exit_code = server.main()
sys.exit(exit_code)
# noinspection PyUnusedLocal
class _ControlServer(_ServerMain):
LOCAL_CONFIG_FILENAME = '.BPS.config'
def __init__(self, command: str):
from biopro.server.controller import ControlServerOptions
from biopro.device.manager import DeviceManagerOptions
from biopro.server.data import DataServerOptions
from biopro.exp_pro.manager import ExpManagerOption
super().__init__(command)
# controller options
self.server_controller_options = self.extend_options(ControlServerOptions(),
help_section='Control Server Options')
# device manager options
self.server_device_options = self.extend_options(DeviceManagerOptions(),
help_section='Device Manager Options')
# data server options
self.server_data_options = self.extend_options(DataServerOptions(),
help_section='Data Server Options',
options_mapper={
'-L': None,
'--library': None,
})
# experimental manager options
self.server_exp_options = self.extend_options(ExpManagerOption(),
help_section='Experimental Protocol Options')
@cli_flags('--version', force_return=True)
def _version(self, opt: str):
"""print version"""
print(NAME, ', version', VERSION)
print(COPYRIGHT)
print('git-rev', REV_VERSION)
def parsing(self,
argv: List[str],
parsing_sub_command=True,
on_unknown_argument: Callable[[int, str], bool] = None) -> Optional[List[str]]:
c = Path.home() / self.LOCAL_CONFIG_FILENAME
# default load config file from file system
self._options_file('-O', '/etc/BPS/default.config')
self._options_file('-O', str(c))
# generate local runtime configuration file
if not c.exists():
with c.open('w'):
pass
print('create file at', str(c))
# then do options from cli
return super().parsing(argv, parsing_sub_command, on_unknown_argument)
@cli_options('-O', '--option-file', value='FILE')
def _options_file(self, opt: str, value: str):
"""load options from file"""
f = Path(value)
if f.exists():
restrict_mode = value != '/etc/BPS/default.config'
argv = self._load_option_file(f, restrict_mode)
if len(argv) > 0:
def _on_unknown_argument(index: int, arg: str) -> bool:
print('unknown argument or options : ' + arg)
return True
super().parsing(argv,
parsing_sub_command=False,
on_unknown_argument=_on_unknown_argument)
@staticmethod
def _load_option_file(path: Path, restrict_mode: bool) -> List[str]:
argv = []
if path.exists():
with path.open('r') as _f:
for line in _f:
line = line.strip()
if len(line) == 0 or line.startswith('#'):
continue
if '#' in line:
line = line[:line.index('#')].strip()
if ' ' in line:
line = re.sub(' +', '=', line, count=1)
if restrict_mode:
if line.startswith('-C') or \
line.startswith('-U') or \
line.startswith('-L') or \
line.startswith('-i') or line.startswith('--interface'):
continue
argv.append(line)
return argv
def create_server(self) -> SocketServer:
from biopro.server.main import ControlServer
return ControlServer(self.server_device_options,
self.server_data_options,
self.server_controller_options,
self.server_exp_options)
# noinspection PyUnusedLocal
class _DataServer(_ServerMain):
def __init__(self, command: str):
from biopro.server.data import DataServerOptions
super().__init__(command)
# data server options
self.server_data_options = self.extend_options(DataServerOptions(),
help_section='Data Server Options')
def create_server(self) -> SocketServer:
from biopro.server.data import DataServer
return DataServer(self.server_data_options)
if __name__ == '__main__':
Main().main()