monitor: scope per chat_id (перенесено из AGENTS.MD)

This commit is contained in:
Алексей Будаев 2026-06-14 00:58:11 +08:00
parent d5f84d6254
commit 76dcb8ed52

View file

@ -847,11 +847,23 @@ def dns_lookup(domain):
# --- Site monitors ---
def load_monitors():
return load_json(MONITORS_FILE, [])
data = load_json(MONITORS_FILE, {})
if isinstance(data, list):
old = data
data = {}
for m in old:
cid = m.pop("added_chat", None)
if cid:
data.setdefault(str(cid), []).append(m)
save_monitors(data)
return data
def save_monitors(data):
save_json(MONITORS_FILE, data)
def get_chat_monitors(data, chat_id):
return data.get(str(chat_id), [])
def check_url(url):
try:
r = requests.get(url, timeout=MONITOR_TIMEOUT, allow_redirects=True)
@ -868,25 +880,24 @@ def monitor_worker(account):
time.sleep(MONITOR_INTERVAL)
monitors = load_monitors()
changed = False
for m in monitors:
ok, detail = check_url(m["url"])
was_ok = m.get("last_ok")
m["last_check"] = time.time()
if was_ok is not None and ok != was_ok:
if ok:
alert = f"Сайт восстановлен\n{m['url']}"
else:
alert = f"САЙТ НЕДОСТУПЕН\n{m['url']}\nСтатус: {detail}"
chat_id = m.get("added_chat")
if chat_id:
for chat_id, chat_monitors in monitors.items():
for m in chat_monitors:
ok, detail = check_url(m["url"])
was_ok = m.get("last_ok")
m["last_check"] = time.time()
if was_ok is not None and ok != was_ok:
if ok:
alert = f"Сайт восстановлен\n{m['url']}"
else:
alert = f"САЙТ НЕДОСТУПЕН\n{m['url']}\nСтатус: {detail}"
try:
account._rpc.send_msg(account.id, chat_id, {"text": alert})
account._rpc.send_msg(account.id, int(chat_id), {"text": alert})
except Exception as e:
logger.error(f"Monitor alert error: {e}")
logger.info(f"Monitor: {m['url']} {'UP' if ok else 'DOWN'} ({detail})")
m["last_ok"] = ok
m["last_detail"] = detail
changed = True
logger.info(f"Monitor: {m['url']} {'UP' if ok else 'DOWN'} ({detail})")
m["last_ok"] = ok
m["last_detail"] = detail
changed = True
if changed:
save_monitors(monitors)
@ -1979,32 +1990,33 @@ def handle_message(event):
parts = text.split(maxsplit=1)
subcmd = parts[1].strip().lower() if len(parts) > 1 else ""
monitors = load_monitors()
chat_monitors = get_chat_monitors(monitors, chat_id)
if subcmd.startswith("add "):
url = subcmd[4:].strip()
if not url.startswith("http"):
url = "https://" + url
if any(m["url"] == url for m in monitors):
if any(m["url"] == url for m in chat_monitors):
message.chat.send_text(f"Уже в мониторинге: {url}")
else:
ok, detail = check_url(url)
monitors.append({
chat_monitors.append({
"url": url,
"added_chat": chat_id,
"last_ok": ok,
"last_check": time.time(),
"last_detail": detail,
})
monitors[str(chat_id)] = chat_monitors
save_monitors(monitors)
status = "доступен" if ok else f"НЕДОСТУПЕН ({detail})"
message.chat.send_text(f"Добавлен: {url}\nСтатус: {status}")
elif subcmd in ("list", "список", ""):
if not monitors:
if not chat_monitors:
message.chat.send_text("Список пуст. /monitor add <url>")
else:
lines = [f"Мониторинг ({len(monitors)}):"]
for i, m in enumerate(monitors, 1):
lines = [f"Мониторинг ({len(chat_monitors)}):"]
for i, m in enumerate(chat_monitors, 1):
icon = "OK" if m.get("last_ok") else "DOWN"
checked = datetime.fromtimestamp(m["last_check"], tz=IRKUTSK_TZ).strftime("%H:%M") if m.get("last_check") else ""
lines.append(f"{i}. [{icon}] {m['url']} (проверен {checked})")
@ -2014,34 +2026,37 @@ def handle_message(event):
arg = subcmd[7:].strip()
if arg.isdigit():
idx = int(arg) - 1
if 0 <= idx < len(monitors):
removed = monitors.pop(idx)
if 0 <= idx < len(chat_monitors):
removed = chat_monitors.pop(idx)
monitors[str(chat_id)] = chat_monitors
save_monitors(monitors)
message.chat.send_text(f"Удалён: {removed['url']}")
else:
message.chat.send_text("Неверный номер. /monitor list — список.")
else:
url = arg if arg.startswith("http") else "https://" + arg
before = len(monitors)
monitors = [m for m in monitors if m["url"] != url]
if len(monitors) < before:
before = len(chat_monitors)
chat_monitors = [m for m in chat_monitors if m["url"] != url]
if len(chat_monitors) < before:
monitors[str(chat_id)] = chat_monitors
save_monitors(monitors)
message.chat.send_text(f"Удалён: {url}")
else:
message.chat.send_text(f"Не найден: {url}")
elif subcmd == "check":
if not monitors:
if not chat_monitors:
message.chat.send_text("Список пуст.")
else:
lines = ["Проверка:"]
for m in monitors:
for m in chat_monitors:
ok, detail = check_url(m["url"])
m["last_ok"] = ok
m["last_check"] = time.time()
m["last_detail"] = detail
icon = "OK" if ok else f"DOWN: {detail}"
lines.append(f"[{icon}] {m['url']}")
monitors[str(chat_id)] = chat_monitors
save_monitors(monitors)
message.chat.send_text("\n".join(lines))
else: