Skip to content

ankit-chaubey/layer

layer

Async Rust library for the Telegram MTProto protocol. Developed by Ankit Chaubey.

Crates.io docs.rs License TL Layer Telegram

Note

This project is no longer maintained or supported. Its original purpose for personal SDK/APK experimentation and learning has been fulfilled.

Instead, please use ferogram, which will receive future development and updates. Development may proceed at a slower pace.


Crates

Most users only need layer-client.

Crate Description
layer-client High-level async client: auth, messaging, media, bots
layer-tl-types Layer 224 types, functions, enums (2,329 definitions)
layer-mtproto MTProto session, DH exchange, framing, transports
layer-crypto AES-IGE, RSA, SHA, Diffie-Hellman, auth key derivation
layer-tl-gen Build-time code generator from the TL AST
layer-tl-parser Parses .tl schema into an AST

Installation

[dependencies]
layer-client = "0.5.0"
tokio        = { version = "1", features = ["full"] }

Get your api_id and api_hash from my.telegram.org.

Optional features:

layer-client = { version = "0.5.0", features = ["sqlite-session"] }  # SQLite session
layer-client = { version = "0.5.0", features = ["libsql-session"] }  # libsql / Turso
layer-client = { version = "0.5.0", features = ["html"] }            # HTML parser
layer-client = { version = "0.5.0", features = ["html5ever"] }       # html5ever parser

layer-client re-exports layer_tl_types as layer_client::tl.


Quick Start - Bot

use layer_client::{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(Update::NewMessage(msg)) = stream.next().await {
        if !msg.outgoing() {
            if let Some(peer) = msg.peer_id() {
                client.send_message_to_peer(peer.clone(), msg.text().unwrap_or("")).await?;
            }
        }
    }
    Ok(())
}

Quick Start - User Account

use layer_client::{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!("Welcome, {name}!"),
            Err(SignInError::PasswordRequired(t)) => {
                client.check_password(*t, "my_2fa_password").await?;
            }
            Err(e) => return Err(e.into()),
        }
        client.save_session().await?;
    }

    client.send_message("me", "Hello from layer!").await?;
    Ok(())
}

Session Backends

Backend Flag Notes
BinaryFileBackend default Single-process bots, scripts
InMemoryBackend default Tests, ephemeral tasks
StringSessionBackend default Serverless, env-var storage
SqliteBackend sqlite-session Multi-session local apps
LibSqlBackend libsql-session Turso / distributed storage
Custom - Implement SessionBackend
let s = client.export_session_string().await?;
let (client, _) = Client::with_string_session(&s).await?;

Raw API

Every Layer method is accessible via client.invoke():

use layer_client::tl;

let req = tl::functions::bots::SetBotCommands {
    scope: tl::enums::BotCommandScope::Default(tl::types::BotCommandScopeDefault {}),
    lang_code: "en".into(),
    commands: vec![
        tl::enums::BotCommand::BotCommand(tl::types::BotCommand {
            command:     "start".into(),
            description: "Start the bot".into(),
        }),
    ],
};
client.invoke(&req).await?;

// Target a specific DC
client.invoke_on_dc(&req, 2).await?;

Tests

cargo test --workspace
cargo test --workspace --all-features

Integration tests in layer-client/tests/integration.rs use InMemoryBackend and don't need real credentials.


Community


Contributing

Read CONTRIBUTING.md before opening a PR. Run cargo test --workspace and cargo clippy --workspace locally. Security issues: see SECURITY.md.


Author

Developed by Ankit Chaubey out of curiosity to explore.

Layer is developed as part of exploration, learning, and experimentation with the Telegram MTProto protocol. Use it at your own risk. Its future and stability are not yet guaranteed.


Acknowledgements

Parts of this library are derived from grammers by Lonami, licensed under MIT or Apache-2.0.

AI was used to reduce manual effort on docs, boilerplate, and large rewrites where it made sense. Core library code is written by the author.


License

Licensed under either of, at your option:

Unless you explicitly state otherwise, any contribution submitted for inclusion shall be dual-licensed as above, without any additional terms or conditions.


Telegram Terms of Service

Ensure your usage complies with Telegram's Terms of Service and API Terms of Service. Misuse of the Telegram API, including spam, mass scraping, or automation of normal user accounts, may result in account limitations or permanent bans.

About

Experimental Rust primitives for working with Telegram MTProto layers and TL schemas. This crate is in very early development. APIs are unstable and subject to change.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages