diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 79a0304a1b..b12e90d9bc 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -160,16 +160,13 @@ impl Project { if let Some(project_id) = remote_id { let mut registrations = Vec::new(); - this.read_with(&cx, |this, cx| { + this.update(&mut cx, |this, cx| { for worktree in &this.worktrees { - let worktree_id = worktree.id() as u64; - let worktree = worktree.read(cx).as_local().unwrap(); - registrations.push(rpc.request( - proto::RegisterWorktree { - project_id, - worktree_id, - root_name: worktree.root_name().to_string(), - authorized_logins: worktree.authorized_logins(), + registrations.push(worktree.update( + cx, + |worktree, cx| { + let worktree = worktree.as_local_mut().unwrap(); + worktree.register(project_id, cx) }, )); } @@ -407,7 +404,7 @@ impl Project { for worktree in &this.worktrees { worktree.update(cx, |worktree, cx| { let worktree = worktree.as_local_mut().unwrap(); - tasks.push(worktree.share(project_id, cx)); + tasks.push(worktree.share(cx)); }); } }); @@ -897,21 +894,15 @@ impl Project { }); if let Some(project_id) = remote_project_id { - let worktree_id = worktree.id() as u64; - let register_message = worktree.update(&mut cx, |worktree, _| { - let worktree = worktree.as_local_mut().unwrap(); - proto::RegisterWorktree { - project_id, - worktree_id, - root_name: worktree.root_name().to_string(), - authorized_logins: worktree.authorized_logins(), - } - }); - client.request(register_message).await?; + worktree + .update(&mut cx, |worktree, cx| { + worktree.as_local_mut().unwrap().register(project_id, cx) + }) + .await?; if is_shared { worktree .update(&mut cx, |worktree, cx| { - worktree.as_local_mut().unwrap().share(project_id, cx) + worktree.as_local_mut().unwrap().share(cx) }) .await?; } @@ -921,6 +912,12 @@ impl Project { }) } + pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext) { + self.worktrees + .retain(|worktree| worktree.read(cx).id() != id); + cx.notify(); + } + fn add_worktree(&mut self, worktree: ModelHandle, cx: &mut ModelContext) { cx.observe(&worktree, |_, _, cx| cx.notify()).detach(); self.worktrees.push(worktree); @@ -1104,9 +1101,7 @@ impl Project { cx: &mut ModelContext, ) -> Result<()> { let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); - self.worktrees - .retain(|worktree| worktree.read(cx).as_remote().unwrap().id() != worktree_id); - cx.notify(); + self.remove_worktree(worktree_id, cx); Ok(()) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index d734a62bc3..ea245cacdc 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -66,6 +66,24 @@ pub enum Worktree { impl Entity for Worktree { type Event = (); + + fn release(&mut self, cx: &mut MutableAppContext) { + if let Some(worktree) = self.as_local_mut() { + if let Registration::Done { project_id } = worktree.registration { + let client = worktree.client.clone(); + let unregister_message = proto::UnregisterWorktree { + project_id, + worktree_id: worktree.id().to_proto(), + }; + cx.foreground() + .spawn(async move { + client.send(unregister_message).await?; + Ok::<_, anyhow::Error>(()) + }) + .detach_and_log_err(cx); + } + } + } } impl Worktree { @@ -747,6 +765,7 @@ pub struct LocalWorktree { last_scan_state_rx: watch::Receiver, _background_scanner_task: Option>, poll_task: Option>, + registration: Registration, share: Option, loading_buffers: LoadingBuffers, open_buffers: HashMap>, @@ -759,6 +778,13 @@ pub struct LocalWorktree { fs: Arc, } +#[derive(Debug, Eq, PartialEq)] +enum Registration { + None, + Pending, + Done { project_id: u64 }, +} + struct ShareState { project_id: u64, snapshots_tx: Sender, @@ -851,6 +877,7 @@ impl LocalWorktree { background_snapshot: Arc::new(Mutex::new(snapshot)), last_scan_state_rx, _background_scanner_task: None, + registration: Registration::None, share: None, poll_task: None, loading_buffers: Default::default(), @@ -1316,11 +1343,48 @@ impl LocalWorktree { }) } - pub fn share( + pub fn register( &mut self, project_id: u64, cx: &mut ModelContext, ) -> Task> { + if self.registration != Registration::None { + return Task::ready(Ok(())); + } + + self.registration = Registration::Pending; + let client = self.client.clone(); + let register_message = proto::RegisterWorktree { + project_id, + worktree_id: self.id().to_proto(), + root_name: self.root_name().to_string(), + authorized_logins: self.authorized_logins(), + }; + cx.spawn(|this, mut cx| async move { + let response = client.request(register_message).await; + this.update(&mut cx, |this, _| { + let worktree = this.as_local_mut().unwrap(); + match response { + Ok(_) => { + worktree.registration = Registration::Done { project_id }; + Ok(()) + } + Err(error) => { + worktree.registration = Registration::None; + Err(error) + } + } + }) + }) + } + + pub fn share(&mut self, cx: &mut ModelContext) -> Task> { + let project_id = if let Registration::Done { project_id } = self.registration { + project_id + } else { + return Task::ready(Err(anyhow!("cannot share worktree before registering it"))); + }; + if self.share.is_some() { return Task::ready(Ok(())); }