1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! An outbound Telegram Bot API notifier.
//!
//! This module exists to replace the hand-rolled `sendMessage` calls which had
//! been copied between projects, each with a different subset of the hard parts
//! missing. It is send-only on purpose: it has no polling, no webhooks, and no
//! update handling, because none of the consuming projects receive anything.
//!
//! # Formatting without escaping
//!
//! Messages are built from [`Message::builder`], which emits Telegram
//! *entities* rather than `parse_mode` markup. Telegram's own documentation
//! describes entities as what a Markdown or HTML parser is converted *into*, so
//! nothing is lost by skipping that step — and because no markup is ever
//! embedded in the text, interpolated values never need escaping:
//!
//! ```no_run
//! use webserver_base::telegram::{ChatId, Message, ReqwestTelegram, Telegram, TelegramSettings};
//!
//! # async fn example(untrusted_filename: &str) -> Result<(), Box<dyn std::error::Error>> {
//! let settings = TelegramSettings::builder("123456789:AA...").build()?;
//! let telegram = ReqwestTelegram::new(settings, None)?;
//!
//! telegram.send(
//! ChatId::Id(1234),
//! Message::builder()
//! .text("🎨 ")
//! .bold("New pattern")
//! .text("\nInput: ")
//! .code(untrusted_filename) // no escaping, ever
//! .build(),
//! );
//! # Ok(())
//! # }
//! ```
//!
//! # What it handles
//!
//! - **Length.** Telegram caps text at 4096 and captions at 1024 UTF-16 code
//! units. Oversized messages are split at natural boundaries, with entities
//! clamped and rebased onto each piece, capped at a configurable number of
//! chunks so an upstream bug cannot become a flood.
//! - **Rate limits.** Sends are queued per chat and paced at Telegram's
//! documented limits: one message per second per chat, thirty per second
//! overall.
//! - **Retries.** A `429` is retried after the `retry_after` Telegram supplies,
//! up to a ceiling; transient failures back off exponentially; permanent
//! client errors are never retried, and misconfiguration is logged loudly.
//! - **Secrets.** The bot token is a path segment of every request URL, so it
//! is held in a [`BotToken`] which refuses to print itself, and every
//! `reqwest` error has its URL stripped before it can reach a log.
pub use ChatId;
pub use ;
pub use TelegramError;
pub use ;
pub use ;
pub use ;
pub use BotToken;