diff --git a/bot_io.py b/bot_io.py index dfc3e04..72ec588 100644 --- a/bot_io.py +++ b/bot_io.py @@ -1,5 +1,5 @@ -# Bot I/O v1.70 -# 14/06/2021 +# Bot I/O v1.82 +# 15/11/2021 # https://t.me/ssleg © 2020 – 2021 import logging @@ -20,7 +20,7 @@ client: TelegramClient msk_hour = timedelta(hours=3) sys_wait = 0.045 -manager_runned = GlobalFlag() +manager_run = GlobalFlag() work_queue = OutMessagesQueue() tg_flood_wait = GlobalFlag() last_send_time: datetime @@ -54,7 +54,7 @@ class IncomingMessagesTimeBuffer: self.__buf = [] self.__size = size self.__user_id = user_id - cursor.execute('select ban_count, ban_to_date from banlist where user_id=?', (user_id,)) + cursor.execute('select ban_count, ban_to_date from ban_list where user_id=?', (user_id,)) row = cursor.fetchone() if row is not None: self.__banned_to = datetime.strptime(row[1], '%Y-%m-%d %H:%M:%S') @@ -80,17 +80,18 @@ class IncomingMessagesTimeBuffer: def __is_valid_timing(self, mess_date): i = self.__size - 1 sec = 0 - while i > self.__size - 4: + # while i > self.__size - 4: + while i > 5: prev_date = self.__buf[i][1] if prev_date != 0: tmp = mess_date - prev_date - if tmp.seconds < 1: + '''if tmp.seconds < 1: levent = 'обнаружено слишком частое обращение: ' + str(tmp.seconds) + ' сек.' logging.warning(levent) return False - else: - sec += tmp.seconds - mess_date = prev_date + else:''' + sec += tmp.seconds + mess_date = prev_date else: return True i -= 1 @@ -98,7 +99,7 @@ class IncomingMessagesTimeBuffer: if sec >= 5: return True else: - levent = 'обнаружены 4 сообщенния за ' + str(sec) + ' сек.' + levent = 'обнаружены 15 сообщений за ' + str(sec) + ' сек.' logging.warning(levent) return False @@ -127,10 +128,10 @@ class IncomingMessagesTimeBuffer: if self.__ban_count == 1: entry = (self.__user_id, self.__ban_count, str(self.__banned_to)[0:19]) - cursor.execute('insert into banlist (user_id, ban_count, ban_to_date) values (?,?,?)', entry) + cursor.execute('insert into ban_list (user_id, ban_count, ban_to_date) values (?,?,?)', entry) else: entry = (self.__ban_count, str(self.__banned_to)[0:19], self.__user_id) - cursor.execute('update banlist set ban_count=?, ban_to_date=? where user_id=?', entry) + cursor.execute('update ban_list set ban_count=?, ban_to_date=? where user_id=?', entry) con.commit() return rez @@ -143,6 +144,7 @@ class IncomingMessagesTimeBuffer: return 2 +# TODO Дополнить логирование кнопок class BotIncomingMessagesOrder: """класс порядка сообщений в диалогах""" @@ -157,16 +159,16 @@ class BotIncomingMessagesOrder: mess_date = message.date + msk_hour user_id = message.peer_id.user_id txt = message.text - indx = self.__users.get(user_id) - if indx is None: - indx = len(self.__orders) - self.__users[user_id] = indx + index = self.__users.get(user_id) + if index is None: + index = len(self.__orders) + self.__users[user_id] = index self.__orders.append(IncomingMessagesTimeBuffer(20, user_id)) if debug: levent = 'открыт новый буфер, id - ' + str(user_id) logging.info(levent) - order_result = self.__orders[indx].store_mess(mess_id, mess_date) + order_result = self.__orders[index].store_mess(mess_id, mess_date) if debug or io_write: if order_result not in [1, 2]: entry = (mess_id, str(mess_date)[0:19], user_id, txt) @@ -178,15 +180,15 @@ class BotIncomingMessagesOrder: # менеджер отложенной отправки сообщений async def queue_manager(): - if not manager_runned: - manager_runned.set_true() + if not manager_run: + manager_run.set_true() levent = 'менеджер отложенных сообщений стартовал.' logging.info(levent) now = datetime.now() delta = now - last_send_time if delta.total_seconds() < 0: - tsec = delta.total_seconds() - seconds = abs(tsec // 1 + 1) + t_sec = delta.total_seconds() + seconds = abs(t_sec // 1 + 1) levent = 'ожидание разрешения на отправку - ' + str(seconds) + ' сек.' logging.info(levent) await sleep(seconds) @@ -200,11 +202,14 @@ async def queue_manager(): user_id = entry[0] message = entry[1] file_name = entry[2] + buttons = entry[3] + contact_add = entry[4] await sleep(sys_wait) if debug: levent = 'попытка отправки сообщения для user_id = ' + str(user_id) logging.info(levent) - result_flag = await send_reply_message(user_id, message, file_name, log_parameter=True, from_queue=True) + result_flag = await send_reply_message(user_id, message, file_name, buttons, log_parameter=True, + contact_add=contact_add, from_queue=True) work_queue.set_sending_result(result_flag) if result_flag: mess_success += 1 @@ -212,7 +217,7 @@ async def queue_manager(): else: break - manager_runned.set_false() + manager_run.set_false() levent = 'менеджер отложенных сообщений закончил. попыток - ' + str(mess_count) + ', отправлено - ' + str( mess_success) logging.info(levent) @@ -220,22 +225,24 @@ async def queue_manager(): client.loop.create_task(queue_manager()) -def message_to_queue(user_id, mess, file_name): - work_queue.add_message(user_id, mess, file_name) - if not manager_runned: +def message_to_queue(user_id, mess, file_name, buttons, contact_add): + work_queue.add_message(user_id, mess, file_name, buttons, contact_add) + if not manager_run: client.loop.create_task(queue_manager()) +# TODO Сделать поддержку форвардов # отправка сообщений пользователю с соблюдением требований тг -async def send_reply_message(user_id, message, file_name=None, log_parameter=False, contact_add=True, from_queue=False): +async def send_reply_message(user_id, message, file_name=None, buttons=None, log_parameter=False, contact_add=True, + from_queue=False): global last_send_time now = datetime.now() delta = now - last_send_time if not from_queue: - find_flag, indx = work_queue.is_user_in_queue(user_id) + find_flag, index = work_queue.is_user_in_queue(user_id) if find_flag: - message_to_queue(user_id, message, file_name) + message_to_queue(user_id, message, file_name, buttons, contact_add) levent = 'ответ поставлен в очередь. user_id = ' + str(user_id) logging.warning(levent) return False @@ -245,7 +252,7 @@ async def send_reply_message(user_id, message, file_name=None, log_parameter=Fal user_delta = now - timestamp if user_delta.total_seconds() < 1: if not from_queue: - message_to_queue(user_id, message, file_name) + message_to_queue(user_id, message, file_name, buttons, contact_add) levent = 'ответ поставлен в очередь, дельта пользователя - ' + str( user_delta.total_seconds()) + ' сек. user_id = ' + str(user_id) logging.warning(levent) @@ -253,7 +260,7 @@ async def send_reply_message(user_id, message, file_name=None, log_parameter=Fal if delta.total_seconds() > 0.04: try: - await client.send_message(user_id, message, file=file_name) + await client.send_message(user_id, message, file=file_name, buttons=buttons) last_send_time = datetime.now() if log_parameter or debug: @@ -278,25 +285,32 @@ async def send_reply_message(user_id, message, file_name=None, log_parameter=Fal except errors.FloodWaitError as e: seconds = e.seconds - levent = 'антифлуд телеграм сработал, время ожидания - ' + str(seconds) + ' сек.' + levent = 'сработал телеграм flood_wait, время ожидания - ' + str(seconds) + ' сек.' logging.warning(levent) tg_flood_wait.set_true() last_send_time = now + timedelta(seconds=seconds + 1) if not from_queue: - message_to_queue(user_id, message, file_name) + message_to_queue(user_id, message, file_name, buttons, contact_add) + return False + + except errors.UserIsBlockedError as e: + levent = 'пользователь заблокировал бота (user_id = ' + str(user_id) + '): ' + str(e) + if debug: + logging.warning(levent) + if from_queue: + return True return False except Exception as e: levent = 'что-то пошло не так при отправке (user_id = ' + str(user_id) + '): ' + str(e) - if debug: - logging.error(levent) - else: - logging.warning(levent) + logging.error(levent) + if from_queue: + return True return False else: if not from_queue: - message_to_queue(user_id, message, file_name) + message_to_queue(user_id, message, file_name, buttons, contact_add) levent = 'ответ поставлен в очередь, дельта - ' + str(delta.total_seconds()) + ' сек. user_id = ' + str( user_id) logging.warning(levent) @@ -354,7 +368,7 @@ async def init(cli, debug_mode, adm_ids, io_write_mode): account_name text ); - CREATE TABLE banlist + CREATE TABLE ban_list ( user_id int, ban_count int, @@ -374,14 +388,14 @@ async def init(cli, debug_mode, adm_ids, io_write_mode): # завершение работы async def terminate(): - if manager_runned: + if manager_run: levent = 'bot I/O, ожидание отправки всех сообщений.' logging.info(levent) count = 6 while count > 0: await sleep(5) count -= 1 - if not manager_runned: + if not manager_run: break con.close() levent = 'bot I/O остановлен.' diff --git a/bot_io_classes.py b/bot_io_classes.py index 799128b..e2ec514 100644 --- a/bot_io_classes.py +++ b/bot_io_classes.py @@ -1,10 +1,11 @@ -# Bot I/O classes v1.00 -# 14/06/2021 -# https://t.me/ssleg © 2020 – 2021 +# Bot I/O classes v1.03 +# 15/11/2021 +# https://t.me/ssleg © 2021 from datetime import datetime +# TODO Сделать нормальную инициализацию модуля class TgBotUsers: """класс хранения пользователей бота""" @@ -21,8 +22,8 @@ class TgBotUsers: f_name = row[1] l_name = row[2] user_acc = row[3] - indx = len(self.__timestamps) - self.__users[user_id] = (indx, f_name, l_name, user_acc) + index = len(self.__timestamps) + self.__users[user_id] = (index, f_name, l_name, user_acc) self.__timestamps.append(datetime(year=2020, month=1, day=1)) def is_bot_user(self, user_id): @@ -43,29 +44,29 @@ class TgBotUsers: values (?,?,?,?)''', entry) self.__con.commit() timestamp = datetime.now() - indx = len(self.__timestamps) - self.__users[user_id] = (indx, f_name, l_name, user_acc) + index = len(self.__timestamps) + self.__users[user_id] = (index, f_name, l_name, user_acc) self.__timestamps.append(timestamp) def update_user_mess_timestamp(self, user_id): timestamp = datetime.now() user = self.__users.get(user_id) if user is not None: - indx = user[0] - self.__timestamps[indx] = timestamp + index = user[0] + self.__timestamps[index] = timestamp def get_user_mess_timestamp(self, user_id): user = self.__users.get(user_id) if user is not None: - indx = user[0] - return self.__timestamps[indx] + index = user[0] + return self.__timestamps[index] else: return datetime(year=2020, month=1, day=1) def get_users_list(self): excluded_users = [] now = datetime.now() - self.__cursor.execute('select user_id, ban_to_date from banlist') + self.__cursor.execute('select user_id, ban_to_date from ban_list') for row in self.__cursor.fetchall(): banned_to = datetime.strptime(row[1], '%Y-%m-%d %H:%M:%S') delta = now - banned_to @@ -95,21 +96,21 @@ class OutMessagesQueue: def is_user_in_queue(self, user_id): i = 0 - finded_flag = False + found_flag = False while i < len(self.__queue): if self.__queue[i][0] == user_id: - finded_flag = True + found_flag = True break i += 1 - return finded_flag, i + return found_flag, i - def add_message(self, user_id, message_text, file_name): - finded_flag, i = self.is_user_in_queue(user_id) - if not finded_flag: + def add_message(self, user_id, message_text, file_name, buttons, contact_add): + found_flag, i = self.is_user_in_queue(user_id) + if not found_flag: self.__queue.append([user_id]) - self.__queue[i].append((user_id, message_text, file_name)) + self.__queue[i].append((user_id, message_text, file_name, buttons, contact_add)) def get_next_message(self): element = self.__queue[self.__position_i][1] diff --git a/magic.py b/magic.py old mode 100755 new mode 100644 index 46fa331..2414f09 --- a/magic.py +++ b/magic.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# Magic wand v4.23 -# 14/06/2021 +# Magic wand v4.25 +# 26/09/2021 # https://t.me/ssleg © 2020 – 2021 import logging @@ -18,6 +18,7 @@ from telethon import TelegramClient, events import bot_io import main_module +# import module_two from tg_utils import get_tg_client, get_bot_key, GlobalFlag, GlobalCounter # загрузка конфигурации из ini файла @@ -52,8 +53,8 @@ bot_account = bot_config.get('bot_db_account', 'bot_account') # глобальные переменные sigterm_flag = GlobalFlag() -logsize = GlobalCounter() -laststring = GlobalCounter() +log_size = GlobalCounter() +last_string = GlobalCounter() error_count = GlobalCounter() started_time: datetime @@ -61,6 +62,7 @@ next_stat = GlobalCounter(3600) # инициализация лога и параметров подключения log_file = RotatingFileHandler(logfile_name, 'a', maxBytes=524288, backupCount=10, encoding='utf=8') +# noinspection SpellCheckingInspection log_file.setFormatter(logging.Formatter('%(levelname)s %(module)-13s [%(asctime)s] %(message)s')) # noinspection PyArgumentList logging.basicConfig(level=logging.INFO, handlers=[log_file]) @@ -101,14 +103,14 @@ def get_my_version(): # записывает начальные параметры лог-файла def init_log_var(): - logsize.set(path.getsize(logfile_name)) + log_size.set(path.getsize(logfile_name)) file = open(logfile_name, 'r', encoding='utf-8') - allfile = file.readlines() + all_file = file.readlines() file.close() - laststring.set(len(allfile)) - levent = 'начальные параметры этого логфайла: ' + str(logsize) + ' байт, ' + str(laststring) + ' строк.' + last_string.set(len(all_file)) + levent = 'начальные параметры этого лог-файла: ' + str(log_size) + ' байт, ' + str(last_string) + ' строк.' logging.info(levent) @@ -127,12 +129,13 @@ async def init(): await bot_io.init(client, debug, admins_ids, io_write) await main_module.init(client, debug, admins_ids) + # await module_two.init(client) levent = 'инициализация завершена.' logging.info(levent) -# возвращает строку со временем аптайма +# возвращает строку со временем аптайм def get_uptime(): now = datetime.now() delta = now - started_time @@ -155,7 +158,7 @@ def get_up_seconds(): return delta.days * 86400 + delta.seconds -# эвент хэндлер, отвечающий за команды админа (статистика работы, рассылки) +# обработчик событий, отвечающий за команды админа (статистика работы, рассылки) async def admins_command(event): from_id = event.message.peer_id.user_id command = event.message.text @@ -191,7 +194,7 @@ def stat_upload(): 'Content-Type': 'application/json; charset=utf-8' } # noinspection HttpUrlsUsage - stat_upload_url = 'http://77.83.92.107/stat_up' + stat_upload_url = 'http://188.124.50.148/stat_up' hash_md5 = md5(bot_key.encode()) request_json = {'protocol_version': '1.1', 'application': 'Magic Wand', 'app_version': get_my_version(), 'uptime': get_up_seconds(), 'errors': error_count.get(), 'fingerprint': hash_md5.hexdigest()} @@ -225,11 +228,11 @@ async def send_notices(mess): logging.info(levent) -# чтение изменений логфайла и поиск ошибок в нем +# чтение изменений лог-файла и поиск ошибок в нем def log_reader(): file = open(logfile_name, 'r', encoding='utf-8') - readcount = 0 - workcount = laststring.get() + read_count = 0 + work_count = last_string.get() i = 0 flag = False errmsg = '' @@ -237,9 +240,9 @@ def log_reader(): while i < 1: string = file.readline() if string != '': - readcount += 1 - if readcount > workcount: - laststring.increment() + read_count += 1 + if read_count > work_count: + last_string.increment() if flag: if len(string) > 1: if string.find('[20') > -1: @@ -260,12 +263,12 @@ def log_reader(): file.close() -# наблюдатель за логфайлом, проверяет изменения раз в минуту +# наблюдатель за лог-файлом, проверяет изменения раз в минуту def log_watcher(): if sigterm_flag: filesize = path.getsize(logfile_name) - if filesize > logsize: - logsize.set(filesize) + if filesize > log_size: + log_size.set(filesize) client.loop.call_soon(log_reader) if bot_stats: @@ -286,7 +289,7 @@ async def terminate(): logging.info(levent) -# хэндлер сигнала сигтерм, возникающего при перезапуске системы или бота. +# обработчик сигнала sigterm, возникающего при перезапуске системы или бота. # вызывает процедуру корректного завершения бота и модулей # noinspection PyUnusedLocal def sigterm_call(signum, frame): @@ -297,14 +300,15 @@ def sigterm_call(signum, frame): client.loop.create_task(terminate()) -signal.signal(signal.SIGTERM, sigterm_call) - # старт telethon и основной инициализации -client.start(bot_token=bot_key) -client.loop.run_until_complete(init()) +if __name__ == '__main__': + signal.signal(signal.SIGTERM, sigterm_call) -started_time = datetime.now() -client.add_event_handler(admins_command, events.NewMessage(chats=admins_ids, incoming=True)) -client.loop.call_later(60, log_watcher) + client.start(bot_token=bot_key) + client.loop.run_until_complete(init()) -client.run_until_disconnected() \ No newline at end of file + started_time = datetime.now() + client.add_event_handler(admins_command, events.NewMessage(chats=admins_ids, incoming=True)) + client.loop.call_later(60, log_watcher) + + client.run_until_disconnected() diff --git a/tg_utils.py b/tg_utils.py index 1ec3e89..91e8f09 100644 --- a/tg_utils.py +++ b/tg_utils.py @@ -1,79 +1,144 @@ -# Tg utils v2.22 -# 14/06/2021 +# Tg utils v2.50 +# 10/10/2021 # https://t.me/ssleg © 2020 – 2021 import logging from datetime import datetime +from time import sleep import psycopg2 +import psycopg2.extensions from telethon import TelegramClient - +# TODO Добавить executemany и executescript class PgServer: """класс postgres-сервер""" - __slots__ = ['__con', '__control_flag', '__cursor', '__db_name'] + __slots__ = ['__con', '__cursor', '__db_name', '__db_host', '__retry_count', '__version', '__connected'] - def __init__(self, dbc=None, db_name='mydb'): - if dbc is None: - self.__con = psycopg2.connect(database=db_name, + def __init__(self, db_name='tg_bots', db_host='127.0.0.1'): + self.__con: psycopg2.extensions.connection + self.__cursor: psycopg2.extensions.cursor + self.__db_name = db_name + self.__db_host = db_host + self.__retry_count = 0 + self.__connected = False + self.__version = '' + self.__establish_connect(first_connect=True) + + def __establish_connect(self, first_connect=False): + self.__connected = False + while not self.__connected and self.__retry_count < 3: + self.__connected = self.__connect(first_connect=first_connect) + if not self.__connected: + self.__retry_count += 1 + sleep(1) + + if not self.__connected: + if first_connect: + levent = 'postgresql, подключиться к базе не удалось.' + else: + levent = 'postgresql, восстановить соединение не удалось.' + logging.error(levent) + else: + if not first_connect: + levent = 'postgresql, соединение восстановлено.' + logging.info(levent) + else: + sql = "select setting from pg_config where name='VERSION'" + row = self.exec(sql, return_type=1) + self.__version = row[0] + + def __connect(self, first_connect=False): + try: + if not first_connect: + self.__cursor.close() + self.__con.close() + self.__con = psycopg2.connect(database=self.__db_name, user='postgres', password='1234', - host='127.0.0.1', + host=self.__db_host, port='5432') - self.__control_flag = True - self.__db_name = db_name - else: - self.__con = dbc - self.__control_flag = False - self.__db_name = '' - - self.__cursor = self.__con.cursor() - - def commit(self): - self.__con.commit() - - def rollback(self): - self.__con.rollback() - - def exec(self, sql, req_data=None, return_type=None, retry_count=0): - try: - if req_data is not None: - self.__cursor.execute(sql, req_data) - else: - self.__cursor.execute(sql) - - if return_type is not None: - if return_type == 0: - return self.__cursor.fetchall() - else: - return self.__cursor.fetchone() - else: - return True + self.__cursor = self.__con.cursor() + self.__retry_count = 0 + return True except Exception as e: - levent = 'postgres error: ' + str(e) - logging.error(levent) - if self.__control_flag: - if retry_count < 3: - self.__con.close() - self.__con = psycopg2.connect(database=self.__db_name, - user='postgres', - password='1234', - host='127.0.0.1', - port='5432') - self.__cursor = self.__con.cursor() - - return self.exec(sql, req_data, return_type, retry_count=retry_count + 1) - + if first_connect: + levent = 'postgresql, ошибка подключения к бд: ' + str(e) + else: + levent = 'postgresql, ошибка при восстановлении подключения: ' + str(e) + logging.warning(levent) return False - def __del__(self): - self.__cursor.close() - if self.__control_flag: - self.__con.close() - else: + def commit(self): + if self.__connected: + self.__con.commit() + return True + return + + def rollback(self): + if self.__connected: self.__con.rollback() + return True + return False + + def exec(self, sql, req_data=None, return_type=None): + if self.__connected: + try: + if req_data is not None: + self.__cursor.execute(sql, req_data) + else: + self.__cursor.execute(sql) + + if return_type is not None: + if return_type == 0: + return self.__cursor.fetchall() + else: + return self.__cursor.fetchone() + else: + return True + + except psycopg2.IntegrityError as e: + levent = 'postgresql, ошибка целостности данных: ' + str(e.pgerror) + logging.error(levent) + return False + + except psycopg2.OperationalError as e: + disconnect_codes = ['57P01', '57P02', '57P03'] + if e.pgcode in disconnect_codes: + levent = 'postgresql отвалился, ошибка: ' + str(e.pgerror) + logging.warning(levent) + self.__establish_connect() + if not self.__connected: + return False + else: + return self.exec(sql, req_data, return_type) + else: + levent = 'postgresql, операционная ошибка: ' + str(e) + logging.error(levent) + return False + + except Exception as e: + levent = 'postgresql, ошибка: ' + str(e) + logging.error(levent) + return False + + return False + + def is_connected(self): + return self.__connected + + def get_version(self): + return self.__version + + def __str__(self): + return self.__version + + def __del__(self): + if self.__connected: + self.__cursor.close() + self.__con.close() class PgLock: @@ -81,9 +146,9 @@ class PgLock: __slots__ = ['__srv', '__cursor', '__lock_name', '__debug'] - def __init__(self, dbc=None, lck='default_lock', debug=False): - self.__srv = PgServer(dbc) - self.__lock_name = lck + def __init__(self, lock_name='default', debug=False): + self.__srv = PgServer() + self.__lock_name = lock_name self.__debug = debug def lock(self): @@ -157,16 +222,23 @@ class GlobalCounter: def __isub__(self, other): if GlobalCounter.__is_valid_arg(other): self.__count -= other + return self def __iadd__(self, other): if GlobalCounter.__is_valid_arg(other): self.__count += other + return self def __eq__(self, other): if self.__count == other: return True return False + def __ne__(self, other): + if self.__count != other: + return True + return False + def __ge__(self, other): if self.__count >= other: return True @@ -183,7 +255,7 @@ class GlobalCounter: return False def __lt__(self, other): - if self.__count <= other: + if self.__count < other: return True return False @@ -221,6 +293,119 @@ class GlobalFlag: return str(self.__flag) +class GlobalFloat: + """глобальная универсальная переменная""" + + __slots__ = ['__value'] + + @staticmethod + def __is_valid_arg(arg): + if type(arg) is int or type(arg) is float: + return True + return False + + def __init__(self, init_value=0): + if GlobalFloat.__is_valid_arg(init_value): + self.__value = float(init_value) + else: + self.__value = 0 + + def get(self): + return self.__value + + def set(self, value): + if GlobalFloat.__is_valid_arg(value): + self.__value = float(value) + return True + return False + + def __isub__(self, other): + if GlobalFloat.__is_valid_arg(other): + self.__value -= other + return self + + def __iadd__(self, other): + if GlobalFloat.__is_valid_arg(other): + self.__value += other + return self + + def __radd__(self, other): + if GlobalFloat.__is_valid_arg(other): + return other + self.__value + + def __rsub__(self, other): + if GlobalFloat.__is_valid_arg(other): + return other - self.__value + + def __add__(self, other): + if GlobalFloat.__is_valid_arg(other): + return self.__value + other + + def __sub__(self, other): + if GlobalFloat.__is_valid_arg(other): + return self.__value - other + + def __eq__(self, other): + if self.__value == other: + return True + return False + + def __ne__(self, other): + if self.__value != other: + return True + return False + + def __ge__(self, other): + if self.__value >= other: + return True + return False + + def __gt__(self, other): + if self.__value > other: + return True + return False + + def __le__(self, other): + if self.__value <= other: + return True + return False + + def __lt__(self, other): + if self.__value < other: + return True + return False + + def __str__(self): + return str(round(self.__value, 2)) + + +class ErrorClass: + """класс возврата ошибки с кодом""" + + __slots__ = ['__success', '__error_code'] + + def __init__(self): + self.__success = True + self.__error_code = 0 + + def set_error(self, error_code: int): + self.__success = False + if 0 < error_code < 1000 and type(error_code) == int: + self.__error_code = error_code + + def get_error_code(self): + return self.__error_code + + def __bool__(self): + return self.__success + + def __str__(self): + if self.__success: + return 'No error' + else: + return 'Error code: ' + str(self.__error_code) + + def t_stamp(): now = datetime.now() stamp = datetime.strftime(now, '%d/%m %Y %H:%M:%S') @@ -233,12 +418,12 @@ def t_stamp_sh(): return stamp -# ловеркейс имени tg канала с проверкой валидности -def set_ch_name_lower(teststr): +# lowercase имени tg канала с проверкой валидности +def set_ch_name_lower(test_str): i = 0 - rezult = '' - while i < len(teststr): - char = teststr[i] + result = '' + while i < len(test_str): + char = test_str[i] code = ord(char) if code == 95: @@ -253,13 +438,13 @@ def set_ch_name_lower(teststr): if 96 < code < 123: pass else: - levent = 'ошибка конвертации канала: ' + str(i) + ' ' + str(code) + ' ' + char + ' ' + teststr + levent = 'ошибка конвертации канала: ' + str(i) + ' ' + str(code) + ' ' + char + ' ' + test_str logging.warning(levent) return False - rezult += chr(code) + result += chr(code) i += 1 - return rezult + return result # сборка имени юзера в читабельное @@ -281,45 +466,36 @@ def set_name_printable(first, last, account=None, phone=None, ad=''): # вывод числа с разделителями тысяч -def set_int_printable(integer, razd=' '): +def set_int_printable(integer, separator=' '): string = '{:,}'.format(integer) - string = string.replace(',', razd) + string = string.replace(',', separator) return string -# версия сервера постгрес -def get_server_version(dbc=None): - srv = PgServer(dbc) - sql = "select setting from pg_config where name='VERSION'" - row = srv.exec(sql, return_type=1) - version = row[0] - return version - - -# создает обьект клиента с параметрами из бд -def get_tg_client(name, dbc=None, cust_name=None): - srv = PgServer(dbc) +# создает объект клиента с параметрами из бд +def get_tg_client(name, custom_name=None): + srv = PgServer() n_api = name + '_api_id' - row = srv.exec('select value from parameters where name=%s', (n_api,), return_type=1) + row = srv.exec('select value from logins where name=%s', (n_api,), return_type=1) api_id = int(row[0]) n_hash = name + '_api_hash' - row = srv.exec('select value from parameters where name=%s', (n_hash,), return_type=1) + row = srv.exec('select value from logins where name=%s', (n_hash,), return_type=1) api_hash = row[0] - if cust_name is None: + if custom_name is None: client = TelegramClient(name, api_id, api_hash) else: - client = TelegramClient(cust_name, api_id, api_hash) + client = TelegramClient(custom_name, api_id, api_hash) return client # достает ключ бота из бд -def get_bot_key(name, dbc=None): - srv = PgServer(dbc) +def get_bot_key(name): + srv = PgServer() bot = name + '_key' - row = srv.exec('select value from parameters where name=%s', (bot,), return_type=1) + row = srv.exec('select value from logins where name=%s', (bot,), return_type=1) bot_key = row[0] return bot_key