чиню телегу
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
dv 2026-03-15 23:51:59 +03:00
parent 88c4c84dec
commit a8723bb3ee
4 changed files with 43 additions and 4 deletions

View file

@ -12,9 +12,12 @@
""" """
from __future__ import annotations from __future__ import annotations
import logging
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
log = logging.getLogger(__name__)
# ── Агностичное представление клавиатуры ────────────────────────────────────── # ── Агностичное представление клавиатуры ──────────────────────────────────────
@ -101,39 +104,48 @@ class TelegramChannelNotifier(Notifier):
# ── Реализация интерфейса ────────────────────────────────────────────────── # ── Реализация интерфейса ──────────────────────────────────────────────────
def send(self, text: str, keyboard: Keyboard | None = None) -> int: def send(self, text: str, keyboard: Keyboard | None = None) -> int:
log.info("Telegram send_message → channel %s", self._channel_id)
msg = self._bot.send_message( msg = self._bot.send_message(
self._channel_id, text, self._channel_id, text,
parse_mode="Markdown", parse_mode="Markdown",
disable_web_page_preview=True, disable_web_page_preview=True,
reply_markup=self._to_markup(keyboard), reply_markup=self._to_markup(keyboard),
) )
log.info("Telegram send_message OK, message_id=%s", msg.message_id)
return msg.message_id return msg.message_id
def edit_text(self, message_id: int, text: str, keyboard: Keyboard | None = None): def edit_text(self, message_id: int, text: str, keyboard: Keyboard | None = None):
log.info("Telegram edit_message_text → message_id=%s", message_id)
self._bot.edit_message_text( self._bot.edit_message_text(
text, self._channel_id, message_id, text, self._channel_id, message_id,
parse_mode="Markdown", parse_mode="Markdown",
disable_web_page_preview=True, disable_web_page_preview=True,
reply_markup=self._to_markup(keyboard), reply_markup=self._to_markup(keyboard),
) )
log.info("Telegram edit_message_text OK, message_id=%s", message_id)
def edit_keyboard(self, message_id: int, keyboard: Keyboard | None): def edit_keyboard(self, message_id: int, keyboard: Keyboard | None):
log.info("Telegram edit_message_reply_markup → message_id=%s", message_id)
self._bot.edit_message_reply_markup( self._bot.edit_message_reply_markup(
self._channel_id, message_id, self._channel_id, message_id,
reply_markup=self._to_markup(keyboard), reply_markup=self._to_markup(keyboard),
) )
def delete(self, message_id: int): def delete(self, message_id: int):
log.info("Telegram delete_message → message_id=%s", message_id)
try: try:
self._bot.delete_message(self._channel_id, message_id) self._bot.delete_message(self._channel_id, message_id)
except Exception: log.info("Telegram delete_message OK, message_id=%s", message_id)
pass except Exception as e:
log.warning("Telegram delete_message failed (message_id=%s): %s", message_id, e)
def send_animation(self, url: str, disable_notification: bool = True) -> int: def send_animation(self, url: str, disable_notification: bool = True) -> int:
log.info("Telegram send_animation → channel %s", self._channel_id)
msg = self._bot.send_animation( msg = self._bot.send_animation(
self._channel_id, url, self._channel_id, url,
disable_notification=disable_notification, disable_notification=disable_notification,
) )
log.info("Telegram send_animation OK, message_id=%s", msg.message_id)
return msg.message_id return msg.message_id
def is_stale_error(self, exc: Exception) -> bool: def is_stale_error(self, exc: Exception) -> bool:

View file

@ -51,6 +51,7 @@ def recreate_post(
Комментарии (💬 ...) и описания (📝 ...) добавляются всегда. Комментарии (💬 ...) и описания (📝 ...) добавляются всегда.
""" """
notifier = get_notifier() notifier = get_notifier()
stored = database.get_stored_events(task_id) stored = database.get_stored_events(task_id)
stored_set = set(stored) stored_set = set(stored)

View file

@ -38,10 +38,17 @@ access_log_format = '%(h)s "%(r)s" %(s)s %(b)s %(D)sµs'
def on_starting(server): def on_starting(server):
"""Инициализация до форка воркеров (выполняется в мастер-процессе).""" """Инициализация до форка воркеров (выполняется в мастер-процессе)."""
import logging
import config import config
import database import database
from intradesk import reference from intradesk import reference
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
handlers=[logging.StreamHandler()],
)
os.makedirs(os.path.dirname(config.DB_FILE), exist_ok=True) os.makedirs(os.path.dirname(config.DB_FILE), exist_ok=True)
database.init_db() database.init_db()
reference.seed_static() reference.seed_static()

View file

@ -1,6 +1,7 @@
import json import json
import logging import logging
import os import os
import queue
import threading import threading
from flask import Flask, Response, jsonify, render_template, request, stream_with_context, abort from flask import Flask, Response, jsonify, render_template, request, stream_with_context, abort
@ -19,6 +20,24 @@ from intradesk.handler import handle_webhook
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
app = Flask(__name__, template_folder=os.path.join(os.path.dirname(__file__), "templates")) app = Flask(__name__, template_folder=os.path.join(os.path.dirname(__file__), "templates"))
# ── Очередь вебхуков (последовательная обработка) ─────────────────────────────
_webhook_queue: queue.Queue = queue.Queue()
def _webhook_worker():
while True:
data = _webhook_queue.get()
try:
handle_webhook(data)
except Exception:
log.exception("Unhandled error in webhook worker")
finally:
_webhook_queue.task_done()
threading.Thread(target=_webhook_worker, daemon=True, name="webhook-worker").start()
# ── Авторизация ──────────────────────────────────────────────────────────────── # ── Авторизация ────────────────────────────────────────────────────────────────
@ -97,7 +116,7 @@ def webhook():
if not data: if not data:
return jsonify({"error": "Invalid JSON"}), 400 return jsonify({"error": "Invalid JSON"}), 400
threading.Thread(target=handle_webhook, args=(data,), daemon=True).start() _webhook_queue.put(data)
return jsonify({"ok": True}), 200 return jsonify({"ok": True}), 200