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}
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
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
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")
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
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")
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)
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()