76 lines
2.0 KiB
Python
76 lines
2.0 KiB
Python
import time
|
|
from datetime import datetime
|
|
from aiogram import Bot
|
|
from app import cfg
|
|
from services.alert_mute import is_muted, is_auto_muted
|
|
from services.incidents import log_incident
|
|
|
|
|
|
_LAST_SENT: dict[str, float] = {}
|
|
|
|
|
|
def _parse_hhmm(value: str) -> int | None:
|
|
try:
|
|
hours, minutes = value.strip().split(":", 1)
|
|
h = int(hours)
|
|
m = int(minutes)
|
|
except Exception:
|
|
return None
|
|
if not (0 <= h <= 23 and 0 <= m <= 59):
|
|
return None
|
|
return h * 60 + m
|
|
|
|
|
|
def _in_quiet_hours(alerts_cfg: dict) -> bool:
|
|
quiet = alerts_cfg.get("quiet_hours", {})
|
|
if not quiet.get("enabled", False):
|
|
return False
|
|
start_min = _parse_hhmm(quiet.get("start", "23:00"))
|
|
end_min = _parse_hhmm(quiet.get("end", "08:00"))
|
|
if start_min is None or end_min is None:
|
|
return False
|
|
if start_min == end_min:
|
|
return False
|
|
now = datetime.now()
|
|
now_min = now.hour * 60 + now.minute
|
|
if start_min < end_min:
|
|
return start_min <= now_min < end_min
|
|
return now_min >= start_min or now_min < end_min
|
|
|
|
|
|
async def notify(
|
|
bot: Bot,
|
|
chat_id: int,
|
|
text: str,
|
|
level: str = "info",
|
|
key: str | None = None,
|
|
category: str | None = None,
|
|
):
|
|
alerts_cfg = cfg.get("alerts", {})
|
|
if category and is_muted(category):
|
|
return
|
|
if category and is_auto_muted(cfg, category):
|
|
return
|
|
if _in_quiet_hours(alerts_cfg):
|
|
allow_critical = bool(alerts_cfg.get("quiet_hours", {}).get("allow_critical", True))
|
|
if not (allow_critical and level == "critical"):
|
|
return
|
|
|
|
dedup_sec = int(alerts_cfg.get("notify_cooldown_sec", alerts_cfg.get("cooldown_sec", 900)))
|
|
if dedup_sec > 0:
|
|
dedup_key = key or text
|
|
now = time.time()
|
|
last_time = _LAST_SENT.get(dedup_key, 0)
|
|
if now - last_time < dedup_sec:
|
|
return
|
|
_LAST_SENT[dedup_key] = now
|
|
|
|
try:
|
|
await bot.send_message(chat_id, text)
|
|
except Exception:
|
|
pass
|
|
try:
|
|
log_incident(cfg, text)
|
|
except Exception:
|
|
pass
|