Exemple #1
0
    def execute(self, func, *args):
        '''Execute the function passed as a parameter. MySQLdb exception handling and automatic reconnection are performed if required
            Args:
                func(function): The function that performs some actions with the database
            Returns:
                dict:           Dictionary with the operation status ('status') and the result of the function execution ('result')
        '''
        try:
            return {'status': True, 'result': func(*args)}
        except MySQLdb.OperationalError as e: # Connection lost
            errnum, _errmsg = e.args
            # 2006 stands for MySQL has gone away
            # 2013 stands for lost connection to MySQL
            if errnum in (2006, 2013):
                log_main.warning("The database connection is lost.")
                self.reconnect()
                return self.execute(func, *args)

            log_main.exception("Error when executing MySQL")
            return {'status': False, 'result': None}

        except UnboundLocalError as e:
            log_main.exception("Error when executing a block of code for database.")
            log_main.error("Most likely, the exception occurred due to the fact that somewhere in the code block a variable with the same name is used as a global one and the interpreter perceives it as local in this entire block (%s)", e)
            return {'status': False, 'result': None}
        except Exception as e: # pylint: disable=broad-except
            log_main.exception("Error when executing a block of code for database.")
            return {'status': False, 'result': None}
Exemple #2
0
    def setStatus(self, stream, status):
        '''Set the status of a given stream
            Args:
                key(str):       Stream key (secret)
                status(int):    New status
            Returns:
                bool:           Operation result
        '''
        status = int(status)
        if stream.status == status:
            return True # The status has not changed

        if stream.secret not in self.__streams:
            log_main.error("Attempt to change the status of a stream that is not in the cache. Key: %s", stream.secret)
            return False # Uncached stream

        def updateStreamStatusSQL():
            with Database().getConnection().cursor() as cursor:
                sql = "UPDATE "+STREAMS_TABLE+" SET status=%s WHERE secret=%s"
                cursor.execute(sql, (status, stream.secret))
                Database().getConnection().commit()

        res = Database().execute(updateStreamStatusSQL)
        if res['status'] is False:
            log_main.error("Error when changing the stream status")
            return False

        # Update the cache
        self.__streams[stream.secret].status = status
        return True
Exemple #3
0
    def delete(self, secret):
        '''Delete stream with specified key
            Args:
                secret(str):    Stream key (secret)
            Returns:
                bool:           Operation result
        '''
        # Удаляем поток даже если в кэше не было
        def deleteStreamSQL():
            with Database().getConnection().cursor() as cursor:
                sql = "DELETE FROM "+STREAMS_TABLE+" WHERE secret=%s"
                cursor.execute(sql, (secret,))
                Database().getConnection().commit()
                return cursor.rowcount > 0

        res = Database().execute(deleteStreamSQL)
        if res['status'] is False:
            log_main.error("Error deleting a stream")
            return None

        # Log operation
        user_id = None
        stream_name = "?"
        if secret in self.__streams:
            user_id = self.__streams[secret].user_id
            stream_name = self.__streams[secret].name
        log_main.info('Deleted stream "%s" for user %s with key: %s', stream_name, user_id, secret)

        # Remove from the cache
        del self.__streams[secret]
        return True
Exemple #4
0
    def __init__(self, host=None, user=None, password=None, database=None):
        if host is None or user is None or password is None or database is None:
            log_main.error("Error when initiating the database connection — not all connection parameters were specified")
            raise BotUnexpected

        self.__host = host
        self.__user = user
        self.__password = password
        self.__database = database
        self.__threadLocal = threading.local() # Thread-unique variable, initiated only once
        if self.connect():
            log_main.info("The connection to the database is established")
Exemple #5
0
 def __setWebhook(self):
     '''Set webhook for telebot'''
     try:
         # Remove old webhook
         self._bot.remove_webhook()
         # Set new webhook
         if self._bot.set_webhook(url=self.__webhook_url):
             log_main.debug("Webhook for telegram bot is set: %s",
                            self.__webhook_url)
             return True
         log_main.error("Error when installing webhook for telegram bot")
         return False
     except telebot.apihelper.ApiException as e:
         log_main.warning(
             "Exception when installing webhook for telegram bot: %s", e)
         return False
Exemple #6
0
    def add(self, user_id, name):
        '''Create new stream for given telegram user
            Args:
                user_id(str):   Telegram user ID (chat ID)
                name(str):      The name of the stream
            Returns:
                str:            Stream key (secret)
        '''
        # Generate a unique stream key
        alphabet = "0123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"
        converter = baseconv.BaseConverter(alphabet)
        codeLength = 32
        secret = converter.encode(uuid.uuid4().int)[0:codeLength]

        # Check the uniqueness
        if secret in self.__streams:
            log_main.error("Uniqueness error when adding a stream: %s", secret)
            return None

        # Add stream
        stream_status = int(StreamStatus.active)
        def addStreamSQL():
            '''Get all existing streams from database'''
            with Database().getConnection().cursor() as cursor:
                sql = "INSERT INTO " + STREAMS_TABLE + " (user_id, secret, name, status) VALUES (%s, %s, %s, %s)"
                cursor.execute(sql, (user_id, secret, name, stream_status))
                Database().getConnection().commit()
                return Database().getConnection().insert_id()

        res = Database().execute(addStreamSQL)
        if res['status'] is False:
            log_main.error("Error when adding a new stream")
            return None

        # Add to cache
        stream_id = res['result']
        if stream_id is not None:
            stream = Stream(stream_id, user_id, secret, name, stream_status)
            self.__streams[secret] = stream
            log_main.info('Added new stream "%s" for user %s with the key: %s', name, user_id, secret)
            return secret

        # If it was not added
        raise Exception("Couldn't add new stream")
Exemple #7
0
    def __init__(self):
        super().__init__()
        self.__streams = {}

        def loadStreamsSQL():
            '''Get all existing streams from database'''
            with Database().getConnection().cursor() as cursor:
                sql = "SELECT * FROM " + STREAMS_TABLE
                cursor.execute(sql)
                return cursor.fetchall()

        res = Database().execute(loadStreamsSQL)
        if res['status'] is False:
            log_main.error("Failed to load streams")
            raise BotUnexpected

        for rec in res['result']:
            id_, user_id, secret, name, status = rec
            self.__streams[secret] = Stream(id_, user_id, secret, name, status)
Exemple #8
0
    def __init__(self, base_url, is_local=None):
        self.__base_url = base_url
        self.__webhook_path = Config().webhook_path
        self.__webhook_url = "%s%s" % (base_url, self.__webhook_path)
        self.__is_local = is_local
        self.__bot_token = Config().bot_token

        log_main.info("Starting BackendServer…")
        # Some debug info (for local dev mode )
        if is_local:
            print("Base URL: %s" % self.__base_url)
            print("Webhook URL: %s" % self.__webhook_url)
            print("Bot token: %s" % self.__bot_token)

        # Initializing Flask
        self.init_flask()

        # Checking and initializing the database connection
        status, description = Database.checkConnection(Config().db_host,
                                                       Config().db_user,
                                                       Config().db_password,
                                                       Config().db_database)
        if not status:
            msg = "Database connect failed\n%s" % description
            self._flask_app.logger.error(msg)  # pylint: disable=no-member
            log_main.error(msg)
            sys.exit()
        Database(Config().db_host,
                 Config().db_user,
                 Config().db_password,
                 Config().db_database)

        # Init streams
        log_main.info("Loading streams…")
        Streams()
        log_main.info("Streams loaded")

        # Init telebot
        self.init_telebot()