sync: 154 file da Baida98/AI@29e25a1b (2026-08-15 11:02 UTC) [deploy-all]

#32
by Baida07 - opened
api/telegram_webhook.py CHANGED
@@ -60,13 +60,24 @@ async def _tg_reply(chat_id: str | int, text: str, token: str | None = None,
60
  payload["reply_markup"] = keyboard
61
  try:
62
  import httpx
63
- async with httpx.AsyncClient(timeout=8.0) as c:
64
- await c.post(
 
 
 
65
  f"https://api.telegram.org/bot{bot_token}/sendMessage",
66
  json=payload,
67
  )
 
 
 
 
 
 
 
68
  except Exception as exc:
69
- _logger.warning("tg_reply error: %s", exc)
 
70
 
71
 
72
  async def _tg_answer_callback(callback_query_id: str, text: str = "", token: str | None = None) -> None:
 
60
  payload["reply_markup"] = keyboard
61
  try:
62
  import httpx
63
+ timeout = httpx.Timeout(connect=5.0, read=15.0, write=10.0, pool=5.0)
64
+ # Il backend non richiede proxy HTTP per raggiungere l'API Telegram.
65
+ # Ignorare proxy d'ambiente evita ReadTimeout silenziosi in hosting gestiti.
66
+ async with httpx.AsyncClient(timeout=timeout, trust_env=False) as c:
67
+ response = await c.post(
68
  f"https://api.telegram.org/bot{bot_token}/sendMessage",
69
  json=payload,
70
  )
71
+ try:
72
+ data = response.json()
73
+ except ValueError:
74
+ data = {}
75
+ if response.status_code >= 400 or not data.get("ok", False):
76
+ detail = str(data.get("description") or response.text[:160] or "unknown")
77
+ _logger.warning("tg_reply rejected: status=%s detail=%s", response.status_code, detail)
78
  except Exception as exc:
79
+ detail = str(exc) or repr(exc)
80
+ _logger.warning("tg_reply error: %s: %s", type(exc).__name__, detail)
81
 
82
 
83
  async def _tg_answer_callback(callback_query_id: str, text: str = "", token: str | None = None) -> None:
tests/test_telegram_reply_transport.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+ from unittest.mock import patch
3
+
4
+ import httpx
5
+
6
+ from api.telegram_webhook import _tg_reply
7
+
8
+
9
+ class _Response:
10
+ def __init__(self, status_code=200, payload=None, text=""):
11
+ self.status_code = status_code
12
+ self._payload = payload if payload is not None else {"ok": True}
13
+ self.text = text
14
+
15
+ def json(self):
16
+ return self._payload
17
+
18
+
19
+ class _Client:
20
+ instances = []
21
+ response = _Response()
22
+ exception = None
23
+
24
+ def __init__(self, **kwargs):
25
+ self.kwargs = kwargs
26
+ type(self).instances.append(self)
27
+
28
+ async def __aenter__(self):
29
+ return self
30
+
31
+ async def __aexit__(self, *_args):
32
+ return False
33
+
34
+ async def post(self, *_args, **_kwargs):
35
+ if type(self).exception is not None:
36
+ raise type(self).exception
37
+ return type(self).response
38
+
39
+
40
+ class TelegramReplyTransportTests(unittest.IsolatedAsyncioTestCase):
41
+ def setUp(self):
42
+ _Client.instances = []
43
+ _Client.response = _Response()
44
+ _Client.exception = None
45
+
46
+ async def test_reply_bypasses_environment_proxy_and_accepts_success(self):
47
+ with patch("httpx.AsyncClient", _Client):
48
+ await _tg_reply(123, "<b>hello</b>", token="test-token")
49
+
50
+ self.assertEqual(len(_Client.instances), 1)
51
+ self.assertFalse(_Client.instances[0].kwargs["trust_env"])
52
+ self.assertIsInstance(_Client.instances[0].kwargs["timeout"], httpx.Timeout)
53
+
54
+ async def test_reply_logs_rejected_telegram_response(self):
55
+ _Client.response = _Response(
56
+ status_code=429,
57
+ payload={"ok": False, "description": "Too Many Requests"},
58
+ )
59
+ with patch("httpx.AsyncClient", _Client), self.assertLogs(
60
+ "api.telegram_webhook", level="WARNING"
61
+ ) as logs:
62
+ await _tg_reply(123, "hello", token="test-token")
63
+
64
+ self.assertIn("status=429 detail=Too Many Requests", "\n".join(logs.output))
65
+
66
+ async def test_reply_logs_timeout_type_when_transport_fails(self):
67
+ _Client.exception = httpx.ReadTimeout("")
68
+ with patch("httpx.AsyncClient", _Client), self.assertLogs(
69
+ "api.telegram_webhook", level="WARNING"
70
+ ) as logs:
71
+ await _tg_reply(123, "hello", token="test-token")
72
+
73
+ self.assertIn("ReadTimeout", "\n".join(logs.output))
74
+
75
+
76
+ if __name__ == "__main__":
77
+ unittest.main()