485 lines
15 KiB
Python
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()
|