class TelegramBotWrapper: def __init__(self, token) -> None: self.chat_ids = set() self.bot = TeleBot(token) for handler_dict in self.__build_handler_dicts(): self.bot.add_message_handler(handler_dict) def __build_handler_dicts(self): defaults = { 'commands': None, 'regexp': None, 'func': None, 'content_types': ['text'] } handlers_info_list = [{ 'handler': self._subscribe, 'commands': ['subscribe'] }, { 'handler': self._unsubscribe, 'commands': ['unsubscribe'] }] handler_dicts = [] for h_info in handlers_info_list: handler_dicts.append( TeleBot._build_handler_dict( h_info['handler'], **{ **defaults, 'commands': h_info['commands'] })) return handler_dicts def _subscribe(self, message): self.chat_ids.add(message.chat.id) self.bot.send_message(message.chat.id, 'Successfully subscribed on updates.') def _unsubscribe(self, message): self.chat_ids.remove(message.chat.id) self.bot.send_message(message.chat.id, 'Successfully unsubscribed from updates.') def start(self): self.bot.polling() def stop(self): self.bot.stop_bot() def notify(self, message): for chat_id in self.chat_ids: self.bot.send_message(chat_id, message)
class TelegramBot: def __init__(self, token: str, mongo: MongoDB): self._mongo = mongo self._bot = TeleBot(token) @self._bot.message_handler(commands=['start', 'help']) def send_welcome(message): try: self._mongo.update_telegram_id(message.chat.username, message.chat.id) self._bot.reply_to(message, "Howdy, how are you doing?") except Exception as e: self._bot.reply_to(message, str(e)) def set_bot(self, bot: TeleBot): self._bot = bot @self._bot.message_handler(commands=['start', 'help']) def send_welcome(message): try: self._mongo.update_telegram_id(message.chat.username, message.chat.id) self._bot.reply_to(message, "Howdy, how are you doing?") except Exception as e: self._bot.reply_to(message, str(e)) def get_bot(self): return self._bot def close(self): self._bot.stop_polling() self._bot.stop_bot() def start(self): self._bot.polling() def send_message(self, recipient: int, message: str): self._bot.send_message(recipient, message)
class TgBot(threading.Thread): def loadCommandConfig(self): pass def loadPersonConfig(self): persons = {} return persons def __init__(self, config, admins, tunnels, loopDelay=0.1, debug=False): super(TgBot, self).__init__() self.debug = debug self.stopped = Event() self.loopDelay = loopDelay self.admins = admins self.tunnels = tunnels self.config = config self.botUserName = config['botUserName'] self.bot = TeleBot(config['token']) self.commands = [ # AddAdmin(bot=self, cmd=['add-admin']), # Alarm('alarm', time.time()) Bind(bot=self, cmd=['b', 'bind']), ListBind(bot=self, cmd=['lb', 'listbind', 'list-bind']), Toggle(bot=self, cmd=['t', 'toggle']), ListToggle(bot=self, cmd=['lt', 'listtoggle', 'list-toggle']), UnBind(bot=self, cmd=['ub', 'unbind', 'un-bind']) ] self.persons = self.loadPersonConfig() def sendMessage(self, _id, _msg, parse_mode=None): self.bot.send_message(chat_id=_id, text=_msg, parse_mode=parse_mode) def replyTo(self, msg, _msg): self.bot.reply_to(msg, _msg) def listbind_handler(self, message): print(message) def handler(self, msg): for each in msg: try: _from = each.from_user _chat = each.chat if each.text and each.text.startswith('#'): _text = each.text for tunnel in getMatchTunnels(self.tunnels, tgId=_chat.id): if tunnel.tg['toggle']: name = _from.username or _from.first_name or _from.last_name message = '[Anonymous]: {0}'.format( _text[2:]) if _text.startswith( '##') else '[{0}]: {1}'.format( name, _text[1:]) tunnel.tk['queue'].put(message) if self.debug: print(each) except Exception as e: if self.debug: traceback.print_exc() def queueHandler(self): while not self.stopped.wait(self.loopDelay): for each in self.tunnels: tg = each.tg while not tg['queue'].empty() and tg['toggle']: chatId = tg['id'] msg = tg['queue'].get() try: if '<img' in msg: link = re.search('src=\".*?\"', msg).group(0)[5:-1] if '.gif' in msg: self.bot.send_document(chatId, link) else: self.bot.send_photo(chatId, link) elif '</' in msg: self.bot.send_message(chatId, msg, parse_mode='HTML') else: self.bot.send_message(chatId, msg, parse_mode='Markdown') except Exception as e: self.bot.send_message(chatId, msg) if self.debug: traceback.print_exc() def start(self): super(TgBot, self).start() for cmd in self.commands: cmd.register() self.bot.set_update_listener(self.handler) thread = threading.Thread(target=self.queueHandler) thread.start() def run(self): while not self.stopped.wait(self.loopDelay): try: self.bot.polling(none_stop=False) except: if self.debug: traceback.print_exc() def stop(self): self.bot.stop_bot() self.stopped.set()
class BaseTelegram: """Telegram is an alternative UI to the web API for the project. It works via telegram commands. If you need just to send a message to the project channel / group, use core.send_telegram_message()""" def __init__(self, app: App): self.app = app self.bot: Optional[TeleBot] = None self.is_started = False self.admins: list[int] = [] @synchronized def start(self) -> Optional[str]: """ Telegram bot can be started only if these bot settings are set: - telegram_token - telegram_admins - telegram_polling """ telegram_token = self.app.dconfig.get("telegram_token") telegram_polling = self.app.dconfig.get("telegram_polling") try: self.admins = [] for admin in self.app.dconfig.get("telegram_admins", "").split(","): admin = admin.strip() if admin: self.admins.append(int(admin)) except Exception as e: self.app.dlog("telegram_parse_admins", {"error": str(e)}) return f"telegram_parse_admins: {str(e)}" if telegram_token and telegram_polling and self.admins: Thread(target=self._start, args=(telegram_token, )).start() return None else: return "there are some unset configs: telegram_token or telegram_polling or telegram_admins" def _start(self, token: str): try: self.bot = TeleBot(token, skip_pending=True) self._init_base_commands() self.init_commands() self.is_started = True self.app.logger.debug("telegram started") self.bot.polling(none_stop=True) except Exception as e: self.is_started = False self.app.dlog("telegram_polling", {"error": str(e)}) self.app.logger.error(f"telegram polling: {str(e)}") @synchronized def stop(self): self.is_started = False if self.bot: self.bot.stop_bot() self.app.logger.debug("telegram stopped") def _init_base_commands(self): @self.bot.message_handler(commands=["start", "help"]) @self.auth(admins=self.admins, bot=self.bot) def help_handler(message: Message): self._send_message(message.chat.id, self.app.app_config.telegram_bot_help) @self.bot.message_handler(commands=["ping"]) @self.auth(admins=self.admins, bot=self.bot) def ping_handler(message: Message): text = message.text.replace("/ping", "").strip() self._send_message(message.chat.id, f"pong {text}") def init_commands(self): pass def _send_message(self, chat_id: int, message: str): for text in split_string(message, 4096): self.bot.send_message(chat_id, text) # type:ignore @staticmethod def auth(*, admins: list[int], bot: TeleBot): def outer(func): @functools.wraps(func) def wrapper(message: Message): if message.chat.id in admins: return func(message) else: bot.send_message(message.chat.id, "Who are you?") return wrapper return outer
class Telegram: """Telegram is an alternative UI to the web API for the project. It works via telegram commands. If you need just to send a message to the project channel / group, use system_service.send_telegram_message()""" def __init__(self, core: Core): self.core = core self.bot: Optional[TeleBot] = None self.is_started = False @synchronized def start(self): """ Telegram bot can be started only if these bot settings are set: - telegram_token - telegram_admins - telegram_polling """ app_bot = self.core.system_service.get_bot() if app_bot.telegram_token and app_bot.telegram_admins and app_bot.telegram_polling: Thread(target=self._start).start() return True def _start(self): try: self.bot = TeleBot(self.core.system_service.get_bot().telegram_token, skip_pending=True) self._init_commands() self.is_started = True self.core.log.debug("telegram started") self.bot.polling(none_stop=True) except Exception as e: self.is_started = False self.core.log.error(f"telegram polling: {str(e)}") @synchronized def stop(self): self.is_started = False if self.bot: self.bot.stop_bot() self.core.log.debug("telegram stopped") def _init_commands(self): @self.bot.message_handler(commands=["start", "help"]) @auth(admins=self.core.system_service.get_bot().telegram_admins, bot=self.bot) def help_handler(message: Message): result = """ /workers - List all workers /start_worker ${worker_name} - Start the worker /stop_worker ${worker_name} - Start the worker """ self._send_message(message.chat.id, result) @self.bot.message_handler(commands=["ping"]) @auth(admins=self.core.system_service.get_bot().telegram_admins, bot=self.bot) def ping_handler(message: Message): text = message.text.replace("/ping", "").strip() self._send_message(message.chat.id, f"pong {text}") @self.bot.message_handler(commands=["workers"]) @auth(admins=self.core.system_service.get_bot().telegram_admins, bot=self.bot) def workers_handler(message: Message): result = "" for w in self.core.db.worker.find({}, "name"): result += f"{w.name}, source={w.source}, started={w.started}\n" self._send_message(message.chat.id, result) @self.bot.message_handler(commands=["start_worker"]) @auth(admins=self.core.system_service.get_bot().telegram_admins, bot=self.bot) def start_handler(message: Message): chat_id = message.chat.id worker_name = message.text.replace("/start_worker", "").strip() if not worker_name: return self._send_message(chat_id, "usage: /start_worker ${worker_name}") worker = self.core.db.worker.find_one({"name": worker_name}) if worker: self.core.worker_service.start_worker(worker.id) return self._send_message(chat_id, "worker was started") else: self._send_message(message.chat.id, "worker was not found") @self.bot.message_handler(commands=["stop_worker"]) @auth(admins=self.core.system_service.get_bot().telegram_admins, bot=self.bot) def stop_handler(message: Message): chat_id = message.chat.id worker_name = message.text.replace("/stop_worker", "").strip() if not worker_name: return self._send_message(chat_id, "usage: /stop_worker ${worker_name}") worker = self.core.db.worker.find_one({"name": worker_name}) if worker: self.core.worker_service.stop_worker(worker.id) return self._send_message(chat_id, "worker was stopped") else: return self._send_message(chat_id, "worker was not found") def _send_message(self, chat_id: int, message: str): for text in split_string(message, 4096): self.bot.send_message(chat_id, text) # type:ignore