core/homeassistant/components/telegram_bot/webhooks.py

109 lines
3.4 KiB
Python
Raw Normal View History

"""Support for Telegram bots using webhooks."""
import datetime as dt
import logging
from telegram.error import TimedOut
from homeassistant.components.http import HomeAssistantView
from homeassistant.components.http.const import KEY_REAL_IP
from homeassistant.const import (
2019-07-31 19:25:30 +00:00
EVENT_HOMEASSISTANT_STOP,
HTTP_BAD_REQUEST,
HTTP_UNAUTHORIZED,
)
from . import (
CONF_ALLOWED_CHAT_IDS,
CONF_TRUSTED_NETWORKS,
CONF_URL,
BaseTelegramBotEntity,
initialize_bot,
)
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
TELEGRAM_HANDLER_URL = "/api/telegram_webhooks"
REMOVE_HANDLER_URL = ""
async def async_setup_platform(hass, config):
"""Set up the Telegram webhooks platform."""
2019-07-31 19:25:30 +00:00
bot = initialize_bot(config)
current_status = await hass.async_add_job(bot.getWebhookInfo)
base_url = config.get(CONF_URL, hass.config.api.base_url)
# Some logging of Bot current status:
2019-07-31 19:25:30 +00:00
last_error_date = getattr(current_status, "last_error_date", None)
if (last_error_date is not None) and (isinstance(last_error_date, int)):
last_error_date = dt.datetime.fromtimestamp(last_error_date)
2019-07-31 19:25:30 +00:00
_LOGGER.info(
"telegram webhook last_error_date: %s. Status: %s",
last_error_date,
current_status,
)
else:
_LOGGER.debug("telegram webhook Status: %s", current_status)
handler_url = f"{base_url}{TELEGRAM_HANDLER_URL}"
2019-07-31 19:25:30 +00:00
if not handler_url.startswith("https"):
_LOGGER.error("Invalid telegram webhook %s must be https", handler_url)
return False
def _try_to_set_webhook():
retry_num = 0
while retry_num < 3:
try:
return bot.setWebhook(handler_url, timeout=5)
except TimedOut:
retry_num += 1
2019-07-31 19:25:30 +00:00
_LOGGER.warning("Timeout trying to set webhook (retry #%d)", retry_num)
2019-07-31 19:25:30 +00:00
if current_status and current_status["url"] != handler_url:
result = await hass.async_add_job(_try_to_set_webhook)
if result:
_LOGGER.info("Set new telegram webhook %s", handler_url)
else:
_LOGGER.error("Set telegram webhook failed %s", handler_url)
return False
hass.bus.async_listen_once(
2019-07-31 19:25:30 +00:00
EVENT_HOMEASSISTANT_STOP, lambda event: bot.setWebhook(REMOVE_HANDLER_URL)
)
hass.http.register_view(
BotPushReceiver(
hass, config[CONF_ALLOWED_CHAT_IDS], config[CONF_TRUSTED_NETWORKS]
)
)
return True
class BotPushReceiver(HomeAssistantView, BaseTelegramBotEntity):
"""Handle pushes from Telegram."""
requires_auth = False
url = TELEGRAM_HANDLER_URL
2019-07-31 19:25:30 +00:00
name = "telegram_webhooks"
def __init__(self, hass, allowed_chat_ids, trusted_networks):
"""Initialize the class."""
BaseTelegramBotEntity.__init__(self, hass, allowed_chat_ids)
self.trusted_networks = trusted_networks
async def post(self, request):
"""Accept the POST from telegram."""
real_ip = request[KEY_REAL_IP]
if not any(real_ip in net for net in self.trusted_networks):
_LOGGER.warning("Access denied from %s", real_ip)
2019-07-31 19:25:30 +00:00
return self.json_message("Access denied", HTTP_UNAUTHORIZED)
try:
data = await request.json()
except ValueError:
2019-07-31 19:25:30 +00:00
return self.json_message("Invalid JSON", HTTP_BAD_REQUEST)
if not self.process_message(data):
2019-07-31 19:25:30 +00:00
return self.json_message("Invalid message", HTTP_BAD_REQUEST)
2018-10-28 18:39:23 +00:00
return None