Example #1
0
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
Example #2
0
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')
Example #3
0
        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")
Example #4
0
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'}
Example #5
0
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',
        }