From 05a3c0c89ba5a1364eb760acdbf9d638c7f40177 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 22 Jan 2022 16:58:02 +0100 Subject: [PATCH] webxdc: synchronous state for read-only-chats already before, we did _not_ sent updates to contact requests or other read-only-chats. however, we _did_ modify the local database, so that getAllUpdates() returns an update that was not sent out to other peers. this is fixed by checking can_send() soon. that way, all peers have the same state also for contact requests or other read-only-chats and webxdc in contact requests can be opened as usual. further ui improvements may be needed for contact requests (maybe allow the webxdc to know about that state or maybe show a warning in the ui somewhere), however, this is not part of this pr. --- CHANGELOG.md | 2 +- draft/webxdc-dev-reference.md | 7 ++++++ src/webxdc.rs | 46 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f937129f..4c70a3614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ - Synchronize Seen status across devices #2942 - Add API to set the database password #2956 - Add information about whether the database is encrypted or not to `dc_get_info()` #3000 -- Add Webxdc #2826 #2971 #2975 #2977 #2979 #2993 #2998 +- Add Webxdc #2826 #2971 #2975 #2977 #2979 #2993 #2998 #3001 ### Changed - selfstatus now defaults to empty diff --git a/draft/webxdc-dev-reference.md b/draft/webxdc-dev-reference.md index 83801deee..2052e21d8 100644 --- a/draft/webxdc-dev-reference.md +++ b/draft/webxdc-dev-reference.md @@ -44,6 +44,13 @@ To get a shared state, the peers use `sendUpdate()` to send updates to each othe All peers, including the sending one, will receive the update by the callback given to `setUpdateListener()`. +There are situations where the user cannot send messages to a chat, +eg. contact requests or if the user has left a group. +In these cases, you can still call `sendUpdate()`, +however, the update won't be sent to other peers +and you won't get the update by `setUpdateListener()` nor by `getAllUpdates()`. + + ### setUpdateListener() ```js diff --git a/src/webxdc.rs b/src/webxdc.rs index 624c3a8fb..257973657 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -1,5 +1,6 @@ //! # Handle webxdc messages. +use crate::chat::Chat; use crate::constants::Viewtype; use crate::context::Context; use crate::dc_tools::{dc_create_smeared_timestamp, dc_open_file_std}; @@ -246,6 +247,9 @@ impl Context { bail!("send_webxdc_status_update: is no webxdc message"); } + let chat = Chat::load_from_db(self, instance.chat_id).await?; + ensure!(chat.can_send(self).await?, "cannot send to {}", chat.id); + let status_update_id = self .create_status_update_record( &mut instance, @@ -683,6 +687,48 @@ mod tests { Ok(()) } + #[async_std::test] + async fn test_webxdc_contact_request() -> Result<()> { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + + // Alice sends an webxdc instance to Bob + let alice_chat = alice.create_chat(&bob).await; + let _alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; + bob.recv_msg(&alice.pop_sent_msg().await).await; + + // Bob can start the webxdc from a contact request (get index.html) + // but cannot send updates to contact requests + let bob_instance = bob.get_last_msg().await; + let bob_chat = Chat::load_from_db(&bob, bob_instance.chat_id).await?; + assert!(bob_chat.is_contact_request()); + assert!(bob_instance + .get_webxdc_blob(&bob, "index.html") + .await + .is_ok()); + assert!(bob + .send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#, "descr") + .await + .is_err()); + assert_eq!( + bob.get_webxdc_status_updates(bob_instance.id, None).await?, + "[]" + ); + + // Once the contact request is accepted, Bob can send updates + bob_chat.id.accept(&bob).await?; + assert!(bob + .send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#, "descr") + .await + .is_ok()); + assert_eq!( + bob.get_webxdc_status_updates(bob_instance.id, None).await?, + r#"[{"payload":42}]"# + ); + + Ok(()) + } + #[async_std::test] async fn test_delete_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await;