ssh remote: Handle disconnect on project and show overlay (#19014)

Demo:



https://github.com/user-attachments/assets/e5edf8f3-8c15-482e-a792-6eb619f83de4


Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-10-10 12:59:09 +02:00 committed by GitHub
parent e3ff2ced79
commit b75532fad7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 264 additions and 78 deletions

View file

@ -58,7 +58,7 @@ use node_runtime::NodeRuntime;
use parking_lot::{Mutex, RwLock};
pub use prettier_store::PrettierStore;
use project_settings::{ProjectSettings, SettingsObserver, SettingsObserverEvent};
use remote::SshRemoteClient;
use remote::{SshConnectionOptions, SshRemoteClient};
use rpc::{proto::SSH_PROJECT_ID, AnyProtoClient, ErrorCode};
use search::{SearchInputKind, SearchQuery, SearchResult};
use search_history::SearchHistory;
@ -245,6 +245,7 @@ pub enum Event {
},
RemoteIdChanged(Option<u64>),
DisconnectedFromHost,
DisconnectedFromSshRemote,
Closed,
DeletedEntry(ProjectEntryId),
CollaboratorUpdated {
@ -755,6 +756,8 @@ impl Project {
}
})
.detach();
cx.subscribe(&ssh, Self::on_ssh_event).detach();
cx.observe(&ssh, |_, _, cx| cx.notify()).detach();
let this = Self {
@ -1313,6 +1316,12 @@ impl Project {
.map(|ssh| ssh.read(cx).connection_state())
}
pub fn ssh_connection_options(&self, cx: &AppContext) -> Option<SshConnectionOptions> {
self.ssh_client
.as_ref()
.map(|ssh| ssh.read(cx).connection_options())
}
pub fn replica_id(&self) -> ReplicaId {
match self.client_state {
ProjectClientState::Remote { replica_id, .. } => replica_id,
@ -1658,7 +1667,7 @@ impl Project {
}
pub fn disconnected_from_host(&mut self, cx: &mut ModelContext<Self>) {
if self.is_disconnected() {
if self.is_disconnected(cx) {
return;
}
self.disconnected_from_host_internal(cx);
@ -1708,16 +1717,24 @@ impl Project {
cx.emit(Event::Closed);
}
pub fn is_disconnected(&self) -> bool {
pub fn is_disconnected(&self, cx: &AppContext) -> bool {
match &self.client_state {
ProjectClientState::Remote {
sharing_has_stopped,
..
} => *sharing_has_stopped,
ProjectClientState::Local if self.is_via_ssh() => self.ssh_is_disconnected(cx),
_ => false,
}
}
fn ssh_is_disconnected(&self, cx: &AppContext) -> bool {
self.ssh_client
.as_ref()
.map(|ssh| ssh.read(cx).is_disconnected())
.unwrap_or(false)
}
pub fn capability(&self) -> Capability {
match &self.client_state {
ProjectClientState::Remote { capability, .. } => *capability,
@ -1725,8 +1742,8 @@ impl Project {
}
}
pub fn is_read_only(&self) -> bool {
self.is_disconnected() || self.capability() == Capability::ReadOnly
pub fn is_read_only(&self, cx: &AppContext) -> bool {
self.is_disconnected(cx) || self.capability() == Capability::ReadOnly
}
pub fn is_local(&self) -> bool {
@ -1807,7 +1824,7 @@ impl Project {
path: impl Into<ProjectPath>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
if self.is_via_collab() && self.is_disconnected() {
if (self.is_via_collab() || self.is_via_ssh()) && self.is_disconnected(cx) {
return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
}
@ -2114,6 +2131,30 @@ impl Project {
}
}
fn on_ssh_event(
&mut self,
_: Model<SshRemoteClient>,
event: &remote::SshRemoteEvent,
cx: &mut ModelContext<Self>,
) {
match event {
remote::SshRemoteEvent::Disconnected => {
// if self.is_via_ssh() {
// self.collaborators.clear();
self.worktree_store.update(cx, |store, cx| {
store.disconnected_from_host(cx);
});
self.buffer_store.update(cx, |buffer_store, cx| {
buffer_store.disconnected_from_host(cx)
});
self.lsp_store.update(cx, |lsp_store, _cx| {
lsp_store.disconnected_from_ssh_remote()
});
cx.emit(Event::DisconnectedFromSshRemote);
}
}
}
fn on_settings_observer_event(
&mut self,
_: Model<SettingsObserver>,