def job_update_computers_status(bot: Bot, job: Job): user_data = job.context if Session.get_from(user_data).connected: update_computers_status(user_data) else: job.schedule_removal()
def reminder_message(self, bot: Bot, job: Job): event = self.repository.find_by_id(job.context['event_id']) if not event: job.schedule_removal() return bot.sendMessage(job.context['chat_id'], text=EventInline.create_event_message(event), reply_markup=InlineKeyboardMarkup( inline_keyboard=EventInline.create_reply_keyboard(event)), parse_mode=ParseMode.HTML)
def test_schedule_removal(self): j0 = Job(self.job1, 0.1) j1 = Job(self.job1, 0.2) self.jq.put(j0) self.jq.put(Job(self.job1, 0.4)) self.jq.put(j1) j0.schedule_removal() j1.schedule_removal() sleep(1) self.assertEqual(2, self.result)
def job_notify_subscriber(bot: Bot, job: Job): chat_id = job.context['chat_id'] city = job.context['city'] subscriber = subscribers[chat_id] try: interesting_ads = list(filter(lambda ad: subscriber.is_interested_in(ad), current_ads[city])) new_ads = subscriber.review_ads(interesting_ads, city) for new_ad in new_ads: bot.sendMessage(chat_id=chat_id, text=new_ad.to_chat_message()) except Unauthorized: logging.warning('unauthorized in job notify. removing job') subscribers.pop(chat_id) job.schedule_removal()
def test_warnings(self, job_queue): j = Job(self.job_run_once, repeat=False) with pytest.warns(UserWarning): job_queue.put(j, next_t=0) j.schedule_removal() with pytest.raises(ValueError, match='can not be set to'): j.repeat = True j.interval = 15 assert j.interval_seconds == 15 j.repeat = True with pytest.raises(ValueError, match='can not be'): j.interval = None j.repeat = False with pytest.raises(ValueError, match='must be of type'): j.interval = 'every 3 minutes' j.interval = 15 assert j.interval_seconds == 15 with pytest.raises(ValueError, match='argument should be of type'): j.days = 'every day' with pytest.raises(ValueError, match='The elements of the'): j.days = ('mon', 'wed') with pytest.raises(ValueError, match='from 0 up to and'): j.days = (0, 6, 12, 14)
class EXPbot: def __init__(self, telegram): self.updater = Updater(telegram) self.j = self.updater.job_queue self.alert = {} self.currissue = {} self.curmsg = {} self.current_work = {} dp = self.updater.dispatcher dp.add_handler(CommandHandler('redmine', self.redmine)) dp.add_handler(CommandHandler('jenkins', self.jenkins)) dp.add_handler(CommandHandler('auth', self.auth, pass_args=True)) dp.add_handler(CallbackQueryHandler(self.filter_for_buttons)) #dp.add_handler(CallbackQueryHandler(self.filter_for_inline)) #dp.add_handler(InlineQueryHandler(self.inline_search)) #dp.add_handler(ChosenInlineResultHandler(self.inline_picture)) #dp.add_handler(MessageHandler([Filters.text], self.command_filter)) #dp.add_handler(MessageHandler([Filters.command], self.unknow)) def logger_wrap(self, message, command): user = message.from_user logger.info(u'%s from %s @%s %s' % (message.text[0:20], user.first_name, user.username, user.last_name)) @staticmethod def put_user(user, key, value): user.__setattr__(key, value) db.session.commit() def auth(self, bot, update, args): user = db.query(User).filter_by( user_id=str(update.message.from_user.id)).first() if user.user_auth == 1: return True elif args == ['123']: EXPbot.put_user(user, 'user_auth', 1) bot.sendMessage(update.message.chat_id, text='Ok', parse_mode=ParseMode.MARKDOWN) return True else: bot.sendMessage(update.message.chat_id, text=u'Необходима авторизация', parse_mode=ParseMode.MARKDOWN) return False def redmine(self, bot, update): try: db.add( User(str(update.message.from_user.id), update.message.from_user.name, 0)) db.commit() except: db.rollback() self.logger_wrap(update.message, 'redmine') self.alert[str(update.message.from_user.id)] = 0 if not self.auth(bot, update, args=None): return chat_id = str(update.message.chat_id) try: bot.editMessageReplyMarkup(chat_id=chat_id, message_id=self.curmsg) except: pass text = EXPbot.redmine_info() self.currissue[str(update.message.from_user.id)] = text keyboard = EXPbot.do_keyboard('redmine') bot.sendMessage(chat_id, text=text, parse_mode=ParseMode.MARKDOWN, reply_markup=keyboard) @staticmethod def redmine_info(): t_time = datetime.date.today() redmine = Redmine('http://help.heliosoft.ru', key='') issues_open_prov = redmine.issue.filter(project_id='experium', status_id='3', cf_19='me') issues_open_me = redmine.issue.filter(assigned_to_id='me') issues_open_all_totay = redmine.issue.filter(project_id='experium', created_on=str(t_time)) issues_open_all_totay_up = redmine.issue.filter(project_id='experium', updated_on=str(t_time)) text = '' text += u'*НА ПРОВЕРКУ!!!*\n' for t in issues_open_prov: text += ( u'[%s](http://help.heliosoft.ru/issues/%s) %s %s\n' % (str(t.id), str(t.id), str(t.status), str(t).decode('utf8'))) text += u'*\n\nЗАДАЧИ НА МНЕ!!!*\n' for t in issues_open_me: text += ( u'[%s](http://help.heliosoft.ru/issues/%s) %s %s\n' % (str(t.id), str(t.id), str(t.status), str(t).decode('utf8'))) text += (u'\n\n*Тикеты, добавленные за %s:*\n' % str(t_time.strftime('%d %b %Y'))) for t in issues_open_all_totay: text += ( u'[%s](http://help.heliosoft.ru/issues/%s) %s %s\n' % (str(t.id), str(t.id), str(t.status), str(t).decode('utf8'))) text += (u'\n\n*Тикеты, обновленные за %s:*\n' % str(t_time.strftime('%d %b %Y'))) for t in issues_open_all_totay_up: text += ( u'[%s](http://help.heliosoft.ru/issues/%s) %s %s\n' % (str(t.id), str(t.id), str(t.status), str(t).decode('utf8'))) return text def jenkins(self, bot, update): try: db.add( User(str(update.message.from_user.id), update.message.from_user.name, 0)) db.commit() except: db.rollback() try: chat_id = str(update.message.chat_id) if not self.auth(bot, update, args=None): return try: bot.editMessageReplyMarkup(chat_id=chat_id, message_id=self.curmsg) except: pass self.curmsg[str( update.message.from_user.id)] = str(update.message.message_id + 1) callback = 0 except: chat_id = str(update.callback_query.message.chat_id) self.curmsg[str(update.callback_query.from_user.id )] = update.callback_query.message.message_id callback = 1 self.J = Jenkins('http://buildsrv.experium.ru/', username="", password="") text = u'*Список доступных работ:*\n' buttons = [] for t in self.J.keys(): if 'Experium' in t: buttons.append([ telegram.InlineKeyboardButton(text=str(t), callback_data=str(t)) ]) keyboard = telegram.InlineKeyboardMarkup(buttons) if callback == 0: bot.sendMessage(chat_id, text=text, parse_mode=ParseMode.MARKDOWN, reply_markup=keyboard) else: bot.editMessageText(text=text, chat_id=chat_id, message_id=self.curmsg[str( update.callback_query.from_user.id)], parse_mode=ParseMode.MARKDOWN, reply_markup=keyboard) def jenkins_work_info(self, cur_job): text = '' j = self.J.get_job(cur_job) try: q = j.get_last_good_build() text = u'*%s*\n\n*Последняя удачная сборка:*\n%s SVN REV - %s' % ( cur_job, str(q), str(q._get_svn_rev())) changes = q.get_changeset_items() text += u'\n\n*Изменения:*' for t in range(len(changes)): text += re.sub( r'#?(\d{4,}\b)', r'[#\1](http://help.heliosoft.ru/issues/\1)', u'\n*%s)*%s' % (str(t + 1), str(changes[t]['msg']).decode('utf8'))) except: pass if j.is_running(): text += u'\n\n*Текущее состояние:* идет сборка' else: text += u'\n\n*Текущее состояние:* сборка не выполняется' return text def filter_for_buttons(self, bot, update): query = update.callback_query if query.data == 'jenkins_build': j = self.J.get_job(self.current_work[str(query.from_user.id)]) if not j.is_queued_or_running(): self.J.build_job(self.current_work[str(query.from_user.id)]) self.job_jenkins_build = Job(self.build_monitor, 10.0, repeat=True, context=[ query.message.chat_id, self.current_work[str( query.from_user.id)] ]) self.j.put(self.job_jenkins_build) bot.answerCallbackQuery(callback_query_id=str(query.id), text=u'Сборка запущена') elif query.data == 'jenkins_close': self.jenkins(bot, update) elif query.data == 'redmine_alert': if self.alert[str(query.from_user.id)] == 0: bot.answerCallbackQuery(callback_query_id=str(query.id), text=u'Уведомления включены') self.alert[str(query.from_user.id)] = 1 self.job_redmine_alert = Job( self.issue_monitor, 60.0, repeat=True, context=[query.message.chat_id, query.from_user.id]) self.j.put(self.job_redmine_alert) else: bot.answerCallbackQuery(callback_query_id=str(query.id), text=u'Уведомления выключены') self.alert[str(query.from_user.id)] = 0 else: text = self.jenkins_work_info(query.data) self.current_work[str(query.from_user.id)] = query.data keyboard = EXPbot.do_keyboard('jenkins') bot.editMessageText(text=text, chat_id=query.message.chat_id, message_id=self.curmsg[str( query.from_user.id)], parse_mode=ParseMode.MARKDOWN, reply_markup=keyboard) @staticmethod def do_keyboard(flag): if flag == 'jenkins': keyboard = telegram.InlineKeyboardMarkup([[ telegram.InlineKeyboardButton(text=u'⚒', callback_data='jenkins_build'), #telegram.InlineKeyboardButton(text=u'📢', callback_data='jenkins_update'), telegram.InlineKeyboardButton(text=u'❌', callback_data='jenkins_close') ]]) if flag == 'redmine': keyboard = telegram.InlineKeyboardMarkup([[ telegram.InlineKeyboardButton(text=u'📢', callback_data='redmine_alert') ]]) return keyboard def build_monitor(self, bot, job): j = self.J.get_job(job.context[1]) if j.is_running(): return else: bot.sendMessage( chat_id=job.context[0], text=u'Сборка %s завершена\n\n%s' % (job.context[1], self.jenkins_work_info(job.context[1])), parse_mode=ParseMode.MARKDOWN) self.job_jenkins_build.schedule_removal() def issue_monitor(self, bot, job): if self.alert[str(job.context[1])] == 1: try: new_text = EXPbot.redmine_info() if self.currissue[str(job.context[1])] != new_text: cd = difflib.ndiff( u''.join(self.currissue[str( job.context[1])]).splitlines(), u''.join(new_text).splitlines()) final = '\n'.join(list(cd)) bot.sendMessage(chat_id=job.context[0], text=u'📢\n%s' % final, parse_mode=ParseMode.MARKDOWN) self.currissue[str(job.context[1])] = new_text except: pass else: self.job_redmine_alert.schedule_removal() def unknow(self, bot, update): self.logger_wrap(update.message, 'unknow') def error(self, bot, update, error): self.logger_wrap(update.message, 'error') logger.warn('Update "%s" caused error "%s"' % (update, error)) def idle(self): self.updater.start_polling() self.updater.idle()
def remove_job(context: CallbackContext, chat_id: int, job: Job): job_key = JOB_TO_CHAT_DATA_KEY[job.name] context._dispatcher.chat_data[chat_id][JOBS][job_key].remove(job) job.schedule_removal()
def caps(bot, update, args): text_caps = ' '.join(args).upper() bot.sendMessage(chat_id=update.message.chat_id, text=text_caps) def callback_minute(bot, job): bot.sendMessage(chat_id='99601112', text='One message every minute') job_minute = Job(callback_minute, 60.0) j.put(job_minute, next_t=0.0) def callback_30(bot, job): bot.sendMessage(chat_id='99601112', text='A single message with 30s delay') j.put(Job(callback_30, 30.0, repeat=False)) job_minute.enabled = False # Temporarily disable this job job_minute.schedule_removal() # Remove this job completely caps_handler = CommandHandler('caps', caps, pass_args=True) dispatcher.add_handler(caps_handler) echo_handler = MessageHandler(Filters.text, echo) dispatcher.add_handler(echo_handler) start_handler = CommandHandler('start', start) dispatcher.add_handler(start_handler) updater.start_polling()
class TelegramBot(object): def __init__(self): self.config = configparser.ConfigParser() self.config.read('bot.config') self.updater = Updater(token=self.config.get('KEYS', 'bot_api')) self.dispatcher = self.updater.dispatcher self.job_queue = self.updater.job_queue self.garage_expire_request = None # job to handle expiring the codes if a garage is not selected self.logger = None self._init_logging() # Garage door params self.garage_door_base_url = None self.garage_door_user_pass = None self._set_garage_door_parameters() def _set_garage_door_parameters(self): hostname = self.config.get('GARAGE', 'hostname') port = self.config.get('GARAGE', 'port') user = self.config.get('GARAGE', 'username') password = self.config.get('GARAGE', 'password') self.garage_door_base_url = 'http://{0}:{1}'.format(hostname, port) self.garage_door_user_pass = (user, password) def _init_logging(self): log_file_path = os.path.join( self.config.get('ADMIN', 'log_file_location'), 'telegram-bot.log') logging.basicConfig(level=logging.INFO, format='%(message)s', filename=log_file_path) logger = logging.getLogger(__name__) self.logger = wrap_logger( logger, processors=[TimeStamper(), format_exc_info, JSONRenderer()], script="telegram_bot") def sender_is_admin(self, sender_id): sender_id = int(sender_id) admin_id = int(self.config.get('ADMIN', 'id')) if sender_id == admin_id: return True self.logger.warning("User {0} is not an admin".format(sender_id), sender_id=sender_id, admin_id=admin_id) return False def send_nagios_alerts(self, bot, job): """ Retrieves alerts and sends them """ admin_id = self.config.get('ADMIN', 'id') self.logger.info("Getting alerts from db") hostname = self.config.get('ALERTS', 'hostname') url = 'http://{0}/get_nagios_unsent_alerts'.format(hostname) r = requests.get(url) if r.status_code != 200: bot.sendMessage( chat_id=sender_id, text='An exception occured while acknowledging alert', reply_keyboard=None) return ConversationHandler.END unsent_alerts = r.json() if not unsent_alerts: # Nothing to do return ConversationHandler.END message_str = """""" for one_alert in unsent_alerts: # No need to check count as server limits it alert_id = one_alert['id'] url = 'http://{0}/update_alert/{1}/SENT'.format(hostname, alert_id) r = requests.get(url) if r.status_code != 200: bot.sendMessage( chat_id=sender_id, text='An exception occured while updating alert status', reply_keyboard=None) host_name = one_alert['hostname'] service_name = one_alert['hostname'] message_str += "Alert ID: {}".format(str(one_alert['id'])) message_str += one_alert['message_text'] if one_alert['acknowledgable']: acknowledgeable_alerts_cache[alert_id] = ( host_name, service_name) # Add to dictionary to track message_str += "--------------------\n" if message_str: message_str += "{0} messages sent".format(len(unsent_alerts)) # If there are alerts than can be acknowledged, add the keyboard to acknowledge reply_keyboard = None if acknowledgeable_alerts_cache: # We have some alerts that can be acknowledged options = [] # Stores the keys for the keyboard reply for alert_id, (host, service) in list( acknowledgeable_alerts_cache.items()): key_string = "acknowledge {alert_id} | {host} {service}".format( alert_id=alert_id, host=host, service=service) options.append([key_string]) # Store the key for the keyboard # Send the message with the keyboard reply_keyboard = ReplyKeyboardMarkup(options, one_time_keyboard=True) bot.sendMessage(chat_id=admin_id, text=message_str, reply_markup=reply_keyboard) self.logger.info("Finished sending {} alerts".format( len(unsent_alerts))) def power_status(self, bot, update, args): arguments_to_use = ['status', 'timeleft'] complete_output = "" self.logger.info("Got request to check power status", sender_id=update.message.chat_id) for one_arg in arguments_to_use: command_to_run = [ '/usr/lib/nagios/plugins/check_apcupsd {0}'.format(one_arg) ] complete_output += subprocess.check_output(command_to_run, shell=True) bot.sendMessage(chat_id=update.message.chat_id, text=complete_output) self.logger.info("Sent message for power status", sender_id=update.message.chat_id) def acknowledge_alert(self, bot, update, groups): """ Given a string in the form of "acknowledge <ID> | <SOME DESC>" this sends the appropriate nagios commands :param bot: :param update: :param groups: tuple of regex group :return: """ sender_id = update.message.chat_id self.logger.info("Got request to acknowledge id {0}".format( groups, sender_id=sender_id)) if not groups: # did not pass us an alert id bot.sendMessage(chat_id=update.message.chat_id, text="No alert specified") return ConversationHandler.END try: _, alert_id = groups[0].split(' ') alert_id = alert_id.strip() except IndexError: bot.sendMessage( chat_id=update.message.chat_id, text="Invalid string {} passed to acknowledge".format( groups[0])) return ConversationHandler.END if alert_id not in acknowledgeable_alerts_cache: bot.sendMessage(chat_id=update.message.chat_id, text="Did not find id {} in cache".format( groups[0])) self.logger.error("Attempted to access id {}. Cache had {}".format( alert_id, acknowledgeable_alerts_cache)) return ConversationHandler.END hostname = self.config.get('ALERTS', 'hostname') url = 'http://{0}/acknowledge/{1}'.format(hostname, alert_id) r = requests.get(url) if r.status_code != 200: bot.sendMessage( chat_id=sender_id, text='An exception occured while acknowledging alert', reply_keyboard=None) return ConversationHandler.END text = "Successfully scheduled downtime for id {0} for 1 day".format( alert_id) self.logger.info(text) bot.sendMessage(chat_id=sender_id, text=text, reply_keyboard=None) return ConversationHandler.END def _get_garage_position(self, garage_name='all'): # Returns whether the garage is open or closed request_url = '{0}/garage/status/{1}'.format(self.garage_door_base_url, garage_name) r = requests.get(request_url, auth=self.garage_door_user_pass) if r.status_code == 200: return r.json() return [] # Action for operating the garage def garage(self, bot, update): return_message = """""" sender_id = update.message.chat_id # Gives menu to select which garage to open if not self.sender_is_admin(sender_id): self.logger.warning("Unauthorized user", sender_id=sender_id) bot.sendMessage(chat_id=sender_id, text='Not authorized') return ConversationHandler.END options = [] # Stores the keys for the keyboard reply self.logger.info("Got request to open garage.", sender_id=sender_id) garage_statuses = self._get_garage_position() if not garage_statuses: bot.sendMessage( chat_id=sender_id, text='An exception occured while getting garage status', reply_keyboard=None) return ConversationHandler.END # Handle the reponse and creation of the keyboard return_message += "Pick a garage \n" for one_garage_dict in garage_statuses: garage_name = one_garage_dict['garage_name'] current_status = one_garage_dict['status'] return_message += ': '.join([ garage_name, current_status, one_garage_dict['status_time'] ]) + '\n' # Determine whether this can be opened or closed if not one_garage_dict['error']: action = 'CLOSE' if current_status == 'OPEN' else 'OPEN' key_string = ' '.join(['confirm', action, str(garage_name)]) options.append([key_string]) # Store the key for the keyboard options.append(["CANCEL GARAGE"]) # Store the key for the keyboard # Send the message with the keyboard reply_keyboard = ReplyKeyboardMarkup(options, one_time_keyboard=True) bot.sendMessage(chat_id=sender_id, text=return_message, reply_markup=reply_keyboard) # Expires request so that the conversation is not open forever def expire_request(bot, job): bot.sendMessage(chat_id=sender_id, text='Timeout reached. Please start again', reply_keyboard=None) return ConversationHandler.END # Add job to expire request self.garage_expire_request = Job(expire_request, 15.0, repeat=False) self.job_queue.put(self.garage_expire_request) # Set the conversation to go to the next state return GarageConversationState.CONFIRM def confirm_garage_action(self, bot, update): sender_id = update.message.chat_id # See if there is a pending job to expire the request. Stop running it if there is if self.garage_expire_request is not None: self.garage_expire_request.schedule_removal() self.garage_expire_request = None if not self.sender_is_admin(update.message.chat_id): bot.sendMessage(chat_id=sender_id, text='Not authorized') return ConversationHandler.END action, garage_name = update.message.text.split(' ')[1:] request_url = '{0}/garage/control/{1}/{2}'.format( self.garage_door_base_url, garage_name, action) r = requests.get(request_url, auth=self.garage_door_user_pass) if r.status_code != 200: bot.sendMessage( chat_id=sender_id, text='An exception occured while sending the {0} command'. format(action), reply_keyboard=None) return ConversationHandler.END response = r.json() self.logger.info("User triggered opening of garage", sender_id=sender_id, garage_name=garage_name) bot.sendMessage(chat_id=sender_id, text=response['status']) def send_current_status(bot, job): response = self._get_garage_position(garage_name) text_to_send = ': '.join([ garage_name, response[0]['status'], response[0]['status_time'] ]) bot.sendMessage(chat_id=sender_id, text=text_to_send) # Wait to allow the door to move and send the status back self.job_queue.put(Job(send_current_status, 15.0, repeat=False)) return ConversationHandler.END def get_gemini_quote(self, quote_id): mapping = {"ETH": "ethusd", "BTC": "btcusd"} quote_name = mapping[quote_id] GEMINI_STR = "GEMINI_STR" if cache.get(GEMINI_STR): self.logger.info("Got hit for cache", exchange='GEMINI') return cache.get(GEMINI_STR) url = 'https://api.gemini.com/v1/pubticker/{0}'.format(quote_name) try: result = json.load(urllib.request.urlopen(url)) except Exception as e: self.logger.exception("Could not get quote from exchange", exc_info=e, exchange='GEMINI') return "Gemini", "", "Could not get quote from Gemini" bid_price = result['bid'] ask_price = result['ask'] quote_details = "Gemini", bid_price, ask_price # Store string into cache cache[GEMINI_STR] = quote_details return quote_details def get_gdax_quote(self, quote_name): GDAX_STR = "GDAX_STR" mapping = {"ETH": "ETH-USD", "BTC": "BTC-USD"} quote_name = mapping[quote_name] if cache.get(GDAX_STR): self.logger.info("Got hit for cache", exchange='GDAX') return cache.get(GDAX_STR) url = 'https://api.gdax.com/products/{0}/book'.format(quote_name) try: result = json.load(urllib.request.urlopen(url)) except Exception as e: self.logger.exception("Could not get quote from exchange", exc_info=e, exchange='GDAX') return "GDAX", "", "Could not get quote from GDAX" bid_price, bid_amount, _ = result['bids'][0] ask_price, ask_amount, _ = result['asks'][0] quote_details = "GDAX", bid_price, ask_price # Store string into cache cache[GDAX_STR] = quote_details return quote_details def get_coinmarketcap_data(self): COINMARKETCAP_STR = "COINMARKETCAP_STR" if market_cap_cache.get(COINMARKETCAP_STR): self.logger.info("Got hit for cache", exchange='COINMARKETCAP') return market_cap_cache.get(COINMARKETCAP_STR) url = 'https://api.coinmarketcap.com/v1/global/' try: result = json.load(urllib.request.urlopen(url)) except Exception as e: self.logger.exception("Could not get quote from exchange", exc_info=e, exchange='COINMARKETCAP') return "CoinMarketCap", "", "Could not get info from CoinMarketCap" total_market_cap = result['total_market_cap_usd'] bitcoin_percent_dominance = result['bitcoin_percentage_of_market_cap'] # Get volume of ETH and BTC url = 'https://api.coinmarketcap.com/v1/ticker/{0}' tickers_to_get = ['bitcoin', 'ethereum'] results = [] for ticker in tickers_to_get: try: results.append( json.load(urllib.request.urlopen(url.format(ticker)))) except Exception as e: self.logger.exception("Could not get quote from exchange", exc_info=e, exchange='COINMARKETCAP') return "CoinMarketCap", "", "Could not get info from CoinMarketCap" btc_result, ethereum_result = results btc_volume = btc_result[0]['24h_volume_usd'] eth_volume = ethereum_result[0]['24h_volume_usd'] eth_btc_volume_ratio = float(eth_volume) / float(btc_volume) final_result = (total_market_cap, bitcoin_percent_dominance, eth_btc_volume_ratio) market_cap_cache[COINMARKETCAP_STR] = final_result return final_result def get_current_quotes(self, bot, update, args): chat_id = update.message.chat_id if not self.sender_is_admin(chat_id): bot.sendMessage(chat_id=chat_id, text='Not authorized') return ConversationHandler.END quote_name = "ETH" if not args else str(args[0]) prices_to_get = [self.get_gdax_quote, self.get_gemini_quote] string_to_send = "Time: {0}\n".format( datetime.datetime.today().strftime("%Y-%m-%d %H:%m:%S")) for one_exchange in prices_to_get: exchange_name, bid_price, ask_price = one_exchange(quote_name) string_to_send += "{0} : Bid: {1} Ask: {2}\n".format( exchange_name, bid_price, ask_price) total_marketcap, btc_dominance, eth_btc_volume_ratio = self.get_coinmarketcap_data( ) string_to_send += "MarketCap: {0:d}B BTC Dom: {1} ETH/BTC Vol Ratio:{2:.2f}".format( int(total_marketcap / 1000000000), btc_dominance, eth_btc_volume_ratio) self.logger.info("Sending quote: {0}".format(string_to_send), sender_id=chat_id, exchange='GDAX') bot.sendMessage(chat_id=chat_id, text=string_to_send) return ConversationHandler.END def unknown_handler(self, bot, update): if update.message: chat_id = update.message.chat_id else: chat_id = update.channel.chat_id self.logger.warn("UNHANDLED MESSAGE".format(update.message.chat_id), sender_id=chat_id, message_dict=update.to_dict()) bot.sendMessage(chat_id=chat_id, text="Did not understand message") return ConversationHandler.END # Make sure to end any conversations def heartbeat_handler(self, bot, update): # Sents a signal to the nagios server that we are still up dict_to_send = [{ 'return_code': "0", 'plugin_output': "Telegram bot is up", 'service_description': "Telegram Bot Available", 'hostname': 'monitoring-station', }] url = self.config.get('ALERTS', 'passive_alerts_endpoint') requests.post(url, json=dict_to_send) def setup(self): self.logger.info("Starting up TelegramBot") power_status_handler = CommandHandler('powerstatus', self.power_status, pass_args=True) self.dispatcher.add_handler(power_status_handler) acknowledge_alert_handler = RegexHandler('^(acknowledge \d+)', self.acknowledge_alert, pass_groups=True) self.dispatcher.add_handler(acknowledge_alert_handler) # Handler for opening the garage garage_menu_handler = ConversationHandler( entry_points=[ CommandHandler('garage', self.garage), RegexHandler('^(Garage|garage)', self.garage), RegexHandler('^(Ga)', self.garage) ], states={ GarageConversationState.CONFIRM: [MessageHandler(ConfirmFilter(), self.confirm_garage_action)] }, fallbacks=[ MessageHandler(Filters.command | Filters.text, self.unknown_handler) ]) self.dispatcher.add_handler(garage_menu_handler) # GDAX quote handler gdax_quote_handler = CommandHandler('quotes', self.get_current_quotes, pass_args=True) self.dispatcher.add_handler(gdax_quote_handler) # Add handler for messages we arent handling unknown_handler = MessageHandler(Filters.command | Filters.text, self.unknown_handler) self.dispatcher.add_handler(unknown_handler) # Create the job to check if we have any nagios alerts to send self.job_queue.run_repeating(self.send_nagios_alerts, 90.0) # Add job to alert nagios server we are up if int(self.config.get('ALERTS', 'heartbeat')) == 1: self.logger.info("Enabling heartbeat handler for nagios") self.job_queue.run_repeating(self.heartbeat_handler, 120.0) def run(self): self.setup() self.updater.start_polling() self.updater.idle()