import json from dataclasses import dataclass from enum import Enum, StrEnum from typing import Optional import aiofiles import nio from alerting.common import CONFIG_FILE from misc import cvars class AlertType(StrEnum): TEST = "TEST" ERROR = "ERROR" RAM = "RAM" CPU = "CPU" TEMP = "TEMP" VULN = "VULN" LOGIN = "LOGIN" # TODO SMART = "SMART" # TODO RAID = "RAID" DISKS = "DISKS" UPS = "UPS" UPDATE = "UPDATE" class Severity(StrEnum): INFO = "INFO" WARNING = "WARNING" CRITICAL = "CRITICAL" @dataclass class Alert: alert_type: AlertType message: str severity: Severity html_message: Optional[str] = None async def get_client() -> nio.AsyncClient: """ Returns a Matrix client. It is better to call get_client once and use it for multiple send_alert calls """ matrix_cfg = cvars.config.get()["matrix"] client = nio.AsyncClient(matrix_cfg["homeserver"]) client.access_token = matrix_cfg["access_token"] client.user_id = matrix_cfg["user_id"] client.device_id = matrix_cfg["device_id"] return client def format_message(alert: Alert) -> str: match alert.severity: case Severity.INFO: severity_emoji = "â„šī¸" case Severity.WARNING: severity_emoji = "âš ī¸" case Severity.CRITICAL: severity_emoji = "🆘" message = f"{severity_emoji} {alert.alert_type} Alert\n{alert.message}" if alert.html_message: html_message = f"{severity_emoji} {alert.alert_type} Alert
{alert.html_message}" return message, html_message else: return message, None async def send_alert(alert: Alert) -> None: try: client = cvars.matrix_client.get() except LookupError: # being called standalone async with aiofiles.open(CONFIG_FILE) as f: contents = await f.read() cvars.config.set(json.loads(contents)) temp_client = True client = await get_client() cvars.matrix_client.set(client) else: temp_client = False room_id = cvars.config.get()["matrix"]["room_id"] message, html_message = format_message(alert) content = { "msgtype": "m.text", "body": message, } if html_message: content["format"] = "org.matrix.custom.html" content["formatted_body"] = html_message await client.room_send( room_id=room_id, message_type="m.room.message", content=content, ) if temp_client: await client.close()