Skip to main content

ferogram_mtsender/
lib.rs

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