summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-12-21 19:58:53 +0100
committerMatthias Beyer <mail@beyermatthias.de>2021-12-21 19:58:53 +0100
commit286497177a040921ea9687a07436565cfad77384 (patch)
tree5ce32bb1c94a39ebaac55f2c4ec0b0dee35dd49d
parent1034a454d0900130796fd8941bbc9696bcc41b29 (diff)
parent2300a0a871ad8e2de528bfcd4d53d1df812fd5d9 (diff)
Merge branch 'posting'
-rw-r--r--gui/src/app/message.rs7
-rw-r--r--gui/src/app/mod.rs62
-rw-r--r--gui/src/gossip.rs5
-rw-r--r--gui/src/timeline.rs17
-rw-r--r--lib/src/gossip/handler.rs8
-rw-r--r--lib/src/types/datetime.rs2
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>);