1 个不稳定版本

0.1.0 2022年10月17日

#13 in #mt-proto


用于 teleser

MIT 许可证

24KB
628

Teleser

基于grammers的Telegram MTProto机器人框架,支持使用电话号码和机器人令牌登录

创建机器人

首先

https://core.telegram.org/api/obtaining_api_id 获取api id

将teleser添加到依赖项

如果你的在中国大陆网络,添加代理功能是个好主意

teleser = { version = "0", features = ["proxy"] }

并查看机器人模板源代码

主要

  • 设置日志记录器
  • 使用tokio异步运行时运行异步main
fn main() -> Result<()> {
    init_tracing_subscriber();
    return runtime::Builder::new_multi_thread()
        .enable_all()
        .max_blocking_threads(30)
        .worker_threads(50)
        .build()
        .unwrap()
        .block_on(async_main());
}

日志记录器

tracing_subscriber设置日志级别,你需要将"teleser_template"修改为你的crate名称。

fn init_tracing_subscriber() {
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::fmt::layer()
                .with_target(true)
                .without_time(),
        )
        .with(
            tracing_subscriber::filter::Targets::new()
                .with_target("teleser", Level::DEBUG)
                .with_target("teleser_template", Level::DEBUG),
        )
        .init();
}

异步_main


async fn async_main() -> Result<()> {
    // Using `ClientBuilder` build a bot client
    let client = Arc::new(
        teleser::ClientBuilder::new()
            // read api id from env (on build)
            .with_api_id(env!("API_ID").parse()?)
            // read api hash from env (on build)
            .with_api_hash(env!("API_HASH").to_string())
            // auth
            .with_auth(Auth::AuthWithPhoneAndCode(Box::new(Input {}))
            // load session file on startup
            // save session to file teleser.session if login
            .with_session_store(Box::new(FileSessionStore{
                path: "teleser.session".to_string(),
            }))
            // modules
            .with_modules(vec![raw_plugin::module(), proc_plugin::module()])
            // connect to server via proxy url, like socks5://127.0.0.1:1080 (runtime)
            // please delete this code if you not add feature named proxy
            .with_init_params(match std::env::var("TELESER_PROXY") {
                Ok(url) => {
                    let mut ip = InitParams::default();
                    ip.proxy_url = Some(url);
                    Some(ip)
                }
                Err(_) => Some(InitParams::default()),
            })
            .build()?,
    );
    //////////////////////////////////////
    // can start some timer task like this
    let copy_client = client.clone();
    tokio::spawn(async move {
        let lock = copy_client.inner_client.lock().await;
        let ic = lock.clone();
        drop(lock);
        if let Some(_ic) = ic {
            // _ic.send_message();
        }
    });
    //////////////////////////////////////
    // run client
    teleser::run_client_and_reconnect(client).await?;
    /////////////////////////////////////
    Ok(())
}

输入

仅从控制台读取一行

pub struct Input {}

#[async_trait]
impl AuthWithPhoneAndCode for Input {
    async fn input_phone(&self) -> Result<String> {
        input("Input your phone number ( like +112345678 )")
    }

    async fn input_code(&self) -> Result<String> {
        input("Input your device or sms code ( like 12345 )")
    }

    async fn input_password(&self) -> Result<String> {
        input("Input your password")
    }
}

fn input(tips: &str) -> Result<String> {
    let mut s = String::new();
    print!("{tips}: ");
    let _ = stdout().flush();
    stdin().read_line(&mut s)?;
    if let Some('\n') = s.chars().next_back() {
        s.pop();
    }
    if let Some('\r') = s.chars().next_back() {
        s.pop();
    }
    Ok(s)
}

处理器

此示例具有处理器grammers Update::OnNewMessage。你可以使用以下处理器

new_message / message_edited / message_deleted / callback_query / inline_query / raw

但我无法在grammers上获取message_edited事件,只获得了raw。

use crate::Result;
use teleser::re_exports::grammers_client::types::Message;
use teleser::{new_message, Handler, InnerClient};

#[new_message]
async fn proc_new_message(_: &mut InnerClient, message: &Message) -> Result<bool> {
    println!("PROC : A NEW MESSAGE : {}", message.text());
    Ok(false)
}

pub(crate) fn module() -> Module {
    Module {
        id: "proc_new_message".to_owned(),
        name: "proc_new_message".to_owned(),
        handlers: vec![Handler {
            id: "proc_new_message".to_owned(),
            process: proc_new_message {}.into(),
        }],
    }
}

解析到处理器

pub(crate) fn module() -> Module {
    Module {
        id: "proc_new_message".to_owned(),
        name: "proc_new_message".to_owned(),
        handlers: vec![proc_new_message {}.into()],
    }
}

解析到处理器

pub(crate) fn module() -> Module {
    Module {
        id: "proc_new_message".to_owned(),
        name: "proc_new_message".to_owned(),
        handlers: proc_new_message {}.into(),
    }
}

解析到模块

pub(crate) fn module() -> Module {
    proc_new_message {}.into()
}

手动编写处理器

use teleser::re_exports::async_trait::async_trait;
use teleser::re_exports::grammers_client::types::Message;
use teleser::{Handler, InnerClient, NewMessageProcess, Process};

pub(crate) struct RawPlugin {}

#[async_trait]
impl NewMessageProcess for RawPlugin {
    async fn handle(&self, _: &mut InnerClient, event: &Message) -> crate::Result<bool> {
        println!("RAW : A NEW MESSAGE : {}", event.text());
        Ok(false)
    }
}

pub(crate) fn module() -> Module {
    Module {
        id: "RawPlugin".to_owned(),
        name: "RawPlugin".to_owned(),
        handlers: vec![Handler {
            id: "RawPlugin".to_owned(),
            process: Process::NewMessageProcess(Box::new(RawPlugin {})),
        }],
    }
}

依赖项

~1.5MB
~41K SLoC