diff --git a/src/mongodb_storage.rs b/src/mongodb_storage.rs new file mode 100644 index 0000000..9fdb76f --- /dev/null +++ b/src/mongodb_storage.rs @@ -0,0 +1,105 @@ +use std::{ + fmt::{Debug, Display}, + sync::Arc, +}; + +use futures::future::BoxFuture; +use mongodb::bson::doc; +use mongodb::Database; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use teloxide::dispatching::dialogue::{Serializer, Storage}; + +pub struct MongodbStorage { + database: Database, + serializer: S, +} + +impl MongodbStorage { + pub async fn open( + database_url: &str, + database_name: &str, + serializer: S, + ) -> Result, mongodb::error::Error> { + let client = mongodb::Client::with_uri_str(database_url).await?; + let database = client.database(database_name); + + Ok(Arc::new(Self { + database, + serializer, + })) + } +} + +#[derive(Serialize, Deserialize)] +pub struct Dialogue { + chat_id: i64, + dialogue: Vec, +} + +impl Storage for MongodbStorage +where + S: Send + Sync + Serializer + 'static, + D: Send + Serialize + DeserializeOwned + 'static, + + >::Error: Debug + Display, +{ + type Error = mongodb::error::Error; + + fn remove_dialogue( + self: std::sync::Arc, + chat_id: teloxide::prelude::ChatId, + ) -> BoxFuture<'static, Result<(), Self::Error>> + where + D: Send + 'static, + { + Box::pin(async move { + let d = self.database.collection::("dialogues"); + d.delete_one(doc! { "chat_id": chat_id.0 }) + .await + .map(|_| ()) + }) + } + + fn update_dialogue( + self: std::sync::Arc, + chat_id: teloxide::prelude::ChatId, + dialogue: D, + ) -> BoxFuture<'static, Result<(), Self::Error>> + where + D: Send + 'static, + { + Box::pin(async move { + let d = self.database.collection::("dialogues"); + d.update_one( + doc! { + "chat_id": chat_id.0 + }, + doc! { + "$set": doc! { + "dialogue": self.serializer.serialize(&dialogue).unwrap().into_iter().map(|v| v as u32).collect::>() + } + }).upsert(true).await?; + Ok(()) + }) + } + + fn get_dialogue( + self: std::sync::Arc, + chat_id: teloxide::prelude::ChatId, + ) -> BoxFuture<'static, Result, Self::Error>> { + Box::pin(async move { + let d = self.database.collection::("dialogues"); + Ok(d.find_one(doc! { "chat_id": chat_id.0 }).await?.map(|d| { + self.serializer + .deserialize( + d.dialogue + .into_iter() + .map(|i| i as u8) + .collect::>() + .as_slice(), + ) + .unwrap() + })) + }) + } +}