class Main(MDApp): bot: BotThread = None parser: Parser logger: Logger def build(self): self.theme_cls.primary_palette = 'Gray' return Builder.load_file('templates/screen/screens.kv') def on_start(self): app = MDApp.get_running_app() self.parser = Parser(app) self.logger = Logger().init_terminal_instance(app) self.logger.info('App started') def go_to_server(self, screen_manager: ScreenManager): screen_manager.transition.direction = 'right' screen_manager.current = 'server' def go_to_settings(self, screen_manager: ScreenManager): screen_manager.transition.direction = 'left' screen_manager.current = 'settings' def run_bot(self): token = self.parser.get_token() bot_status = self.parser.get_bot_status() try: if self.bot is not None: self.bot = None self.logger.info('Polling stopped') bot_status.circle_color = colors.RED_COLOR elif token: self.bot = BotThread(self.parser, self.logger) self.bot.start() self.logger.info('Polling started') bot_status.circle_color = colors.GREEN_COLOR else: self.logger.alert('Empty token') bot_status.circle_color = colors.RED_COLOR except Exception as e: self.bot = None self.logger.alert(e) bot_status.circle_color = colors.RED_COLOR
from controllers.parser import ( ParseError, TaskmasterDaemonParser, ) from controllers.task import Task from controllers.server import Server from controllers.manager import Manager from controllers.logger import Logger LOGLEVEL = getattr(logging, os.environ.get('LOGLEVEL', 'INFO'), logging.INFO) if __name__ == '__main__': logger = Logger(level=LOGLEVEL) try: try: logger.info('Parsing input configuration...', end='') parser = TaskmasterDaemonParser.from_command_line() except ParseError as e: print("") logger.error(e) sys.exit(-1) logger.success('') logger.debug('Configuration retrieved: %s' % parser.configuration) programs = list() if parser.configuration.get('programs', {}): for program_name, program_params in parser.configuration.get( 'programs', {}).items(): params = copy.deepcopy(program_params) cmd = params.pop('cmd')
r = requests.get(f"{url}/outcome?user_id={message['from']['id']}") @dp.message_handler(commands=["unread"]) async def botUnread(message): logger.userMessage(message) if isUserExist(message): r = requests.get(f"{url}/unread?user_id={message['from']['id']}") @dp.message_handler() async def botMessageReciever(message): logger.userMessage(message) if message["text"] in ['income', 'outcome', 'unread']: r = requests.get(f"{url}/{message['text']}?user_id=2") if len(r.json()['data']) != 0: await message.reply(' '.join(str(x) for x in r.json()['data'])) else: await message.reply('Сообщений нет') else: botAnswer = f'Привет, {message["from"]["first_name"]}!\nХочешь пообщаться?' await message.reply(botAnswer) logger.botMessage(botAnswer) if __name__ == '__main__': logger.info("Polling started") executor.start_polling(dp) logger.info("Polling over")
class Task: def __init__(self, *args, **kwargs): self.log = Logger(level=LOGLEVEL) self.processes = list() self.start_time = -1 self.stdout = '' self.stderr = '' self.trynum = 1 self.threads = list() self.stopping = False self.update(*args, **kwargs) self.log.info('task %s initialized.' % self.name) def update(self, name, cmd, numprocs=1, umask='666', workingdir=os.getcwd(), autostart=True, autorestart='unexpected', exitcodes=[0], startretries=2, starttime=5, stopsignal='TERM', stoptime=10, env={}, **kwargs): self.name = name self.cmd = cmd self.numprocs = numprocs self.umask = str(umask) if umask else '000' self.workingdir = workingdir self.autostart = autostart self.autorestart = autorestart self.exitcodes = exitcodes self.startretries = startretries self.starttime = starttime self.stopsignal = stopsignal self.stoptime = stoptime self.env = os.environ for key, value in env.items(): self.env[key] = str(value) self.stdout = kwargs.get('stdout', '') self.stderr = kwargs.get('stderr', '') if autostart: if self.is_running: self.restart() else: self.run() def close_fds(self): getattr(self.stdout, 'close', _nop)() getattr(self.stderr, 'close', _nop)() def reopen_stds(self): if getattr(self.stdout, 'closed', True): self.stdout = getattr(self.stdout, 'name', '') if getattr(self.stderr, 'closed', True): self.stderr = getattr(self.stderr, 'name', '') @property def stdout(self): return self._stdout @stdout.setter def stdout(self, path): if not path: self._stdout = subprocess.PIPE return self._stdout = open(path, 'w') @property def stderr(self): return self._stderr @stderr.setter def stderr(self, path): if not path: self._stderr = subprocess.PIPE return self._stderr = open(path, 'w') def _initchildproc(self): os.umask(int(self.umask, 8)) def restart(self, retry=False, from_thread=False): if from_thread and self.stopping: return self.stop(from_thread) self.run(retry=retry) def define_restart_policy(self, process, retry=False): thr = threading.Thread( target=handle_process_restart_behavior, args=( process, self.autorestart, self.exitcodes, lambda *_: self.restart(retry=retry, from_thread=True), ), daemon=True, ) thr.start() self.threads.append(thr) def run(self, retry=False): self.trynum = 1 if not retry else (self.trynum + 1) if self.trynum > self.startretries: self.log.warning('%s reached the maximum number of retries.' % self.name) return self.reopen_stds() self.log.info('Try to start {}. Retry attempt {}, max retries: {}, cmd: `{}`'.format( self.name, self.trynum, self.startretries, self.cmd, )) try: for virtual_pid in range(self.numprocs): process = subprocess.Popen( self.cmd.split(), stderr=self.stderr, stdout=self.stdout, env=self.env, cwd=self.workingdir, preexec_fn=self._initchildproc, ) self.processes.append(process) self.start_time = time.time() if process.returncode in self.exitcodes: self.define_restart_policy(process) self.log.success(( f'{self.name}: process number {virtual_pid} started.' f' Exited directly, with returncode {process.returncode}' )) self.start_time = -2 self.trynum = 1 continue else: try: process.wait(timeout=self.starttime) if process.returncode in self.exitcodes: self.define_restart_policy(process) self.log.success(( f'{self.name}: process number {virtual_pid} started.' f' Exited directly, with returncode {process.returncode}' )) self.start_time = -2 self.trynum = 1 continue except subprocess.TimeoutExpired: self.define_restart_policy(process) self.log.success(f'{self.name}: process number {virtual_pid} started.') self.trynum = 1 continue # retry self.log.info(f'Unexpected returncode {process.returncode}') self.restart(retry=True) except Exception: # retry self.log.warning('%s startup failed.' % self.name) self.restart(retry=True) def stop(self, from_thread=False): self.stopping = True self.close_fds() for process in self.processes: self.log.info(f'Send SIG{self.stopsignal} to {process.pid}.') process.send_signal(getattr(signal, 'SIG' + self.stopsignal)) try: process.wait(self.stoptime) except subprocess.TimeoutExpired: self.log.info(f'Force kill {process.pid}.') process.kill() if not from_thread: for thr in self.threads: thr.join(.1) self.processes = list() self.threads = list() self.start_time = -3 self.stopping = False @property def is_running(self): return self.start_time > 0 @property def uptime(self): for p in self.processes: if p.returncode is not None: if p.returncode in self.exitcodes: self.start_time = -2 else: self.start_time = -3 break if self.start_time == -1: return 'not started' if self.start_time == -2: return 'finished' if self.start_time == -3: return 'stopped' upt = int(time.time() - self.start_time) return '{}:{}:{}'.format(int(upt / 3600), int(upt / 60 % 60), int(upt % 60)) def send_command(self, command): self.log.info(f'task {self.name}, command received {command}.') if command.upper() == 'START': self.run() elif command.upper() == 'RESTART': self.stop() self.run() elif command.upper() == 'STOP': self.stop() else: return {'error': True, 'message': 'Unknown command %s' % command, 'task': self.name} return {'task': self.name, 'message': command.lower() + 'ed'}
class Manager: programs = list() def __init__(self, programs, parser): self.programs = programs self.parser = parser self.log = Logger(level=LOGLEVEL) def stop_all(self): for program in self.programs: program.stop() for thr in program.threads: thr.join(.1) def _get_program_by_name(self, name): for program in self.programs: if program.name == name: return program def _remove_program_by_name(self, name): for program in self.programs: if program.name == name: self.programs.remove(program) def update(self): self.log.info('Received update command.') diff = self.parser.refresh() self.log.info('Affected/new tasks: %s.' % diff) parser = self.parser programs_names = [program.name for program in self.programs] affected = list() if parser.configuration.get('programs', {}): for program_name, _program_params in parser.configuration.get('programs', {}).items(): program_params = copy.deepcopy(_program_params) if program_name in programs_names and program_name not in diff: # not affected continue elif program_name in programs_names: # affected -- w/restart affected.append(program_name) program = self._get_program_by_name(program_name) cmd = program_params.pop('cmd') program.update(program_name, cmd, **program_params) continue # start affected/new programs cmd = program_params.pop('cmd') task = Task(program_name, cmd, **program_params) self.programs.append(task) if program_name in programs_names: programs_names.remove(program_name) for program_name in programs_names: if program_name not in diff or program_name in affected: continue program = self._get_program_by_name(program_name) program.stop() self._remove_program_by_name(program_name) return {"raw_output": "Updated tasks %s" % diff, "updated_tasks": diff} def load_tcp_command(self, request): command = request.get('command', '') args = request.get('args', list()) with_refresh = request.get('with_refresh', False) response = [] if command.upper() == 'UPDATE': ret = self.update() if not with_refresh: return ret for program in self.programs: if program.name in args: args.remove(program.name) ret = program.send_command(command) if 'error' in ret: response.append(dict(raw_output='{}: ERROR ({})'.format( ret['task'], ret['message'], ), **ret)) else: response.append(dict(raw_output='{}: {}'.format( ret['task'], ret['message'], ), **ret)) if response and not with_refresh: return response if len(response) > 1 else response[0] if command.upper() == 'REFRESH' or with_refresh: if args: return [{ "task": program.name, "uptime": program.uptime, "started_processes": len(program.processes), "pids": [p.pid for p in program.processes], } for program in self.programs if program.name in args] return [{ "task": program.name, "uptime": program.uptime, "started_processes": len(program.processes), "pids": [p.pid for p in program.processes], } for program in self.programs] if command.upper() == 'STOP_DAEMON': self.stop_all() raise Exception return { 'raw_output': '%s: ERROR (no such command)' % command, 'error': True, 'input_request': request, 'message': 'no such process', }