Asutorufaのブログ

こんにちは

RustでTelegram BotをLambdaにデプロイする

投稿日 2025-08-07|更新日: 2025-08-07|カテゴリ Rust, Lambda, Telegram

Telegram BotにはサーバーとWebhookの二つの立ち上げる方法があります。Lambdaはサーバーレスだから、今回はWebhookで使用します。

最初はCargoで新たなプロジェクトを作ります。

cargo new telegram-bot

必要な依存を追加します。

crgo add aws_lambda_events base64 lambda_runtime serde_json serde teloxide-macros tokio teloxide cargo-lambda

zigをインストール

# macosbrew install zig# lambda cliでzigのインストール方法を出力してcargo lambda system --install-zig

Telegramのコマンドを宣言します

#[derive(BotCommands, PartialEq, Clone, Debug)]// いろんなパラメータに対応しています。公式ドキュメントをチェックしてください。#[command(    rename_rule = "lowercase",    description = "These commands are supported:")]pub enum Command {    #[command(description = "get current user id")]    UserID,}

Telegramの処理関数を定義します

pub async fn answer(    bot: teloxide::prelude::Bot,    msg: Message,    cmd: Command,) -> Result<(), RequestError> {    let reply = match cmd {        Command::UserID => format!("your id is: {}", from_user).to_string(),    }     // 返事を送信し    bot.send_message(msg.chat.id, v)        .reply_parameters(ReplyParameters::new(msg.id))        .parse_mode(teloxide::types::ParseMode::MarkdownV2)        .disable_link_preview(true)        .await?;     Ok(())}

Telegramのルートを定義します

ここはちょっと難しいかもしれません

  • Update::filter_message()は一般的なメッセージ
  • Update::filter_edited_message()は更新したメッセージ
  • 他の種類のメッセージはtrait.UpdateFilterExtにご確認ください。

filter_command::<Command>()はCommandによってメッセージをフィルターする。  
例えばfilter_commandを削除してdptree::entry().endpoint(answer)になったら、これはすべてのメッセージをマッチする。

pub fn handler() -> Handler<'static, Result<(), RequestError>, DpHandlerDescription> {    return dptree::entry()        .branch(            Update::filter_message()                .branch(dptree::entry().filter_command::<Command>().endpoint(answer)),        )        .branch(            Update::filter_edited_message()                .branch(dptree::entry().filter_command::<Command>().endpoint(answer)),        );}

Telegram Botサーバーなら次のコードで実行できます。Lambdaには他の方法を使います。

pub struct TErrorHandler {} impl ErrorHandler<RequestError> for TErrorHandler {    fn handle_error(self: std::sync::Arc<Self>, error: RequestError) -> BoxFuture<'static, ()> {        println!("error: {}", error);        Box::pin(async move {})    }} pub async fn run_bot() -> Dispatcher<Bot, RequestError, DefaultKey> {    let bot = Bot::from_env();     bot.set_my_commands(Command::bot_commands())        .send()        .await        .unwrap();     let handler = handler();      let dispatcher: Dispatcher<Bot, RequestError, DefaultKey> = Dispatcher::builder(bot, handler)        .enable_ctrlc_handler()        .error_handler(Arc::new(TErrorHandler {}))        .build();     return dispatcher;}

まずLambdaのエントリー関数を作ります。

#[derive(Serialize, Deserialize)]struct Response {    msg: String,} #[derive(Serialize, Deserialize)]struct LambdaRequest {} async fn handler(&self, event: LambdaEvent<Value>) -> Result<Response, lambda_runtime::Error> {        let (payload, _) = event.into_parts();        // Telegram WebhookはFunction Urlにアクセスするので、ここではLambdaFunctionUrlRequestを使います        if let Ok(v) = serde_json::from_value::<LambdaFunctionUrlRequest>(payload.clone()) {            return bot_handler(v).await;        // 他にはカスタマイズした構造体を使うこともできますので、自由に定義してください。        } else if let Ok(v) = serde_json::from_value::<LambdaRequest>(payload.clone()) {            return request_handler(v).await;        } else {            return Err(lambda_runtime::Error::from("Unknown request"));        }} async fn request_handler(    &self,    request: LambdaRequest,) -> Result<Response, lambda_runtime::Error> {    // TODO ...    return Ok(Response {        msg: "Send successful.".to_string(),    });}

Telegram Botのハンドラーを作ります。

async fn bot_handler(event: LambdaFunctionUrlRequest) -> Result<Response, lambda_runtime::Error> {    let bot = Bot::from_env();     let me = bot.get_me().await?;    println!("Bot: {}, {}", me.username.as_ref().unwrap(), me.id.0);     match event.raw_path.ok_or("Path is None")?.as_str() {        // Function UrlをTelegram BotのWebhookに設定し        "/tgbot/register" => {            // UrlのHostはHTTPリクエストのドメインです            let url = format!(                "https://{}/tgbot",                event                    .request_context                    .domain_name                    .ok_or("domain name is none")?            );             println!("Registering webhook: {}", url);             // Commandを設定する            let _ = bot.set_my_commands(Command::bot_commands()).await;            // Webhookを設定する            let _ = bot.set_webhook(url::Url::parse(&url)?).send().await?;             return Ok(Response {                msg: format!("register telegram bot to {} successful", url).to_string(),            });        }         // telegram Botのリクエストのhandler        "/tgbot" => {            let bytes = event.body.ok_or("body is none")?;             // Function UrlのBodyはbase64エンコードされたものです            let body = if event.is_base64_encoded {                general_purpose::STANDARD.decode(bytes)?            } else {                bytes.as_bytes().to_vec()            };             println!("body: {}", String::from_utf8_lossy(&body));             // UpdateはTelegram Botのリクストの構造体です, teloxide::types::Update            let update: Update = serde_json::from_slice(&body)?;            let handler = handler();            let dependencies = dptree::deps![me.clone(), bot.clone(), update];            // リクエスを処理する            let result = handler.dispatch(dependencies).await;             return match result {                ControlFlow::Break(Ok(())) => Ok(Response {                    msg: "Update was handled by bot.".to_string(),                }),                ControlFlow::Break(Err(e)) => Err(lambda_runtime::Error::from(e)),                ControlFlow::Continue(_) => Ok(Response {                    msg: "Update was not handled by bot.".to_string(),                }),            };        }        _ => {}    }     Err(lambda_runtime::Error::from(format!("404 NOT FOUND")))}

次はTelegram Bot Fatherで新たなBotを作成して、Tokenを取得してください。
Lambdaに新たな環境変数を追加します

TELOXIDE_TOKEN=<Telegram Bot Token>

ビルド

cargo lambda build --release --bin lambda

デプロイ

cargo lambda deploy --binary-name lambda hj-telegram-bot

Webhookを登録します

curl https://<function url>/tgbot/register

これで完成しました。
Telegram Botに/useridを送信してテストしましょう。

0 件のコメント

©2026Asutorufa