Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
๐ค layer-client
High-level async Telegram client for Rust.
Connect, authenticate, send messages, and stream updates with a clean async API.
Table of Contents
- Installation
- What It Does
- Minimal Bot โ 15 Lines
- Connecting โ ClientBuilder
- Authentication
- String Sessions โ Portable Auth
- Update Stream
- Messaging
- InputMessage Builder
- Keyboards
- Media Upload & Download
- Text Formatting
- Reactions
- Typing Guard โ RAII
- Participants & Chat Management
- Search
- Dialogs & Iterators
- Peer Resolution
- Session Backends
- Transport & Networking
- Feature Flags
- Configuration Reference
- Error Handling
- Raw API Escape Hatch
- Shutdown
๐ฆ Installation
[]
= "0.4.5"
= { = "1", = ["full"] }
โจ What It Does
layer-client wraps the raw MTProto machinery into a clean, ergonomic async API. You don't need to know anything about TL schemas, DH handshakes, or message framing โ just connect and go.
- ๐ User auth โ phone code + optional 2FA (SRP)
- ๐ค Bot auth โ bot token login
- ๐ฌ Messaging โ send, edit, delete, forward, pin, schedule
- ๐ Media โ upload files with automatic chunking, download with streaming
- ๐ก Update stream โ typed async events (
NewMessage,CallbackQuery,InlineQuery, etc.) - โจ๏ธ Keyboards โ fluent inline and reply keyboard builders
- ๐ FLOOD_WAIT retries โ automatic with configurable policy
- ๐ DC migration โ handled transparently
- ๐พ Session persistence โ five backends (file, memory, string, SQLite, libSQL)
- ๐งฆ SOCKS5 proxy โ route all connections through a proxy
- ๐ง Raw API access โ
client.invoke(req)for any TL function
๐ Minimal Bot โ 15 Lines
use ;
async
๐ Connecting โ ClientBuilder
The preferred way to connect is through the fluent ClientBuilder:
use Client;
let = builder
.api_id // from https://my.telegram.org
.api_hash
.session // file-backed session
.catch_up // replay missed updates on reconnect
.connect
.await?;
Other session options:
// In-memory session (lost on restart)
.in_memory
// Portable base64 string session (for cloud deployments)
.session_string
You can also use the lower-level Client::connect(Config { ... }) API directly if you prefer explicit struct construction.
๐ Authentication
User Login
use SignInError;
if !client.is_authorized.await?
Bot Login
client.bot_sign_in.await?;
client.save_session.await?;
Other Methods
// Get the currently logged-in user
let me = client.get_me.await?;
println!;
// Sign out (invalidates the server-side session)
client.sign_out.await?;
๐ฆ String Sessions โ Portable Auth
A string session encodes your auth key and DC info as a base64 string โ useful for deploying bots to servers or cloud functions without shipping a session file.
// Export the session to a string
let session_str = client.export_session_string.await?;
println!;
// Later, restore it:
let = builder
.api_id
.api_hash
.session_string
.connect.await?;
๐ก Update Stream
let mut stream = client.stream_updates;
while let Some = stream.next.await
IncomingMessage API
msg.id // โ i32
msg.text // โ Option<&str>
msg.markdown_text // โ Option<String> (text + entities as Markdown)
msg.html_text // โ Option<String> (text + entities as HTML)
msg.date // โ i32 (Unix timestamp)
msg.peer_id // โ Option<&Peer> (the chat this belongs to)
msg.sender_id // โ Option<&Peer> (None for anonymous posts)
msg.outgoing // โ bool
msg.via_bot_id // โ Option<i64>
msg.reply_to_msg_id // โ Option<i32>
// Reply with text
msg.reply.await?;
// Reply with an InputMessage builder
msg.reply_exawait?;
Spawning per-update tasks
use Arc;
let client = new;
while let Some = stream.next.await
๐ฌ Messaging
// Send by username, phone, "me", or numeric ID
client.send_message.await?;
client.send_message.await?;
client.send_to_self.await?;
// Send to a resolved peer directly
client.send_message_to_peer.await?;
// Send with full InputMessage options (see next section)
client.send_message_to_peer_ex.await?;
// Edit a message
client.edit_message.await?;
// Edit an inline message (for inline bot results)
client.edit_inline_message.await?;
// Forward messages
client.forward_messages.await?;
// Delete messages
client.delete_messages.await?;
// Pin / unpin
client.pin_message.await?;
client.unpin_message.await?;
client.unpin_all_messages.await?;
// Fetch message history
let msgs = client.get_messages.await?;
// Fetch specific messages by ID
let msgs = client.get_messages_by_id.await?;
// Fetch pinned message
let pinned = client.get_pinned_message.await?;
// Scheduled messages
let scheduled = client.get_scheduled_messages.await?;
client.delete_scheduled_messages.await?;
// Mark as read
client.mark_as_read.await?;
// Clear unread mentions
client.clear_mentions.await?;
๐ InputMessage Builder
InputMessage is the fluent builder for composing rich outgoing messages:
use InputMessage;
let msg = text
.reply_to
.silent
.no_webpage
.schedule_date // schedule for later
.schedule_once_online // send when recipient comes online
.keyboard
.entities
.copy_media; // attach media from another message
client.send_message_to_peer_ex.await?;
โจ๏ธ Keyboards
Inline Keyboards
use ;
let kb = new
.row
.row;
let msg = text.keyboard;
Reply Keyboards
use ReplyKeyboard;
let kb = new
.row
.row;
let msg = text.keyboard;
Answering Callback Queries
// Simple toast notification
client.answer_callback_query.await?;
// Alert popup
client.answer_callback_query.await?;
Answering Inline Queries
use layer_tl_types as tl;
let results = vec!;
client.answer_inline_query.await?;
๐ Media Upload & Download
Upload
// Upload a file from disk (auto-chooses sequential or concurrent based on size)
let uploaded = client.upload_file.await?;
// Concurrent upload (parallel worker pool โ faster for large files)
let uploaded = client.upload_file_concurrent.await?;
// Upload from an AsyncRead stream
let uploaded = client.upload_stream.await?;
// Send as photo
let media = uploaded.as_photo_media;
let msg = text.copy_media;
client.send_message_to_peer_ex.await?;
// Send as document (forces download button in Telegram)
let media = uploaded.as_document_media;
Albums (Multi-media)
use AlbumItem;
let items = vec!;
client.send_album.await?;
Download
// Download to a file
client.download_media_to_file.await?;
// Download to bytes in memory
let bytes = client.download_media.await?;
// Concurrent download (multi-worker, faster for large files)
let bytes = client.download_media_concurrent.await?;
// Streaming iterator (process chunks as they arrive)
let mut iter = client.iter_download;
while let Some = iter.next.await?
Typed Media Wrappers
use ;
// Extract from a message
if let Some = from_media
if let Some = from_media
if let Some = from_document
โ๏ธ Text Formatting
Markdown
use parse_markdown;
let = parse_markdown?;
let msg = text.entities;
HTML
// Built-in HTML parser (always available, no feature flag)
use parse_html;
let = parse_html?;
With the html5ever feature, HTML parsing is backed by the spec-compliant html5ever tokenizer (handles malformed markup):
= { = "0.4.5", = ["html5ever"] }
Formatting of incoming messages
// Reconstruct the Markdown from a received message's entities
let md = msg.markdown_text; // e.g. Some("Hello **world**!")
let html = msg.html_text; // e.g. Some("Hello <b>world</b>!")
๐ Reactions
// Send a reaction
client.send_reaction.await?;
// Remove a reaction (empty string)
client.send_reaction.await?;
โ Typing Guard โ RAII
TypingGuard automatically manages the typing indicator โ sends it immediately, keeps it alive by re-sending every ~4 seconds, and cancels it on drop.
use TypingGuard;
use layer_tl_types as tl;
async
For explicit chat actions without RAII:
use SendMessageAction;
client.send_chat_action.await?;
๐ฅ Participants & Chat Management
// Fetch participants (paginated internally)
let participants = client.get_participants.await?;
// Search participants by name
let matches = client.search_peer.await?;
// Kick (remove from group)
client.kick_participant.await?;
// Ban with granular rights
use BanRights;
let rights = default
.send_messages
.send_media;
client.ban_participant.await?;
// Promote to admin
use AdminRightsBuilder;
client.promote_participant.await?;
// Profile photos
let photos = client.get_profile_photos.await?;
// Effective permissions
let perms = client.get_permissions.await?;
// Join a chat / channel
client.join_chat.await?;
// Accept an invite link
client.accept_invite_link.await?;
๐ Search
In-chat search
let results = client
.search
.min_date
.max_date
.filter
.limit
.fetch
.await?;
Global search
let results = client
.search_global_builder
.broadcasts_only
.min_date
.limit
.fetch
.await?;
๐ Dialogs & Iterators
// Fetch the first N dialogs (snapshot)
let dialogs = client.get_dialogs.await?;
// Streaming dialog iterator (all dialogs, paginated automatically)
let mut iter = client.iter_dialogs;
while let Some = iter.next.await?
// Streaming message iterator for a chat
let mut iter = client.iter_messages;
iter.limit;
while let Some = iter.next.await?
// Delete a dialog
client.delete_dialog.await?;
๐ Peer Resolution
// From a username
let peer = client.resolve_peer.await?;
// From "me" (yourself)
let peer = client.resolve_peer.await?;
// From a numeric ID string
let peer = client.resolve_peer.await?;
// Resolve a username directly (returns the full User or Chat)
let entity = client.resolve_username.await?;
// Resolve to InputPeer (needed for raw API calls)
let input_peer = client.resolve_to_input_peer.await?;
๐พ Session Backends
| Backend | Type | Notes |
|---|---|---|
BinaryFileBackend |
File | Default โ fast binary format, survives restarts |
InMemoryBackend |
Memory | Ephemeral โ lost on restart; useful for tests |
StringSessionBackend |
String | Portable base64; inject via env var |
SqliteBackend |
SQLite | Requires sqlite-session feature |
LibSqlBackend |
libSQL | Requires libsql-session feature; works with Turso |
use ;
use Arc;
// SQLite
let = builder
.api_id
.api_hash
.session_backend
.connect.await?;
// In-memory (for tests)
builder
.api_id
.api_hash
.in_memory
.connect.await?;
๐ Transport & Networking
Transport kinds
use TransportKind;
builder
.transport // default โ lowest overhead
.transport // fixed-width framing
.transport // XOR-encrypted, resists DPI
SOCKS5 Proxy
use Socks5Config;
builder
.api_id
.api_hash
.socks5
.connect.await?;
DC Pool
layer-client maintains a connection pool across Telegram's DCs. When an API call is routed to a different DC (e.g. for media downloads), the pool opens a new connection and caches it. DC migration after a *_MIGRATE error is handled transparently โ no user code needed.
๐ฉ Feature Flags
| Feature | Default | Description |
|---|---|---|
sqlite-session |
โ | Enables SqliteBackend via rusqlite |
libsql-session |
โ | Enables LibSqlBackend via libsql (Turso-compatible) |
html |
โ | Built-in HTML โ entity parser |
html5ever |
โ | HTML parser backed by html5ever (spec-compliant; implies html) |
serde |
โ | Adds serde::Serialize / Deserialize on public types |
= { = "0.4.5", = ["sqlite-session", "html"] }
โ๏ธ Configuration Reference
Config
Retry Policies
// Auto-sleep on FLOOD_WAIT (default) โ sleeps for the duration Telegram specifies
retry_policy: new
// Never retry โ propagate all errors immediately
retry_policy: new
// Custom policy
;
โ ๏ธ Error Handling
use ;
match client.send_message.await
Common RPC errors: FLOOD_WAIT_X, USER_DEACTIVATED, AUTH_KEY_UNREGISTERED, PEER_ID_INVALID, USERNAME_NOT_OCCUPIED.
๐ง Raw API Escape Hatch
Any TL function can be invoked directly:
use functions;
// Call any function directly
let state = client.invoke.await?;
// Call on a specific DC (e.g. for media DCs)
let result = client.invoke_on_dc.await?;
๐ Shutdown
// Soft shutdown โ signals the background task to stop
let = builder
.api_id
.api_hash
.session
.connect.await?;
// ... use client ...
// Initiate a graceful disconnect
client.disconnect;
// Or hold `shutdown` and drop it when done
drop;
The signal_network_restored() method re-triggers an update catch-up after a network outage:
client.signal_network_restored;
๐ Part of the layer stack
layer-client โ you are here
โโโ layer-mtproto (session, DH, framing)
โโโ layer-tl-types (generated API types, TL Layer 224)
โโโ layer-crypto (AES-IGE, RSA, SHA, factorize)
๐ License
Licensed under either of, at your option:
- MIT License โ see LICENSE-MIT
- Apache License, Version 2.0 โ see LICENSE-APACHE
๐ค Author
Ankit Chaubey
github.com/ankit-chaubey ยท ankitchaubey.in ยท ankitchaubey.dev@gmail.com