class MainWorker(QObject): kill_all = Signal() max_grid_size = 50 max_grid_cnt = 5 config = None # element configuration updateLogdate = Signal(object) # update displayed date string in stdin_reader updateConfig = Signal(object) # update configuration in execution operator startExec = Signal(object) # element-Id stopExec = Signal(object) # element-Id saveConfig = Signal(object) # configuration sysCommand = Signal(object) # Optional: Element Constructor / Destructor frontendCtrl = Signal(object) queryStates = Signal() # Query the running states of elements startAll = Signal(object) # Start all elements: (config) stopAll = Signal() # Stop all elements killAll = Signal() # Kill all running processes def __init__(self, app): super(MainWorker, self).__init__() self.app = app # Setup command line arguments parser = argparse.ArgumentParser(description='Pythonic background daemon') # Debug output switch parser.add_argument('-Ex', action='store_true', help='Interactive shell interface, Unix only') # Log level parser.add_argument('-v', action='store_true', help='Verbose output') self.args = parser.parse_args() # Set Log Level if self.args.v: log_level = logging.DEBUG else: log_level = logging.INFO # Instantiate the LogFileHandler self.logFileHandler = LogFileHandler(log_level) # Select multiprocessing spawn method mp.set_start_method('spawn') # Set working directory os.chdir(Path(__file__).parent.absolute()) # Setup format locale.setlocale(locale.LC_TIME, '') # Instantiate WSGI Server self.wsgi_server = WSGI_Server(self) # Instantiate Execution Operator self.operator = Operator() self.operator.command.connect(self.forwardCmd) self.startExec.connect(self.operator.startExec) self.stopExec.connect(self.operator.stopExec) self.updateConfig.connect(self.operator.updateConfig) self.queryStates.connect(self.operator.getElementStates) self.startAll.connect(self.operator.startAll) self.stopAll.connect(self.operator.stopAll) self.killAll.connect(self.operator.killAll) # Instantiate Standard Input Reader (Unix only) if self.args.Ex: try: from stdin_reader import stdinReader except ImportError: from Pythonic.stdin_reader import stdinReader self.stdinReader = stdinReader(self.operator.processHandles.items(), self.logFileHandler.log_date_str) self.stdinReader.quit_app.connect(self.exitApp) # Connect the logger if self.args.Ex: self.logFileHandler.updateLogdate.connect(self.stdinReader.updateLogDate) # Instantiate ToolboxLoader self.toolbox_loader = ToolboxLoader() self.toolbox_loader.tooldataLoaded.connect(self.forwardCmd) # Instantiate (Element)-EditorLoader self.editor_loader = EditorLoader() self.editor_loader.editorLoaded.connect(self.forwardCmd) # Instantiate ConfigWriter self.config_writer = ConfigWriter() self.config_writer.configSaved.connect(self.forwardCmd) self.saveConfig.connect(self.config_writer.saveConfig) # Instantiate ConfigLoader self.config_loader = ConfigLoader() self.config_loader.configLoaded.connect(self.configLoaded) # Instantiate System Command Executor self.exec_sys_cmd = ExecSysCMD() self.sysCommand.connect(self.exec_sys_cmd.execCommand) def exitApp(self): print('# Stopping all processes....') self.kill_all.emit() time.sleep(3) # wait for 1 seconds to kill all processes self.app.quit() os.kill(self.app.applicationPid(), signal.SIGTERM) # kill all related threads def start(self, args): reset_screen() if self.args.Ex: reset_screen_dbg() self.stdinReader.start() # call run() method in separate thread self.config = self.config_loader.loadConfigSync() self.wsgi_server.start() self.operator.start(self.config) def loadTools(self): # Multithreaded logging.debug('MainWorker::loadTools() called') self.toolbox_loader.start() def loadEditorConfig(self, address, typeName): # Multithreaded logging.debug('MainWorker::loadEditorConfig() called') self.editor_loader.startLoad(address, typeName) def forwardCmd(self, cmd): #logging.debug('MainWorker::forwardCmd() called') self.frontendCtrl.emit(cmd) def loadConfig(self): # Multithreaded logging.debug('MainWorker::loadConfig() called') self.config_loader.start() def configLoaded(self, config): self.config = config address = { 'target' : 'MainWindow'} cmd = { 'cmd' : 'CurrentConfig', 'address' : address, 'data' : config } self.frontendCtrl.emit(cmd) def checkArgs(self, args): b_file_found = False grid_file = None for argument in args: if argument[0] == '-' or argument[0] == '--': print('Option found: {}'.format(argument)) else: if not b_file_found: b_file_found = True grid_file = argument return grid_file
class MainWorker(QObject): kill_all = Signal() log_level = logging.INFO formatter = logging.Formatter( fmt='%(asctime)s - %(levelname)s - %(message)s', datefmt='%H:%M:%S') max_grid_size = 50 max_grid_cnt = 5 config = None # element configuration update_logdate = Signal( object) # update displayed date string in stdin_reader startExec = Signal(object, object) # element-Id, configuration stopExec = Signal(object) # element-Id saveConfig = Signal(object) # configuration sysCommand = Signal(object) # Optional: Element Constructor / Destructor frontendCtrl = Signal(object) queryStates = Signal() # Query the running states of elements startAll = Signal(object) # Start all elements: (config) stopAll = Signal() # Stop all elements killAll = Signal() # Kill all running processes def __init__(self, app): super(MainWorker, self).__init__() self.app = app # Setup command line arguments parser = argparse.ArgumentParser( description='Pythonic background daemon') parser.add_argument('-Debug', action='store_true', help='Interactive shell intercace, Unix only') self.args = parser.parse_args() # Select multiprocessing spawn method mp.set_start_method('spawn') # Set working directory os.chdir(Path(__file__).parent.absolute()) # Setup format locale.setlocale(locale.LC_TIME, '') # Instantiate WSGI Server self.wsgi_server = WSGI_Server(self) # Instantiate Execution Operator self.operator = Operator() self.operator.command.connect(self.forwardCmd) self.startExec.connect(self.operator.startExec) self.stopExec.connect(self.operator.stopExec) self.queryStates.connect(self.operator.getElementStates) self.startAll.connect(self.operator.startAll) self.stopAll.connect(self.operator.stopAll) self.killAll.connect(self.operator.killAll) # Instantiate Standard Input Reader (Unix only) if self.args.Debug: try: from stdin_reader import stdinReader except ImportError: from Pythonic.stdin_reader import stdinReader self.stdinReader = stdinReader( self.operator.processHandles.items()) self.stdinReader.quit_app.connect(self.exitApp) # Instantiate ToolboxLoader self.toolbox_loader = ToolboxLoader() self.toolbox_loader.tooldataLoaded.connect(self.forwardCmd) # Instantiate (Element)-EditorLoader self.editor_loader = EditorLoader() self.editor_loader.editorLoaded.connect(self.forwardCmd) # Instantiate ConfigWriter self.config_writer = ConfigWriter() self.config_writer.configSaved.connect(self.forwardCmd) self.saveConfig.connect(self.config_writer.saveConfig) # Instantiate ConfigLoader self.config_loader = ConfigLoader() self.config_loader.tooldataLoaded.connect(self.forwardCmd) # Instantiate System Command Executor self.exec_sys_cmd = ExecSysCMD() self.sysCommand.connect(self.exec_sys_cmd.execCommand) # Connect the logger if self.args.Debug: self.update_logdate.connect(self.stdinReader.updateLogDate) self.logger = logging.getLogger() self.logger.setLevel(self.log_level) # Create home path (if not already existing) home_path = Path.home() / 'Pythonic' if not os.path.exists(home_path): os.makedirs(home_path) # Create log path (if not already existing) self.log_path = home_path / 'log' if not os.path.exists(self.log_path): os.makedirs(self.log_path) # Get current date self.log_date = datetime.datetime.now() # self.log_date is kept up to date in heartbeat (WebSocket rcv) # Create directory structure for logging log_date_str = self.log_date.strftime('%Y_%m_%d') file_path = '{}/{}.txt'.format(str(self.log_path), log_date_str) # Setup logger file_handler = logging.FileHandler(file_path) file_handler.setLevel(self.log_level) file_handler.setFormatter(self.formatter) self.logger.addHandler(file_handler) self.update_logdate.emit( log_date_str) # forward log_date_str to instance of stdinReader # Create directory for executables executables_path = home_path / 'executables' if not os.path.exists(executables_path): os.makedirs(executables_path) # Create trash folder for deleted files # TODO # Append executables folder to module search path sys.path.append(str(executables_path)) logging.debug('MainWorker::__init__() called') def exitApp(self): print('# Stopping all processes....') self.kill_all.emit() time.sleep(3) # wait for 1 seconds to kill all processes self.app.quit() os.kill(self.app.applicationPid(), signal.SIGTERM) # kill all related threads def update_logfile(self): now = datetime.datetime.now().date() if (now != self.log_date.date()): self.logger.removeHandler(self.logger.handlers[0]) log_date_str = now.strftime('%Y_%m_%d') file_path = '{}/{}.txt'.format(str(self.log_path), log_date_str) file_handler = logging.FileHandler(file_path) file_handler.setLevel(self.log_level) file_handler.setFormatter(self.formatter) self.logger.addHandler(file_handler) self.log_date = datetime.datetime.now() self.update_logdate.emit(log_date_str) def start(self, args): logging.info('<#>DAEMON STARTED<#>') reset_screen() if self.args.Debug: reset_screen_dbg() self.stdinReader.start() # call run() method in separate thread self.wsgi_server.start() self.operator.start() def loadTools(self): logging.debug('MainWorker::loadTools() called') self.toolbox_loader.start() def loadEditorConfig(self, address, typeName): logging.debug('MainWorker::loadEditorConfig() called') self.editor_loader.startLoad(address, typeName) def forwardCmd(self, cmd): #logging.debug('MainWorker::forwardCmd() called') self.frontendCtrl.emit(cmd) def loadConfig(self): logging.debug('MainWorker::loadConfig() called') self.config_loader.start() def checkArgs(self, args): b_file_found = False grid_file = None for argument in args: if argument[0] == '-' or argument[0] == '--': print('Option found: {}'.format(argument)) else: if not b_file_found: b_file_found = True grid_file = argument return grid_file