Keep unregistered projects' ids until pending contact updates are done

Max Brunsfeld created

Change summary

crates/client/src/user.rs     | 15 +++++++++++++++
crates/project/src/project.rs | 13 +++++++++++++
2 files changed, 28 insertions(+)

Detailed changes

crates/client/src/user.rs 🔗

@@ -99,6 +99,7 @@ impl Entity for UserStore {
 
 enum UpdateContacts {
     Update(proto::UpdateContacts),
+    Wait(postage::barrier::Sender),
     Clear(postage::barrier::Sender),
 }
 
@@ -217,6 +218,10 @@ impl UserStore {
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<()>> {
         match message {
+            UpdateContacts::Wait(barrier) => {
+                drop(barrier);
+                Task::ready(Ok(()))
+            }
             UpdateContacts::Clear(barrier) => {
                 self.contacts.clear();
                 self.incoming_contact_requests.clear();
@@ -497,6 +502,16 @@ impl UserStore {
         }
     }
 
+    pub fn contact_updates_done(&mut self) -> impl Future<Output = ()> {
+        let (tx, mut rx) = postage::barrier::channel();
+        self.update_contacts_tx
+            .unbounded_send(UpdateContacts::Wait(tx))
+            .unwrap();
+        async move {
+            rx.recv().await;
+        }
+    }
+
     pub fn get_users(
         &mut self,
         mut user_ids: Vec<u64>,

crates/project/src/project.rs 🔗

@@ -654,6 +654,19 @@ impl Project {
                 });
                 return cx.spawn(|this, mut cx| async move {
                     let response = request.await;
+
+                    // Unregistering the project causes the server to send out a
+                    // contact update removing this project from the host's list
+                    // of public projects. Wait until this contact update has been
+                    // processed before clearing out this project's remote id, so
+                    // that there is no moment where this project appears in the
+                    // contact metadata and *also* has no remote id.
+                    this.update(&mut cx, |this, cx| {
+                        this.user_store()
+                            .update(cx, |store, _| store.contact_updates_done())
+                    })
+                    .await;
+
                     this.update(&mut cx, |this, cx| {
                         if let ProjectClientState::Local { remote_id_tx, .. } =
                             &mut this.client_state