From ea5b2df25158b4e8cfb6f0fc0e97a8c653b9dd68 Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Wed, 18 Aug 2021 21:54:32 -0700 Subject: [PATCH 1/6] Include inline bot example --- examples/inline_bot/Cargo.toml | 14 +++++++ examples/inline_bot/src/main.rs | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 examples/inline_bot/Cargo.toml create mode 100644 examples/inline_bot/src/main.rs diff --git a/examples/inline_bot/Cargo.toml b/examples/inline_bot/Cargo.toml new file mode 100644 index 00000000..40e7281d --- /dev/null +++ b/examples/inline_bot/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "inline_bot" +version = "0.1.0" +authors = ["Colin Diener "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +teloxide = { path = "../../", features = ["macros", "auto-send"] } +log = "0.4.8" +pretty_env_logger = "0.4.0" +tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] } +tokio-stream = "0.1.3" diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs new file mode 100644 index 00000000..fc919b3c --- /dev/null +++ b/examples/inline_bot/src/main.rs @@ -0,0 +1,73 @@ +use teloxide::{Bot, payloads::AnswerInlineQuery, prelude::*, types::{InlineQueryResult, InlineQueryResultArticle, InputMessageContent, InputMessageContentText}}; +use tokio_stream::wrappers::UnboundedReceiverStream; + +#[tokio::main] +async fn main() { + run().await; +} + +async fn run() { + let bot = Bot::from_env(); + // Create a new dispatcher to handle incoming messages + let dp = Dispatcher::new(bot); + dp.inline_queries_handler(|rx: DispatcherHandlerRx| { + UnboundedReceiverStream::new(rx).for_each_concurrent(None, |msg| async move { + // First, create your actual response + let google_search = InlineQueryResultArticle::new( + // Each item needs a unique ID, as well as the response container for the items. + // These can be whatever, as long as they don't conflict. + "01".to_string(), + // What the user will actually see + "Google Search", + // What message will send when clicked/tapped + InputMessageContent::Text(InputMessageContentText::new(format!( + "https://www.google.com/search?q={}", + msg.update.query, + ))), + ); + // You can also construct them from the struct itself, if you want a little more control. + // Please refer to the documentation for more detailed information about each field. + // https://docs.rs/teloxide/0.5.1/teloxide/types/struct.InlineQueryResultArticle.html + let ddg_search = InlineQueryResultArticle { + id: "02".to_string(), // again, anything -- as long as it's unique in this context + title: "DuckDuckGo Search".to_string(), + input_message_content: InputMessageContent::Text(InputMessageContentText::new( + format!("https://duckduckgo.com/?q={}", msg.update.query.to_string()), + )), + reply_markup: None, + url: Some("https://duckduckgo.com/about".to_string()), // Note: This is the url that will open if they click the thumbnail + hide_url: None, + description: Some("DuckDuckGo Search".to_string()), + thumb_url: Some( + "https://duckduckgo.com/assets/logo_header.v108.png".to_string(), + ), + thumb_width: Some(64), + thumb_height: Some(64), + }; + + // Now put those responses into a "Result" + // https://docs.rs/teloxide/0.5.1/teloxide/payloads/struct.AnswerInlineQuery.html + let all_results = AnswerInlineQuery { + inline_query_id: "03".to_string(), // again, anything -- as long as it's unique in this context + results: vec![InlineQueryResult::Article(google_search), InlineQueryResult::Article(ddg_search)], + cache_time: None, + is_personal: None, + next_offset: None, + switch_pm_text: None, + switch_pm_parameter: None, + }; + + // Send it off! One thing to note -- the ID we use here must be of the message we're responding to. + let response = msg + .requester + .answer_inline_query(msg.update.id.to_string(), all_results.results) + .send() + .await; + if response.is_err() { + dbg!(response); + } + }) + }) + .dispatch() + .await; +} From 93c8e00086030aca6426fa57ea815edce7e4d3c9 Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Thu, 19 Aug 2021 10:56:39 -0700 Subject: [PATCH 2/6] Remove unused dispatcher variable, Bot to AutoSend --- examples/inline_bot/src/main.rs | 130 +++++++++++++++++--------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs index fc919b3c..ab15b82c 100644 --- a/examples/inline_bot/src/main.rs +++ b/examples/inline_bot/src/main.rs @@ -1,4 +1,11 @@ -use teloxide::{Bot, payloads::AnswerInlineQuery, prelude::*, types::{InlineQueryResult, InlineQueryResultArticle, InputMessageContent, InputMessageContentText}}; +use teloxide::{ + payloads::AnswerInlineQuery, + prelude::*, + types::{ + InlineQueryResult, InlineQueryResultArticle, InputMessageContent, InputMessageContentText, + }, + Bot, +}; use tokio_stream::wrappers::UnboundedReceiverStream; #[tokio::main] @@ -7,67 +14,70 @@ async fn main() { } async fn run() { - let bot = Bot::from_env(); + let bot = Bot::from_env().auto_send(); // Create a new dispatcher to handle incoming messages - let dp = Dispatcher::new(bot); - dp.inline_queries_handler(|rx: DispatcherHandlerRx| { - UnboundedReceiverStream::new(rx).for_each_concurrent(None, |msg| async move { - // First, create your actual response - let google_search = InlineQueryResultArticle::new( - // Each item needs a unique ID, as well as the response container for the items. - // These can be whatever, as long as they don't conflict. - "01".to_string(), - // What the user will actually see - "Google Search", - // What message will send when clicked/tapped - InputMessageContent::Text(InputMessageContentText::new(format!( - "https://www.google.com/search?q={}", - msg.update.query, - ))), - ); - // You can also construct them from the struct itself, if you want a little more control. - // Please refer to the documentation for more detailed information about each field. - // https://docs.rs/teloxide/0.5.1/teloxide/types/struct.InlineQueryResultArticle.html - let ddg_search = InlineQueryResultArticle { - id: "02".to_string(), // again, anything -- as long as it's unique in this context - title: "DuckDuckGo Search".to_string(), - input_message_content: InputMessageContent::Text(InputMessageContentText::new( - format!("https://duckduckgo.com/?q={}", msg.update.query.to_string()), - )), - reply_markup: None, - url: Some("https://duckduckgo.com/about".to_string()), // Note: This is the url that will open if they click the thumbnail - hide_url: None, - description: Some("DuckDuckGo Search".to_string()), - thumb_url: Some( - "https://duckduckgo.com/assets/logo_header.v108.png".to_string(), - ), - thumb_width: Some(64), - thumb_height: Some(64), - }; + Dispatcher::new(bot) + .inline_queries_handler(|rx: DispatcherHandlerRx, InlineQuery>| { + UnboundedReceiverStream::new(rx).for_each_concurrent(None, |msg| async move { + // First, create your actual response + let google_search = InlineQueryResultArticle::new( + // Each item needs a unique ID, as well as the response container for the items. + // These can be whatever, as long as they don't conflict. + "01".to_string(), + // What the user will actually see + "Google Search", + // What message will send when clicked/tapped + InputMessageContent::Text(InputMessageContentText::new(format!( + "https://www.google.com/search?q={}", + msg.update.query, + ))), + ); + // You can also construct them from the struct itself, if you want a little more control. + // Please refer to the documentation for more detailed information about each field. + // https://docs.rs/teloxide/0.5.1/teloxide/types/struct.InlineQueryResultArticle.html + let ddg_search = InlineQueryResultArticle { + id: "02".to_string(), // again, anything -- as long as it's unique in this context + title: "DuckDuckGo Search".to_string(), + input_message_content: InputMessageContent::Text(InputMessageContentText::new( + format!("https://duckduckgo.com/?q={}", msg.update.query.to_string()), + )), + reply_markup: None, + url: Some("https://duckduckgo.com/about".to_string()), // Note: This is the url that will open if they click the thumbnail + hide_url: None, + description: Some("DuckDuckGo Search".to_string()), + thumb_url: Some( + "https://duckduckgo.com/assets/logo_header.v108.png".to_string(), + ), + thumb_width: Some(64), + thumb_height: Some(64), + }; - // Now put those responses into a "Result" - // https://docs.rs/teloxide/0.5.1/teloxide/payloads/struct.AnswerInlineQuery.html - let all_results = AnswerInlineQuery { - inline_query_id: "03".to_string(), // again, anything -- as long as it's unique in this context - results: vec![InlineQueryResult::Article(google_search), InlineQueryResult::Article(ddg_search)], - cache_time: None, - is_personal: None, - next_offset: None, - switch_pm_text: None, - switch_pm_parameter: None, - }; + // Now put those responses into a "Result" + // https://docs.rs/teloxide/0.5.1/teloxide/payloads/struct.AnswerInlineQuery.html + let all_results = AnswerInlineQuery { + inline_query_id: "03".to_string(), // again, anything -- as long as it's unique in this context + results: vec![ + InlineQueryResult::Article(google_search), + InlineQueryResult::Article(ddg_search), + ], + cache_time: None, + is_personal: None, + next_offset: None, + switch_pm_text: None, + switch_pm_parameter: None, + }; - // Send it off! One thing to note -- the ID we use here must be of the message we're responding to. - let response = msg - .requester - .answer_inline_query(msg.update.id.to_string(), all_results.results) - .send() - .await; - if response.is_err() { - dbg!(response); - } + // Send it off! One thing to note -- the ID we use here must be of the message we're responding to. + let response = msg + .requester + .answer_inline_query(msg.update.id.to_string(), all_results.results) + .send() + .await; + if response.is_err() { + dbg!(response); + } + }) }) - }) - .dispatch() - .await; + .dispatch() + .await; } From f6ad066087bac65d60f4ee58cae45193f9533bc8 Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Thu, 19 Aug 2021 11:00:58 -0700 Subject: [PATCH 3/6] Clarify verbage from message to query --- examples/inline_bot/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs index ab15b82c..d8437c01 100644 --- a/examples/inline_bot/src/main.rs +++ b/examples/inline_bot/src/main.rs @@ -15,10 +15,10 @@ async fn main() { async fn run() { let bot = Bot::from_env().auto_send(); - // Create a new dispatcher to handle incoming messages + // Create a new dispatcher to handle incoming queries Dispatcher::new(bot) .inline_queries_handler(|rx: DispatcherHandlerRx, InlineQuery>| { - UnboundedReceiverStream::new(rx).for_each_concurrent(None, |msg| async move { + UnboundedReceiverStream::new(rx).for_each_concurrent(None, |query| async move { // First, create your actual response let google_search = InlineQueryResultArticle::new( // Each item needs a unique ID, as well as the response container for the items. @@ -26,10 +26,10 @@ async fn run() { "01".to_string(), // What the user will actually see "Google Search", - // What message will send when clicked/tapped + // What message will be sent when clicked/tapped InputMessageContent::Text(InputMessageContentText::new(format!( "https://www.google.com/search?q={}", - msg.update.query, + query.update.query, ))), ); // You can also construct them from the struct itself, if you want a little more control. @@ -39,7 +39,7 @@ async fn run() { id: "02".to_string(), // again, anything -- as long as it's unique in this context title: "DuckDuckGo Search".to_string(), input_message_content: InputMessageContent::Text(InputMessageContentText::new( - format!("https://duckduckgo.com/?q={}", msg.update.query.to_string()), + format!("https://duckduckgo.com/?q={}", query.update.query.to_string()), )), reply_markup: None, url: Some("https://duckduckgo.com/about".to_string()), // Note: This is the url that will open if they click the thumbnail @@ -67,10 +67,10 @@ async fn run() { switch_pm_parameter: None, }; - // Send it off! One thing to note -- the ID we use here must be of the message we're responding to. - let response = msg + // Send it off! One thing to note -- the ID we use here must be of the query we're responding to. + let response = query .requester - .answer_inline_query(msg.update.id.to_string(), all_results.results) + .answer_inline_query(query.update.id.to_string(), all_results.results) .send() .await; if response.is_err() { From 43f8e73973b4300740c3d61c3c8f4e59f43b22c4 Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Thu, 19 Aug 2021 11:03:53 -0700 Subject: [PATCH 4/6] Remove superfluous struct --- examples/inline_bot/src/main.rs | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs index d8437c01..0a6b1d49 100644 --- a/examples/inline_bot/src/main.rs +++ b/examples/inline_bot/src/main.rs @@ -1,5 +1,4 @@ use teloxide::{ - payloads::AnswerInlineQuery, prelude::*, types::{ InlineQueryResult, InlineQueryResultArticle, InputMessageContent, InputMessageContentText, @@ -52,27 +51,13 @@ async fn run() { thumb_height: Some(64), }; - // Now put those responses into a "Result" - // https://docs.rs/teloxide/0.5.1/teloxide/payloads/struct.AnswerInlineQuery.html - let all_results = AnswerInlineQuery { - inline_query_id: "03".to_string(), // again, anything -- as long as it's unique in this context - results: vec![ - InlineQueryResult::Article(google_search), - InlineQueryResult::Article(ddg_search), - ], - cache_time: None, - is_personal: None, - next_offset: None, - switch_pm_text: None, - switch_pm_parameter: None, - }; - + let results = vec![ + InlineQueryResult::Article(google_search), + InlineQueryResult::Article(ddg_search), + ]; // Send it off! One thing to note -- the ID we use here must be of the query we're responding to. - let response = query - .requester - .answer_inline_query(query.update.id.to_string(), all_results.results) - .send() - .await; + let response = + query.requester.answer_inline_query(&query.update.id, results).send().await; if response.is_err() { dbg!(response); } From 1bd47314bee1e6812f066e026bd0a069f382d06b Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Thu, 19 Aug 2021 11:05:56 -0700 Subject: [PATCH 5/6] Remove dbg! macro in favour of log::error! macro --- examples/inline_bot/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs index 0a6b1d49..cd542eff 100644 --- a/examples/inline_bot/src/main.rs +++ b/examples/inline_bot/src/main.rs @@ -58,8 +58,8 @@ async fn run() { // Send it off! One thing to note -- the ID we use here must be of the query we're responding to. let response = query.requester.answer_inline_query(&query.update.id, results).send().await; - if response.is_err() { - dbg!(response); + if let Err(err) = response { + log::error!("Error in handler: {:?}", err); } }) }) From f5a7187295969237d30ce7876828326e6f685b00 Mon Sep 17 00:00:00 2001 From: Colin Diener Date: Thu, 19 Aug 2021 11:23:57 -0700 Subject: [PATCH 6/6] Apply builder-pattern to second example result --- examples/inline_bot/src/main.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/examples/inline_bot/src/main.rs b/examples/inline_bot/src/main.rs index cd542eff..927679e8 100644 --- a/examples/inline_bot/src/main.rs +++ b/examples/inline_bot/src/main.rs @@ -31,30 +31,27 @@ async fn run() { query.update.query, ))), ); - // You can also construct them from the struct itself, if you want a little more control. + // While constructing them from the struct itself is possible, it is preferred to use + // the builder pattern if you wish to add more information to your result. // Please refer to the documentation for more detailed information about each field. // https://docs.rs/teloxide/0.5.1/teloxide/types/struct.InlineQueryResultArticle.html - let ddg_search = InlineQueryResultArticle { - id: "02".to_string(), // again, anything -- as long as it's unique in this context - title: "DuckDuckGo Search".to_string(), - input_message_content: InputMessageContent::Text(InputMessageContentText::new( - format!("https://duckduckgo.com/?q={}", query.update.query.to_string()), - )), - reply_markup: None, - url: Some("https://duckduckgo.com/about".to_string()), // Note: This is the url that will open if they click the thumbnail - hide_url: None, - description: Some("DuckDuckGo Search".to_string()), - thumb_url: Some( - "https://duckduckgo.com/assets/logo_header.v108.png".to_string(), - ), - thumb_width: Some(64), - thumb_height: Some(64), - }; + let ddg_search = InlineQueryResultArticle::new( + "02".to_string(), + "DuckDuckGo Search".to_string(), + InputMessageContent::Text(InputMessageContentText::new(format!( + "https://duckduckgo.com/?q={}", + query.update.query.to_string() + ))), + ) + .description("DuckDuckGo Search") + .thumb_url("https://duckduckgo.com/assets/logo_header.v108.png") + .url("https://duckduckgo.com/about"); // Note: This is the url that will open if they click the thumbnail let results = vec![ InlineQueryResult::Article(google_search), InlineQueryResult::Article(ddg_search), ]; + // Send it off! One thing to note -- the ID we use here must be of the query we're responding to. let response = query.requester.answer_inline_query(&query.update.id, results).send().await;