Skip to main content

ferogram_mtsender/
lib.rs

1/*
2 * Copyright (c) 2026 Ankit Chaubey <ankitchaubey.dev@gmail.com>
3 * https://github.com/ankit-chaubey
4 *
5 * Project: ferogram
6 * Website: https://ferogram.dev
7 *
8 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
9 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
10 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
11 * This file may not be copied, modified, or distributed except according
12 * to those terms.
13 */
14
15#![cfg_attr(docsrs, feature(doc_cfg))]
16#![doc(html_root_url = "https://docs.rs/ferogram-mtsender/0.6.5")]
17//! MTProto sender pool and retry policy for ferogram.
18//!
19//! This crate is part of [ferogram](https://crates.io/crates/ferogram), an async Rust
20//! MTProto client built by [Ankit Chaubey](https://github.com/ankit-chaubey).
21//!
22//! - Channel: [t.me/Ferogram](https://t.me/Ferogram)
23//! - Chat: [t.me/FerogramChat](https://t.me/FerogramChat)
24//!
25//! Most users do not need this crate directly. The `ferogram` crate wraps
26//! everything. Use `ferogram-mtsender` only if you are building a custom
27//! dispatch layer or need direct access to the DC connection pool.
28//!
29//! # What's in here
30//!
31//! - **[`MtpSender`]**: Single-task MTProto sender. All TCP I/O (read, write,
32//!   ping) runs inside one Tokio task that owns the unsplit `TcpStream`.
33//!   Callers enqueue request bodies via [`MtpSender::enqueue`] and receive
34//!   results through a oneshot channel. This design eliminates mutex
35//!   contention between reader and writer halves and ensures ACKs are flushed
36//!   on every outgoing frame.
37//! - **[`DcPool`]**: Per-DC connection pool capped at three slots. Requests
38//!   are round-robined across live [`ConnSlot`]s. The pool opens new
39//!   connections on demand and replaces slots that have faulted.
40//! - **[`DcConnection`]**: One encrypted connection to a single DC. Handles
41//!   pending `msgs_ack` accumulation and issues `ping_delay_disconnect` to
42//!   keep the socket alive inside Telegram's 75-second idle window.
43//! - **[`RetryPolicy`] / [`RetryLoop`]**: Trait and executor for retry
44//!   behaviour on RPC failures. [`AutoSleep`] sleeps through `FLOOD_WAIT`
45//!   errors; [`NoRetries`] returns the error immediately. Implement the
46//!   trait to add exponential back-off or a circuit breaker.
47//! - **[`CircuitBreaker`]**: Stops issuing requests to a DC that has failed
48//!   repeatedly, giving the pool time to reconnect before hammering the
49//!   server.
50//! - **`spawn_sender_task` / [`SenderHandle`]**: Spawns the background I/O
51//!   loop and returns a handle for enqueuing RPCs, subscribing to
52//!   [`FrameEvent`]s (updates), and issuing [`ReconnectRequest`]s.
53//! - **[`InvocationError`] / [`RpcError`]**: Typed errors for failed RPC
54//!   calls, including flood waits, server errors, and transport failures.
55//!
56//! # Example: send an RPC via the pool
57//!
58//! ```rust,no_run
59//! use ferogram_mtsender::{DcPool, InvocationError};
60//! use ferogram_connect::TransportKind;
61//! use ferogram_session::DcEntry;
62//! use ferogram_tl_types::functions::help::GetConfig;
63//!
64//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
65//! let dc_entries: Vec<DcEntry> = vec![]; // populate from your session
66//! let mut pool = DcPool::new(2, &dc_entries, None, TransportKind::Full);
67//! let raw = pool.invoke_on_dc(2, &dc_entries, &GetConfig {}).await?;
68//! println!("raw response bytes: {}", raw.len());
69//! # Ok(())
70//! # }
71//! ```
72//!
73//! # Feature flags
74//!
75//! | Flag | What it enables |
76//! |---|---|
77//! | `metrics` | RPC/connection instrumentation (counters, histograms, gauges) via the [`metrics`](https://docs.rs/metrics) crate. Off by default; a zero-cost no-op shim is used otherwise. |
78
79#![deny(unsafe_code)]
80
81mod errors;
82mod metrics_shim;
83pub mod mtp_sender;
84mod pool;
85mod retry;
86mod sender;
87pub mod sender_task;
88
89pub use errors::{InvocationError, RpcError};
90pub use mtp_sender::MtpSender;
91pub use pool::{ConnSlot, DcPool};
92pub use retry::{AutoSleep, CircuitBreaker, NoRetries, RetryContext, RetryLoop, RetryPolicy};
93pub use sender::DcConnection;
94pub use sender_task::{
95    FrameEvent, PipelinedSender, ReconnectRequest, RpcEnqueue, SenderHandle, spawn_pipelined,
96    spawn_sender_task,
97};