Expand description
Async Rust client for the Telegram MTProto protocol.
ferogram works with both user accounts and bots. It talks directly to Telegram’s MTProto servers: there is no Bot API HTTP proxy involved.
Built by Ankit Chaubey. Community: t.me/Ferogram (channel) | t.me/FerogramChat (chat)
§Getting started
Add to Cargo.toml:
[dependencies]
ferogram = "0.3"
tokio = { version = "1", features = ["full"] }Get api_id and api_hash from my.telegram.org.
§Bot login
use ferogram::{Client, update::Update};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let (client, _shutdown) = Client::builder()
.api_id(std::env::var("API_ID")?.parse()?)
.api_hash(std::env::var("API_HASH")?)
.session("bot.session")
.connect()
.await?;
client.bot_sign_in(&std::env::var("BOT_TOKEN")?).await?;
client.save_session().await?;
let mut stream = client.stream_updates();
while let Some(upd) = stream.next().await {
if let Update::NewMessage(msg) = upd {
if !msg.outgoing() {
if let Some(text) = msg.text() {
msg.reply(text).await?;
}
}
}
}
Ok(())
}§User login
use ferogram::{Client, SignInError};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (client, _shutdown) = Client::builder()
.api_id(12345)
.api_hash("your_api_hash")
.session("my.session")
.connect()
.await?;
if !client.is_authorized().await? {
let token = client.request_login_code("+1234567890").await?;
let code = read_line();
match client.sign_in(&token, &code).await {
Ok(name) => println!("Signed in as {name}"),
Err(SignInError::PasswordRequired(t)) => {
client.check_password(*t, "2fa_password").await?;
}
Err(e) => return Err(e.into()),
}
client.save_session().await?;
}
client.send_message("me", "Hello from ferogram!").await?;
Ok(())
}§What’s covered
Authentication
- Phone + code + 2FA SRP user login
- Bot token login
- Session string export / import
Updates: typed variants from update::Update:
NewMessage, MessageEdited, MessageDeleted, CallbackQuery,
InlineQuery, InlineSend, UserStatus, UserTyping,
ParticipantUpdate, JoinRequest, MessageReaction, PollVote,
BotStopped, ShippingQuery, PreCheckoutQuery, ChatBoost, Raw
Messaging
- Send, edit, delete, forward, pin, unpin
- Reply-to, schedule, silent flag
- HTML and Markdown entity formatting (see
parsers) - Inline keyboards via [
keyboard::InlineKeyboardBuilder]
Media
- Concurrent chunked file upload
- Media and CDN file download
- Photo, document, audio, video, sticker
Peers and dialogs
- Automatic access-hash caching for users, chats, channels
- Paginated dialog iterator
- Paginated per-chat message history
- Global and per-chat message search
- Mark as read, delete dialogs, clear mentions
Dispatcher and filters (see filters)
FLOOD_WAITauto-retry with configurable policyfilters::Dispatcherwith composable filter combinators (&,|,!)- Middleware chain (pre-handler interception, see
middleware) - FSM for multi-step conversations (see
fsm)
Connection
- DC migration
- Transport probing: races Abridged vs Obfuscated connections
- SOCKS5 proxy (see
proxy) - DNS-over-HTTPS resolver with TTL cache
- Reconnect with session persistence
Raw API
client.invoke(&req)for any TL functionclient.invoke_on_dc(dc_id, &req)for specific DCs- All of Layer 224 accessible via
ferogram::tl
§Dispatcher and filters
use ferogram::filters::{Dispatcher, command, private, text_contains};
let mut dp = Dispatcher::new();
dp.on_message(command("start"), |msg| async move {
msg.reply("Hello!").await.ok();
});
dp.on_message(private() & text_contains("help"), |msg| async move {
msg.reply("Type /start to begin.").await.ok();
});§FSM
use ferogram::{FsmState, fsm::MemoryStorage};
use ferogram::filters::{Dispatcher, command, text};
use std::sync::Arc;
#[derive(FsmState, Clone, Debug, PartialEq)]
enum Form { Name, Age }
let mut dp = Dispatcher::new();
dp.with_state_storage(Arc::new(MemoryStorage::new()));
dp.on_message_fsm(text(), Form::Name, |msg, state| async move {
state.set_data("name", msg.text().unwrap()).await.ok();
state.transition(Form::Age).await.ok();
msg.reply("How old are you?").await.ok();
});§Session backends
| Backend | Feature flag | Notes |
|---|---|---|
BinaryFileBackend | default | Single file on disk |
InMemoryBackend | default | No persistence, tests |
StringSessionBackend | default | Base64 string, serverless |
SqliteBackend | sqlite-session | Multi-session local file |
LibSqlBackend | libsql-session | Turso / distributed libSQL |
§Feature flags
| Flag | What it enables |
|---|---|
sqlite-session | SqliteBackend via rusqlite |
libsql-session | LibSqlBackend via libsql-client |
html | parse_html / generate_html (built-in parser) |
html5ever | Replaces parse_html with spec-compliant html5ever |
derive | #[derive(FsmState)] macro |
serde | Serde support for session types |
parser | Re-exports ferogram-tl-parser for custom tooling |
codegen | Re-exports ferogram-tl-gen for custom tooling |
§Raw API
use ferogram::tl;
let req = tl::functions::messages::GetDialogs {
offset_date: 0,
offset_id: 0,
offset_peer: tl::enums::InputPeer::Empty,
limit: 20,
hash: 0,
exclude_pinned: false,
folder_id: None,
};
let result = client.invoke(&req).await?;Re-exports§
pub use fsm::FsmState;pub use builder::BuilderError;pub use builder::ClientBuilder;pub use keyboard::Button;pub use keyboard::InlineKeyboard;pub use keyboard::ReplyKeyboard;pub use media::Document;pub use media::DownloadIter;pub use media::Downloadable;pub use media::Photo;pub use media::Sticker;pub use media::UploadedFile;pub use participants::Participant;pub use participants::ProfilePhotoIter;pub use peer_ref::PeerRef;pub use proxy::MtProxyConfig;pub use proxy::parse_proxy_link;pub use search::GlobalSearchBuilder;pub use search::SearchBuilder;pub use socks5::Socks5Config;pub use types::ChannelKind;pub use types::Channel;pub use types::Chat;pub use types::Group;pub use types::User;pub use typing_guard::TypingGuard;pub use update::BotStoppedUpdate;pub use update::MessageReactionUpdate;pub use update::PollVoteUpdate;pub use update::ButtonFilter;pub use update::Update;pub use update::ChatActionUpdate;pub use update::JoinRequestUpdate;pub use update::ParticipantUpdate;pub use update::UserStatusUpdate;pub use update::ChatBoostUpdate;pub use update::PreCheckoutQueryUpdate;pub use update::ShippingQueryUpdate;pub use ferogram_tl_types as tl;pub use ferogram_mtproto as mtproto;pub use ferogram_crypto as crypto;pub use ferogram_tl_parser as parser;parserpub use ferogram_tl_gen as codegen;codegen
Modules§
- authentication
- MTProto authentication key generation (DH handshake steps).
- builder
- cdn_
download - Telegram CDN DC file downloads.
- conversation
- dc_
migration - dc_pool
- dns_
resolver - DNS-over-HTTPS resolver.
- filters
- fsm
- inline_
iter - keyboard
- macros
- media
- message_
box - middleware
- parsers
- participants
- peer_
ref - persist
- proxy
- reactions
- search
- session_
backend - socks5
- special_
config - Firebase / Google special-config fallback.
- transport_
intermediate - transport_
obfuscated - types
- typing_
guard - update
- util
Macros§
Structs§
- AuthKey
- A Telegram authorization key (256 bytes) plus pre-computed identifiers.
- Auto
Sleep - Automatically sleep on
FLOOD_WAITand retry once on transient I/O errors. - Binary
File Backend - Stores the session in a compact binary file (v2 format).
- Circuit
Breaker - A
RetryPolicythat stops retrying afterthresholdconsecutive failures and stays silent for acooldownwindow before resetting. - Client
- The main Telegram client. Cheap to clone: internally Arc-wrapped.
- Config
- Configuration for
Client::connect. - DcEntry
- One entry in the DC address table.
- DcFlags
- Per-DC option flags.
- Dialog
- A Telegram dialog (chat, user, channel).
- Dialog
Iter - Cursor-based iterator over dialogs. Created by
Client::iter_dialogs. - Experimental
Features - Opt-in experimental behaviours that deviate from strict Telegram spec.
- Exponential
Backoff - Exponential backoff with jitter.
- Finished
- The final output of a successful auth key handshake.
- Fixed
Interval - Forward
Options - Options for forwarding messages.
- InMemory
Backend - Ephemeral in-process session: nothing persisted to disk.
- Input
Message - Builder for composing outgoing messages.
- Login
Token - Opaque token returned by
crate::Client::request_login_code. - Message
Iter - Cursor-based iterator over message history. Created by
Client::iter_messages. - Mini
AppSession - An active mini-app session returned by
Client::open_mini_app. - Never
Restart - NoRetries
- Never retry: propagate every error immediately.
- Password
Token - Opaque 2FA challenge token returned in
SignInError::PasswordRequired. - Peer
Cache - Caches access hashes for users and channels so every API call carries the correct hash without re-resolving peers.
- Retry
Context - Context passed to
RetryPolicy::should_retryon each failure. - RpcError
- An error returned by Telegram’s servers in response to an RPC call.
- Sqlite
Backend sqlite-session - SQLite-backed session (via
rusqlite). - String
Session Backend - Portable base64 string session backend.
- Update
Stream - Asynchronous stream of
Updates.
Enums§
- Invocation
Error - The error type returned from any
Clientmethod that talks to Telegram. - Link
Kind - Selects which flavour of message link
Client::export_message_linkshould produce. - MiniApp
- Which kind of mini-app to open.
- Sign
InError - Errors returned by
crate::Client::sign_in. - Transport
Kind - Update
State Change - A single update-sequence change, applied via
SessionBackend::apply_update_state.
Constants§
- LAYER
- The API layer this code was generated from.
Traits§
- Connection
Restart Policy - Identifiable
- Every generated type has a unique 32-bit constructor ID.
- Retry
Policy - Controls how the client reacts when an RPC call fails.
- Serializable
- Session
Backend - Synchronous snapshot backend: saves and loads the full session at once.
Functions§
- finish
- Finalise the handshake.
- step1
- Generate a
req_pq_multirequest. Returns the request + opaque state. - step2
- Process
ResPQand generatereq_DH_params. - step3
- Process
ServerDhParamsinto a reusableDhParamsForRetry+ send the firstset_client_DH_paramsrequest.
Type Aliases§
- Shutdown
Token - A token that can be used to gracefully shut down a
Client.