diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2023-09-22 12:20:33 +0300 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2023-09-22 12:20:33 +0300 |
| commit | cc8680564d259313042b211c0d40fa818b32059a (patch) | |
| tree | 982aede1a088565d8dbbff3736838363923b9ddf /app | |
| parent | 27d7323dc47a06553e7c664f52102f4ffe120759 (diff) | |
Add email alerts
Diffstat (limited to 'app')
| -rw-r--r-- | app/AggroConfig.py | 18 | ||||
| -rw-r--r-- | app/EmailAlerter.py | 47 | ||||
| -rw-r--r-- | app/PluginManager.py | 19 | ||||
| -rw-r--r-- | app/utils.py | 12 |
4 files changed, 88 insertions, 8 deletions
diff --git a/app/AggroConfig.py b/app/AggroConfig.py index 789fd6b..01d1230 100644 --- a/app/AggroConfig.py +++ b/app/AggroConfig.py @@ -4,9 +4,23 @@ from app.PluginInterface import Params @dataclass +class AggroConfigServer: + host: str + port: int + + +@dataclass +class AggroConfigEmailAlerter: + api_url: str + api_auth: str + email_from: str + email_to: list[str] + + +@dataclass class AggroConfig: - server_host: str - server_port: int + server: AggroConfigServer + email_alerter: AggroConfigEmailAlerter | None db_path: str plugins: dict[str, Params] graph: dict[str, list[str]] diff --git a/app/EmailAlerter.py b/app/EmailAlerter.py new file mode 100644 index 0000000..823cbf1 --- /dev/null +++ b/app/EmailAlerter.py @@ -0,0 +1,47 @@ +import requests +import traceback +from datetime import datetime +from app.AggroConfig import AggroConfigEmailAlerter +from dataclasses import asdict + + +class EmailAlerter: + @staticmethod + def from_config(config: AggroConfigEmailAlerter) -> "EmailAlerter": + return EmailAlerter(**asdict(config)) + + def __init__( + self, api_url: str, api_auth: str, email_from: str, email_to: list[str] + ): + self.api_url = api_url + self.email_from = email_from + self.email_to = email_to + api_auth_parts = api_auth.split(":") + if len(api_auth_parts) != 2: + raise Exception( + "[EmailAlerter] supplied api_auth is not of form <key>:<value>" + ) + self.api_auth = (api_auth_parts[0], api_auth_parts[1]) + + def send_alert(self, text: str): + try: + now = datetime.now() + now_text = now.strftime("%a, %d %b %Y %H:%M:%S +0000") + data = { + "from": self.email_from, + "to": self.email_to, + "subject": f"Aggro alert on {now_text}", + "text": text, + } + r = requests.post( + self.api_url, + auth=self.api_auth, + data=data, + ) + if r.status_code >= 400: + raise Exception( + f"[EmailAlerter] sending alert email via HTTP returned code {r.status_code} and body:\n{r.text}" + ) + + except: + traceback.print_exc() diff --git a/app/PluginManager.py b/app/PluginManager.py index cd810b0..86da22f 100644 --- a/app/PluginManager.py +++ b/app/PluginManager.py @@ -1,13 +1,16 @@ import importlib import schedule import time +import sys +import traceback from types import ModuleType from typing import Any from app.Item import Item from app.PluginInterface import Params, PluginInterface -from app.AggroConfig import AggroConfig +from app.AggroConfig import AggroConfig, AggroConfigEmailAlerter from app.utils import get_config from app.MemoryState import memory_state +from app.EmailAlerter import EmailAlerter class PluginManager: @@ -16,6 +19,8 @@ class PluginManager: self.plugin_instances: dict[str, PluginInterface] = {} self.config = config self.scheduled_plugin_ids: list[str] = [] + if self.config.email_alerter: + self.email_alerter = EmailAlerter.from_config(self.config.email_alerter) def load_plugin(self, plugin_name: str) -> None: module: ModuleType = importlib.import_module(f"plugins.{plugin_name}") @@ -36,9 +41,15 @@ class PluginManager: if not memory_state.running: return - plugin: PluginInterface = self.plugin_instances[id] - ret_items: list[Item] = plugin.process(source_id, items) - self.propagate(id, ret_items) + try: + plugin: PluginInterface = self.plugin_instances[id] + ret_items: list[Item] = plugin.process(source_id, items) + self.propagate(id, ret_items) + except Exception as ex: + exc = traceback.format_exc() + print(exc, file=sys.stderr) + if self.email_alerter: + self.email_alerter.send_alert(exc) def build_plugin_instances(self): for id in self.config.plugins: diff --git a/app/utils.py b/app/utils.py index 6deb147..5401c5c 100644 --- a/app/utils.py +++ b/app/utils.py @@ -22,7 +22,11 @@ def get_config(config: dict[str, Any], key: str) -> Any: except KeyError: raise Exception(f"no {key} field in config: " + str(config)) - return evaluate_env_ref(v) + if type(v) == list: + mapped = map(evaluate_env_ref, v) + return list(mapped) + else: + return evaluate_env_ref(v) def get_config_or_default( @@ -30,7 +34,11 @@ def get_config_or_default( ) -> Any: v: Any = config.get(key, default) - return evaluate_env_ref(v) + if type(v) == list: + mapped = map(evaluate_env_ref, v) + return list(mapped) + else: + return evaluate_env_ref(v) def item_to_dict(item: Item) -> ItemDict: |
