diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-12-21 19:58:53 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2021-12-21 19:58:53 +0100 |
commit | 286497177a040921ea9687a07436565cfad77384 (patch) | |
tree | 5ce32bb1c94a39ebaac55f2c4ec0b0dee35dd49d | |
parent | 1034a454d0900130796fd8941bbc9696bcc41b29 (diff) | |
parent | 2300a0a871ad8e2de528bfcd4d53d1df812fd5d9 (diff) |
Merge branch 'posting'
-rw-r--r-- | gui/src/app/message.rs | 7 | ||||
-rw-r--r-- | gui/src/app/mod.rs | 62 | ||||
-rw-r--r-- | gui/src/gossip.rs | 5 | ||||
-rw-r--r-- | gui/src/timeline.rs | 17 | ||||
-rw-r--r-- | lib/src/gossip/handler.rs | 8 | ||||
-rw-r--r-- | lib/src/types/datetime.rs | 2 |
6 files changed, 70 insertions, 31 deletions
diff --git a/gui/src/app/message.rs b/gui/src/app/message.rs index dcb7477..f19a2dd 100644 --- a/gui/src/app/message.rs +++ b/gui/src/app/message.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use cid::Cid; +use tokio::sync::RwLock; use distrox_lib::gossip::GossipMessage; use distrox_lib::profile::Profile; @@ -10,8 +11,10 @@ use crate::gossip::GossipRecipe; #[derive(Clone, Debug)] pub enum Message { - Loaded(Arc<Profile>), + Loaded(Arc<RwLock<Profile>>), FailedToLoad(String), + ProfileStateSaved, + ProfileStateSavingFailed(String), ToggleLog, @@ -39,6 +42,8 @@ impl Message { match self { Message::Loaded(_) => "Loaded", Message::FailedToLoad(_) => "FailedToLoad", + Message::ProfileStateSaved => "ProfileStateSaved", + Message::ProfileStateSavingFailed(_) => "ProfileStateSavingFailed", Message::ToggleLog => "ToggleLog", diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 77f6c9d..a1428cd 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -1,5 +1,4 @@ use std::sync::Arc; -use std::sync::RwLock as StdRwLock; use anyhow::Result; use iced::Application; @@ -12,6 +11,7 @@ use iced::TextInput; use iced::scrollable; use iced::text_input; use distrox_lib::profile::Profile; +use tokio::sync::RwLock; use crate::timeline::Timeline; use crate::timeline::PostLoadingRecipe; @@ -24,11 +24,11 @@ use crate::gossip::GossipRecipe; #[derive(Debug)] enum Distrox { Loading { - gossip_subscription_recv: StdRwLock<tokio::sync::oneshot::Receiver<GossipRecipe>>, + gossip_subscription_recv: RwLock<tokio::sync::oneshot::Receiver<GossipRecipe>>, }, Loaded { - profile: Arc<Profile>, - gossip_subscription_recv: StdRwLock<tokio::sync::oneshot::Receiver<GossipRecipe>>, + profile: Arc<RwLock<Profile>>, + gossip_subscription_recv: RwLock<tokio::sync::oneshot::Receiver<GossipRecipe>>, scroll: scrollable::State, input: text_input::State, @@ -50,16 +50,19 @@ impl Application for Distrox { let (gossip_subscription_sender, gossip_subscription_recv) = tokio::sync::oneshot::channel(); ( Distrox::Loading { - gossip_subscription_recv: StdRwLock::new(gossip_subscription_recv), + gossip_subscription_recv: RwLock::new(gossip_subscription_recv), }, iced::Command::perform(async move { let profile = match Profile::load(&name).await { Err(e) => return Message::FailedToLoad(e.to_string()), - Ok(instance) => Arc::new(instance), + Ok(instance) => Arc::new(RwLock::new(instance)), }; - if let Err(e) = profile.client() + if let Err(e) = profile + .read() + .await + .client() .pubsub_subscribe("distrox".to_string()) .await .map_err(anyhow::Error::from) @@ -91,7 +94,7 @@ impl Application for Distrox { profile, // Don't even try to think what hoops I am jumping through here... - gossip_subscription_recv: std::mem::replace(gossip_subscription_recv, StdRwLock::new(tokio::sync::oneshot::channel().1)), + gossip_subscription_recv: std::mem::replace(gossip_subscription_recv, RwLock::new(tokio::sync::oneshot::channel().1)), scroll: scrollable::State::default(), input: text_input::State::default(), input_value: String::default(), @@ -115,11 +118,11 @@ impl Application for Distrox { Message::CreatePost => { if !input_value.is_empty() { let input = input_value.clone(); - let client = profile.client().clone(); + let profile = profile.clone(); log::trace!("Posting..."); iced::Command::perform(async move { log::trace!("Posting: '{}'", input); - client.post_text_blob(input).await + profile.write().await.post_text(input).await }, |res| match res { Ok(cid) => Message::PostCreated(cid), @@ -133,9 +136,27 @@ impl Application for Distrox { Message::PostCreated(cid) => { *input_value = String::new(); log::info!("Post created: {}", cid); - iced::Command::none() + + let profile = profile.clone(); + iced::Command::perform(async move { + if let Err(e) = profile.read().await.save().await { + Message::ProfileStateSavingFailed(e.to_string()) + } else { + Message::ProfileStateSaved + } + }, |m: Message| -> Message { m }) } + Message::ProfileStateSaved => { + log::info!("Profile state saved"); + iced::Command::none() + }, + + Message::ProfileStateSavingFailed(e) => { + log::error!("Saving profile failed: {}", e); + iced::Command::none() + }, + Message::PostCreationFailed(err) => { log::error!("Post creation failed: {}", err); iced::Command::none() @@ -181,7 +202,7 @@ impl Application for Distrox { Message::PublishGossipAboutMe => { let profile = profile.clone(); iced::Command::perform(async move { - if let Err(e) = profile.gossip_own_state("distrox".to_string()).await { + if let Err(e) = profile.read().await.gossip_own_state("distrox".to_string()).await { Message::GossippingFailed(e.to_string()) } else { Message::OwnStateGossipped @@ -293,9 +314,12 @@ impl Application for Distrox { fn subscription(&self) -> iced::Subscription<Self::Message> { let post_loading_subs = match self { Distrox::Loaded { profile, .. } => { - let head = profile.head(); + let profile = match profile.try_read() { + Err(_) => return iced::Subscription::none(), + Ok(p) => p, + }; - match head { + match profile.head() { None => iced::Subscription::none(), Some(head) => { iced::Subscription::from_recipe({ @@ -326,18 +350,18 @@ impl Application for Distrox { let gossip_sub = match self { Distrox::Loaded { gossip_subscription_recv, .. } => { - match gossip_subscription_recv.write().ok() { - Some(mut sub) => sub.try_recv() - .ok() // Either empty or closed, ignore both + match gossip_subscription_recv.try_write() { + Err(_) => None, + Ok(mut sub) => sub.try_recv() + .ok() .map(|sub| iced::Subscription::from_recipe(sub)), - None => None } }, _ => None, }; let gossip_sending_sub = { - iced::time::every(std::time::Duration::from_millis(100)) + iced::time::every(std::time::Duration::from_secs(5)) .map(|_| Message::PublishGossipAboutMe) }; diff --git a/gui/src/gossip.rs b/gui/src/gossip.rs index ac6bab0..c88c29c 100644 --- a/gui/src/gossip.rs +++ b/gui/src/gossip.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use futures::StreamExt; +use tokio::sync::RwLock; use distrox_lib::profile::Profile; use distrox_lib::client::Client; @@ -9,12 +10,12 @@ use crate::app::Message; #[derive(Clone, Debug)] pub struct GossipRecipe { - profile: Arc<Profile>, + profile: Arc<RwLock<Profile>>, subscription: Arc<ipfs::SubscriptionStream>, } impl GossipRecipe { - pub fn new(profile: Arc<Profile>, subscription: ipfs::SubscriptionStream) -> Self { + pub fn new(profile: Arc<RwLock<Profile>>, subscription: ipfs::SubscriptionStream) -> Self { Self { profile, subscription: Arc::new(subscription) } } } diff --git a/gui/src/timeline.rs b/gui/src/timeline.rs index 0dace40..75f3c73 100644 --- a/gui/src/timeline.rs +++ b/gui/src/timeline.rs @@ -1,3 +1,6 @@ +use std::collections::HashSet; +use std::collections::BTreeMap; + use anyhow::Result; use futures::StreamExt; @@ -8,23 +11,28 @@ use crate::post::Post; use distrox_lib::client::Client; use distrox_lib::stream::NodeStreamBuilder; use distrox_lib::types::Payload; +use distrox_lib::types::DateTime; #[derive(Debug)] pub struct Timeline { - posts: Vec<Post>, + post_ids: HashSet<cid::Cid>, + posts: BTreeMap<DateTime, Post>, scrollable: ScrollableState, } impl Timeline { pub fn new() -> Self { Self { - posts: Vec::new(), + post_ids: HashSet::with_capacity(1000), + posts: BTreeMap::new(), scrollable: ScrollableState::new(), } } pub fn push(&mut self, payload: Payload, content: String) { - self.posts.push(Post::new(payload, content)); + if self.post_ids.insert(payload.content()) { + self.posts.insert(payload.timestamp().clone(), Post::new(payload, content)); + } } pub fn view(&mut self) -> iced::Element<Message> { @@ -39,7 +47,8 @@ impl Timeline { self.posts .iter() - .fold(scrollable, |scrollable, post| { + .rev() + .fold(scrollable, |scrollable, (_, post)| { scrollable.push(post.view()) }) .into() diff --git a/lib/src/gossip/handler.rs b/lib/src/gossip/handler.rs index 7c9ffa6..e524da8 100644 --- a/lib/src/gossip/handler.rs +++ b/lib/src/gossip/handler.rs @@ -18,14 +18,14 @@ use crate::gossip::GossipMessage; pub struct GossipHandler<Strategy = LogStrategy> where Strategy: GossipHandlingStrategy + Sync + Send { - profile: Arc<Profile>, + profile: Arc<RwLock<Profile>>, strategy: std::marker::PhantomData<Strategy>, } impl<Strat> GossipHandler<Strat> where Strat: GossipHandlingStrategy + Sync + Send { - pub fn new(profile: Arc<Profile>) -> Self { + pub fn new(profile: Arc<RwLock<Profile>>) -> Self { Self { profile, strategy: std::marker::PhantomData, @@ -48,14 +48,14 @@ impl<Strat> GossipHandler<Strat> #[async_trait::async_trait] pub trait GossipHandlingStrategy: Sync + Send { - async fn handle_gossip_message(profile: Arc<Profile>, source: &ipfs::PeerId, msg: &GossipMessage) -> Result<()>; + async fn handle_gossip_message(profile: Arc<RwLock<Profile>>, source: &ipfs::PeerId, msg: &GossipMessage) -> Result<()>; } pub struct LogStrategy; #[async_trait::async_trait] impl GossipHandlingStrategy for LogStrategy { - async fn handle_gossip_message(_profile: Arc<Profile>, source: &ipfs::PeerId, msg: &GossipMessage) -> Result<()> { + async fn handle_gossip_message(_profile: Arc<RwLock<Profile>>, source: &ipfs::PeerId, msg: &GossipMessage) -> Result<()> { use std::convert::TryFrom; use std::ops::Deref; diff --git a/lib/src/types/datetime.rs b/lib/src/types/datetime.rs index 70098d7..9cc1e65 100644 --- a/lib/src/types/datetime.rs +++ b/lib/src/types/datetime.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use anyhow::Error; use anyhow::Result; -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(transparent)] pub struct DateTime(chrono::DateTime<chrono::Utc>); |