diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f2e5d1..daaa61c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed + - Updated `teloxide-core` from version `0.4.5` to version [`0.5.0`](https://github.com/teloxide/teloxide-core/releases/tag/v0.5.0) [**BC**] - Rename `dispatching2` => `dispatching` [**BC**]. - Rename `prelude2` => `prelude` [**BC**]. - Move `update_listeners`, `stop_token`, `IdleShutdownError`, and `ShutdownToken` from the old `dispatching` to the new `dispatching` (previously `dispatching2`). diff --git a/Cargo.toml b/Cargo.toml index 91225a17..013f97bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ full = [ ] [dependencies] -teloxide-core = { version = "0.4", default-features = false } +teloxide-core = { version = "0.5", default-features = false } teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros.git", rev = "dfba097c7146ba6244a36001d703e04b771baa05", optional = true } serde_json = "1.0" diff --git a/examples/dispatching_features.rs b/examples/dispatching_features.rs index beda128c..fb36a96a 100644 --- a/examples/dispatching_features.rs +++ b/examples/dispatching_features.rs @@ -5,7 +5,7 @@ use rand::Rng; use teloxide::{ prelude::*, - types::{Dice, Update}, + types::{Dice, Update, UserId}, utils::command::BotCommands, }; @@ -17,7 +17,7 @@ async fn main() { let bot = Bot::from_env().auto_send(); let parameters = ConfigParameters { - bot_maintainer: 268486177, // Paste your ID to run this bot. + bot_maintainer: UserId(0), // Paste your ID to run this bot. maintainer_username: None, }; @@ -95,7 +95,7 @@ async fn main() { #[derive(Clone)] struct ConfigParameters { - bot_maintainer: i64, + bot_maintainer: UserId, maintainer_username: Option<String>, } diff --git a/src/dispatching/dialogue/get_chat_id.rs b/src/dispatching/dialogue/get_chat_id.rs index eb2a1bf1..d84d73fd 100644 --- a/src/dispatching/dialogue/get_chat_id.rs +++ b/src/dispatching/dialogue/get_chat_id.rs @@ -1,20 +1,20 @@ use crate::types::CallbackQuery; -use teloxide_core::types::Message; +use teloxide_core::types::{ChatId, Message}; /// Something that may has a chat ID. pub trait GetChatId { #[must_use] - fn chat_id(&self) -> Option<i64>; + fn chat_id(&self) -> Option<ChatId>; } impl GetChatId for Message { - fn chat_id(&self) -> Option<i64> { + fn chat_id(&self) -> Option<ChatId> { Some(self.chat.id) } } impl GetChatId for CallbackQuery { - fn chat_id(&self) -> Option<i64> { + fn chat_id(&self) -> Option<ChatId> { self.message.as_ref().map(|mes| mes.chat.id) } } diff --git a/src/dispatching/dialogue/mod.rs b/src/dispatching/dialogue/mod.rs index 33d6f3ad..5f9e27f4 100644 --- a/src/dispatching/dialogue/mod.rs +++ b/src/dispatching/dialogue/mod.rs @@ -85,6 +85,7 @@ pub use crate::dispatching::dialogue::{SqliteStorage, SqliteStorageError}; pub use get_chat_id::GetChatId; pub use storage::*; +use teloxide_core::types::ChatId; use std::{marker::PhantomData, sync::Arc}; @@ -98,7 +99,7 @@ where S: ?Sized, { storage: Arc<S>, - chat_id: i64, + chat_id: ChatId, _phantom: PhantomData<D>, } @@ -121,13 +122,13 @@ where /// Constructs a new dialogue with `storage` (where dialogues are stored) /// and `chat_id` of a current dialogue. #[must_use] - pub fn new(storage: Arc<S>, chat_id: i64) -> Self { + pub fn new(storage: Arc<S>, chat_id: ChatId) -> Self { Self { storage, chat_id, _phantom: PhantomData } } /// Returns a chat ID associated with this dialogue. #[must_use] - pub fn chat_id(&self) -> i64 { + pub fn chat_id(&self) -> ChatId { self.chat_id } diff --git a/src/dispatching/dialogue/storage/in_mem_storage.rs b/src/dispatching/dialogue/storage/in_mem_storage.rs index d26a21eb..5085b5b4 100644 --- a/src/dispatching/dialogue/storage/in_mem_storage.rs +++ b/src/dispatching/dialogue/storage/in_mem_storage.rs @@ -1,6 +1,7 @@ use super::Storage; use futures::future::BoxFuture; use std::{collections::HashMap, sync::Arc}; +use teloxide_core::types::ChatId; use thiserror::Error; use tokio::sync::Mutex; @@ -20,7 +21,7 @@ pub enum InMemStorageError { /// [`super::SqliteStorage`] or implement your own. #[derive(Debug)] pub struct InMemStorage<D> { - map: Mutex<HashMap<i64, D>>, + map: Mutex<HashMap<ChatId, D>>, } impl<S> InMemStorage<S> { @@ -37,7 +38,10 @@ where { type Error = InMemStorageError; - fn remove_dialogue(self: Arc<Self>, chat_id: i64) -> BoxFuture<'static, Result<(), Self::Error>> + fn remove_dialogue( + self: Arc<Self>, + chat_id: ChatId, + ) -> BoxFuture<'static, Result<(), Self::Error>> where D: Send + 'static, { @@ -52,7 +56,7 @@ where fn update_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> where @@ -66,7 +70,7 @@ where fn get_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>> { Box::pin(async move { Ok(self.map.lock().await.get(&chat_id).map(ToOwned::to_owned)) }) } diff --git a/src/dispatching/dialogue/storage/mod.rs b/src/dispatching/dialogue/storage/mod.rs index 600cf988..b78cd72e 100644 --- a/src/dispatching/dialogue/storage/mod.rs +++ b/src/dispatching/dialogue/storage/mod.rs @@ -10,6 +10,7 @@ mod redis_storage; mod sqlite_storage; use futures::future::BoxFuture; +use teloxide_core::types::ChatId; pub use self::{ in_mem_storage::{InMemStorage, InMemStorageError}, @@ -55,7 +56,7 @@ pub trait Storage<D> { #[must_use = "Futures are lazy and do nothing unless polled with .await"] fn remove_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<(), Self::Error>> where D: Send + 'static; @@ -64,7 +65,7 @@ pub trait Storage<D> { #[must_use = "Futures are lazy and do nothing unless polled with .await"] fn update_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> where @@ -74,7 +75,7 @@ pub trait Storage<D> { #[must_use = "Futures are lazy and do nothing unless polled with .await"] fn get_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>>; /// Erases [`Self::Error`] to [`std::error::Error`]. @@ -97,7 +98,10 @@ where { type Error = Box<dyn std::error::Error + Send + Sync>; - fn remove_dialogue(self: Arc<Self>, chat_id: i64) -> BoxFuture<'static, Result<(), Self::Error>> + fn remove_dialogue( + self: Arc<Self>, + chat_id: ChatId, + ) -> BoxFuture<'static, Result<(), Self::Error>> where D: Send + 'static, { @@ -108,7 +112,7 @@ where fn update_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> where @@ -121,7 +125,7 @@ where fn get_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>> { Box::pin( async move { Arc::clone(&self.0).get_dialogue(chat_id).await.map_err(|e| e.into()) }, @@ -135,7 +139,7 @@ mod tests { #[tokio::test] async fn test_erased() { - let chat_id = 123; + let chat_id = ChatId(123); let erased = InMemStorage::new().erase(); Arc::clone(&erased).update_dialogue(chat_id, 1).await.unwrap(); diff --git a/src/dispatching/dialogue/storage/redis_storage.rs b/src/dispatching/dialogue/storage/redis_storage.rs index f3889acc..de9294d8 100644 --- a/src/dispatching/dialogue/storage/redis_storage.rs +++ b/src/dispatching/dialogue/storage/redis_storage.rs @@ -8,6 +8,7 @@ use std::{ ops::DerefMut, sync::Arc, }; +use teloxide_core::types::ChatId; use thiserror::Error; use tokio::sync::Mutex; @@ -56,7 +57,7 @@ where fn remove_dialogue( self: Arc<Self>, - chat_id: i64, + ChatId(chat_id): ChatId, ) -> BoxFuture<'static, Result<(), Self::Error>> { Box::pin(async move { let deleted_rows_count = redis::pipe() @@ -82,7 +83,7 @@ where fn update_dialogue( self: Arc<Self>, - chat_id: i64, + ChatId(chat_id): ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> { Box::pin(async move { @@ -95,7 +96,7 @@ where fn get_dialogue( self: Arc<Self>, - chat_id: i64, + ChatId(chat_id): ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>> { Box::pin(async move { self.conn diff --git a/src/dispatching/dialogue/storage/sqlite_storage.rs b/src/dispatching/dialogue/storage/sqlite_storage.rs index a562b5e5..982fefc1 100644 --- a/src/dispatching/dialogue/storage/sqlite_storage.rs +++ b/src/dispatching/dialogue/storage/sqlite_storage.rs @@ -8,6 +8,7 @@ use std::{ str, sync::Arc, }; +use teloxide_core::types::ChatId; use thiserror::Error; /// A persistent dialogue storage based on [SQLite](https://www.sqlite.org/). @@ -66,7 +67,7 @@ where /// Returns [`sqlx::Error::RowNotFound`] if a dialogue does not exist. fn remove_dialogue( self: Arc<Self>, - chat_id: i64, + ChatId(chat_id): ChatId, ) -> BoxFuture<'static, Result<(), Self::Error>> { Box::pin(async move { let deleted_rows_count = @@ -86,7 +87,7 @@ where fn update_dialogue( self: Arc<Self>, - chat_id: i64, + ChatId(chat_id): ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> { Box::pin(async move { @@ -112,7 +113,7 @@ where fn get_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>> { Box::pin(async move { get_dialogue(&self.pool, chat_id) @@ -123,7 +124,10 @@ where } } -async fn get_dialogue(pool: &SqlitePool, chat_id: i64) -> Result<Option<Vec<u8>>, sqlx::Error> { +async fn get_dialogue( + pool: &SqlitePool, + ChatId(chat_id): ChatId, +) -> Result<Option<Vec<u8>>, sqlx::Error> { #[derive(sqlx::FromRow)] struct DialogueDbRow { dialogue: Vec<u8>, diff --git a/src/dispatching/dialogue/storage/trace_storage.rs b/src/dispatching/dialogue/storage/trace_storage.rs index f4e22d8e..33571194 100644 --- a/src/dispatching/dialogue/storage/trace_storage.rs +++ b/src/dispatching/dialogue/storage/trace_storage.rs @@ -5,6 +5,7 @@ use std::{ }; use futures::future::BoxFuture; +use teloxide_core::types::ChatId; use crate::dispatching::dialogue::Storage; @@ -34,7 +35,10 @@ where { type Error = <S as Storage<D>>::Error; - fn remove_dialogue(self: Arc<Self>, chat_id: i64) -> BoxFuture<'static, Result<(), Self::Error>> + fn remove_dialogue( + self: Arc<Self>, + chat_id: ChatId, + ) -> BoxFuture<'static, Result<(), Self::Error>> where D: Send + 'static, { @@ -44,7 +48,7 @@ where fn update_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, dialogue: D, ) -> BoxFuture<'static, Result<(), Self::Error>> where @@ -60,7 +64,7 @@ where fn get_dialogue( self: Arc<Self>, - chat_id: i64, + chat_id: ChatId, ) -> BoxFuture<'static, Result<Option<D>, Self::Error>> { log::trace!("Requested a dialogue #{}", chat_id); <S as Storage<D>>::get_dialogue(self.inner.clone(), chat_id) diff --git a/src/dispatching/dispatcher.rs b/src/dispatching/dispatcher.rs index fd194430..c6f14616 100644 --- a/src/dispatching/dispatcher.rs +++ b/src/dispatching/dispatcher.rs @@ -16,7 +16,10 @@ use std::{ ops::{ControlFlow, Deref}, sync::Arc, }; -use teloxide_core::{requests::Request, types::UpdateKind}; +use teloxide_core::{ + requests::Request, + types::{ChatId, UpdateKind}, +}; use tokio::time::timeout; use tokio_stream::wrappers::ReceiverStream; @@ -102,7 +105,7 @@ pub struct Dispatcher<R, Err> { default_handler: DefaultHandler, // Tokio TX channel parts associated with chat IDs that consume updates sequentially. - workers: HashMap<i64, Worker>, + workers: HashMap<ChatId, Worker>, // The default TX part that consume updates concurrently. default_worker: Option<Worker>, diff --git a/src/utils/html.rs b/src/utils/html.rs index d61c84c2..11ae475d 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -93,6 +93,8 @@ pub fn user_mention_or_link(user: &User) -> String { #[cfg(test)] mod tests { + use teloxide_core::types::UserId; + use super::*; #[test] @@ -183,7 +185,7 @@ mod tests { #[test] fn user_mention_link() { let user_with_username = User { - id: 0, + id: UserId(0), is_bot: false, first_name: "".to_string(), last_name: None, @@ -192,7 +194,7 @@ mod tests { }; assert_eq!(user_mention_or_link(&user_with_username), "@abcd"); let user_without_username = User { - id: 123_456_789, + id: UserId(123_456_789), is_bot: false, first_name: "Name".to_string(), last_name: None, diff --git a/src/utils/markdown.rs b/src/utils/markdown.rs index 6ee5f451..9b120d6a 100644 --- a/src/utils/markdown.rs +++ b/src/utils/markdown.rs @@ -131,7 +131,7 @@ pub fn user_mention_or_link(user: &User) -> String { #[cfg(test)] mod tests { use super::*; - use teloxide_core::types::User; + use teloxide_core::types::{User, UserId}; #[test] fn test_bold() { @@ -234,7 +234,7 @@ mod tests { #[test] fn user_mention_link() { let user_with_username = User { - id: 0, + id: UserId(0), is_bot: false, first_name: "".to_string(), last_name: None, @@ -243,7 +243,7 @@ mod tests { }; assert_eq!(user_mention_or_link(&user_with_username), "@abcd"); let user_without_username = User { - id: 123_456_789, + id: UserId(123_456_789), is_bot: false, first_name: "Name".to_string(), last_name: None, diff --git a/tests/redis.rs b/tests/redis.rs index dff537ec..f06375c8 100644 --- a/tests/redis.rs +++ b/tests/redis.rs @@ -2,7 +2,10 @@ use std::{ fmt::{Debug, Display}, sync::Arc, }; -use teloxide::dispatching::dialogue::{RedisStorage, RedisStorageError, Serializer, Storage}; +use teloxide::{ + dispatching::dialogue::{RedisStorage, RedisStorageError, Serializer, Storage}, + types::ChatId, +}; #[tokio::test] #[cfg_attr(not(CI_REDIS), ignore)] @@ -44,9 +47,9 @@ type Dialogue = String; macro_rules! test_dialogues { ($storage:expr, $_0:expr, $_1:expr, $_2:expr) => { - assert_eq!(Arc::clone(&$storage).get_dialogue(1).await.unwrap(), $_0); - assert_eq!(Arc::clone(&$storage).get_dialogue(11).await.unwrap(), $_1); - assert_eq!(Arc::clone(&$storage).get_dialogue(256).await.unwrap(), $_2); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(1)).await.unwrap(), $_0); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(11)).await.unwrap(), $_1); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(256)).await.unwrap(), $_2); }; } @@ -57,9 +60,9 @@ where { test_dialogues!(storage, None, None, None); - Arc::clone(&storage).update_dialogue(1, "ABC".to_owned()).await.unwrap(); - Arc::clone(&storage).update_dialogue(11, "DEF".to_owned()).await.unwrap(); - Arc::clone(&storage).update_dialogue(256, "GHI".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(1), "ABC".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(11), "DEF".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(256), "GHI".to_owned()).await.unwrap(); test_dialogues!( storage, @@ -68,15 +71,15 @@ where Some("GHI".to_owned()) ); - Arc::clone(&storage).remove_dialogue(1).await.unwrap(); - Arc::clone(&storage).remove_dialogue(11).await.unwrap(); - Arc::clone(&storage).remove_dialogue(256).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(11)).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(256)).await.unwrap(); test_dialogues!(storage, None, None, None); // Check that a try to remove a non-existing dialogue results in an error. assert!(matches!( - Arc::clone(&storage).remove_dialogue(1).await.unwrap_err(), + Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap_err(), RedisStorageError::DialogueNotFound )); } diff --git a/tests/sqlite.rs b/tests/sqlite.rs index 18dec25b..96cec7db 100644 --- a/tests/sqlite.rs +++ b/tests/sqlite.rs @@ -3,7 +3,10 @@ use std::{ fs, sync::Arc, }; -use teloxide::dispatching::dialogue::{Serializer, SqliteStorage, SqliteStorageError, Storage}; +use teloxide::{ + dispatching::dialogue::{Serializer, SqliteStorage, SqliteStorageError, Storage}, + types::ChatId, +}; #[tokio::test(flavor = "multi_thread")] async fn test_sqlite_json() { @@ -48,9 +51,9 @@ type Dialogue = String; macro_rules! test_dialogues { ($storage:expr, $_0:expr, $_1:expr, $_2:expr) => { - assert_eq!(Arc::clone(&$storage).get_dialogue(1).await.unwrap(), $_0); - assert_eq!(Arc::clone(&$storage).get_dialogue(11).await.unwrap(), $_1); - assert_eq!(Arc::clone(&$storage).get_dialogue(256).await.unwrap(), $_2); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(1)).await.unwrap(), $_0); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(11)).await.unwrap(), $_1); + assert_eq!(Arc::clone(&$storage).get_dialogue(ChatId(256)).await.unwrap(), $_2); }; } @@ -61,9 +64,9 @@ where { test_dialogues!(storage, None, None, None); - Arc::clone(&storage).update_dialogue(1, "ABC".to_owned()).await.unwrap(); - Arc::clone(&storage).update_dialogue(11, "DEF".to_owned()).await.unwrap(); - Arc::clone(&storage).update_dialogue(256, "GHI".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(1), "ABC".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(11), "DEF".to_owned()).await.unwrap(); + Arc::clone(&storage).update_dialogue(ChatId(256), "GHI".to_owned()).await.unwrap(); test_dialogues!( storage, @@ -72,15 +75,15 @@ where Some("GHI".to_owned()) ); - Arc::clone(&storage).remove_dialogue(1).await.unwrap(); - Arc::clone(&storage).remove_dialogue(11).await.unwrap(); - Arc::clone(&storage).remove_dialogue(256).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(11)).await.unwrap(); + Arc::clone(&storage).remove_dialogue(ChatId(256)).await.unwrap(); test_dialogues!(storage, None, None, None); // Check that a try to remove a non-existing dialogue results in an error. assert!(matches!( - Arc::clone(&storage).remove_dialogue(1).await.unwrap_err(), + Arc::clone(&storage).remove_dialogue(ChatId(1)).await.unwrap_err(), SqliteStorageError::DialogueNotFound )); }