ssh remoting: Enable reconnecting after connection losses (#18586)
Release Notes: - N/A --------- Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
parent
67fbdbbed6
commit
c03b8d6c48
19 changed files with 727 additions and 240 deletions
|
@ -141,7 +141,7 @@ pub struct Project {
|
|||
join_project_response_message_id: u32,
|
||||
user_store: Model<UserStore>,
|
||||
fs: Arc<dyn Fs>,
|
||||
ssh_client: Option<Arc<SshRemoteClient>>,
|
||||
ssh_client: Option<Model<SshRemoteClient>>,
|
||||
client_state: ProjectClientState,
|
||||
collaborators: HashMap<proto::PeerId, Collaborator>,
|
||||
client_subscriptions: Vec<client::Subscription>,
|
||||
|
@ -667,7 +667,7 @@ impl Project {
|
|||
}
|
||||
|
||||
pub fn ssh(
|
||||
ssh: Arc<SshRemoteClient>,
|
||||
ssh: Model<SshRemoteClient>,
|
||||
client: Arc<Client>,
|
||||
node: NodeRuntime,
|
||||
user_store: Model<UserStore>,
|
||||
|
@ -684,15 +684,16 @@ impl Project {
|
|||
let snippets =
|
||||
SnippetProvider::new(fs.clone(), BTreeSet::from_iter([global_snippets_dir]), cx);
|
||||
|
||||
let ssh_proto = ssh.read(cx).to_proto_client();
|
||||
let worktree_store =
|
||||
cx.new_model(|_| WorktreeStore::remote(false, ssh.to_proto_client(), 0, None));
|
||||
cx.new_model(|_| WorktreeStore::remote(false, ssh_proto.clone(), 0, None));
|
||||
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
|
||||
.detach();
|
||||
|
||||
let buffer_store = cx.new_model(|cx| {
|
||||
BufferStore::remote(
|
||||
worktree_store.clone(),
|
||||
ssh.to_proto_client(),
|
||||
ssh.read(cx).to_proto_client(),
|
||||
SSH_PROJECT_ID,
|
||||
cx,
|
||||
)
|
||||
|
@ -701,7 +702,7 @@ impl Project {
|
|||
.detach();
|
||||
|
||||
let settings_observer = cx.new_model(|cx| {
|
||||
SettingsObserver::new_ssh(ssh.to_proto_client(), worktree_store.clone(), cx)
|
||||
SettingsObserver::new_ssh(ssh_proto.clone(), worktree_store.clone(), cx)
|
||||
});
|
||||
cx.subscribe(&settings_observer, Self::on_settings_observer_event)
|
||||
.detach();
|
||||
|
@ -712,13 +713,24 @@ impl Project {
|
|||
buffer_store.clone(),
|
||||
worktree_store.clone(),
|
||||
languages.clone(),
|
||||
ssh.to_proto_client(),
|
||||
ssh_proto.clone(),
|
||||
SSH_PROJECT_ID,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
|
||||
|
||||
cx.on_release(|this, cx| {
|
||||
if let Some(ssh_client) = this.ssh_client.as_ref() {
|
||||
ssh_client
|
||||
.read(cx)
|
||||
.to_proto_client()
|
||||
.send(proto::ShutdownRemoteServer {})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
let this = Self {
|
||||
buffer_ordered_messages_tx: tx,
|
||||
collaborators: Default::default(),
|
||||
|
@ -754,20 +766,20 @@ impl Project {
|
|||
search_excluded_history: Self::new_search_history(),
|
||||
};
|
||||
|
||||
let client: AnyProtoClient = ssh.to_proto_client();
|
||||
|
||||
let ssh = ssh.read(cx);
|
||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &cx.handle());
|
||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.buffer_store);
|
||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.worktree_store);
|
||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.lsp_store);
|
||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.settings_observer);
|
||||
client.add_model_message_handler(Self::handle_create_buffer_for_peer);
|
||||
client.add_model_message_handler(Self::handle_update_worktree);
|
||||
client.add_model_message_handler(Self::handle_update_project);
|
||||
client.add_model_request_handler(BufferStore::handle_update_buffer);
|
||||
BufferStore::init(&client);
|
||||
LspStore::init(&client);
|
||||
SettingsObserver::init(&client);
|
||||
|
||||
ssh_proto.add_model_message_handler(Self::handle_create_buffer_for_peer);
|
||||
ssh_proto.add_model_message_handler(Self::handle_update_worktree);
|
||||
ssh_proto.add_model_message_handler(Self::handle_update_project);
|
||||
ssh_proto.add_model_request_handler(BufferStore::handle_update_buffer);
|
||||
BufferStore::init(&ssh_proto);
|
||||
LspStore::init(&ssh_proto);
|
||||
SettingsObserver::init(&ssh_proto);
|
||||
|
||||
this
|
||||
})
|
||||
|
@ -1222,7 +1234,7 @@ impl Project {
|
|||
|
||||
pub fn ssh_connection_string(&self, cx: &AppContext) -> Option<SharedString> {
|
||||
if let Some(ssh_state) = &self.ssh_client {
|
||||
return Some(ssh_state.connection_string().into());
|
||||
return Some(ssh_state.read(cx).connection_string().into());
|
||||
}
|
||||
let dev_server_id = self.dev_server_project_id()?;
|
||||
dev_server_projects::Store::global(cx)
|
||||
|
@ -1232,8 +1244,8 @@ impl Project {
|
|||
.clone()
|
||||
}
|
||||
|
||||
pub fn ssh_is_connected(&self) -> Option<bool> {
|
||||
Some(!self.ssh_client.as_ref()?.is_reconnect_underway())
|
||||
pub fn ssh_is_connected(&self, cx: &AppContext) -> Option<bool> {
|
||||
Some(!self.ssh_client.as_ref()?.read(cx).is_reconnect_underway())
|
||||
}
|
||||
|
||||
pub fn replica_id(&self) -> ReplicaId {
|
||||
|
@ -1945,6 +1957,7 @@ impl Project {
|
|||
BufferStoreEvent::BufferDropped(buffer_id) => {
|
||||
if let Some(ref ssh_client) = self.ssh_client {
|
||||
ssh_client
|
||||
.read(cx)
|
||||
.to_proto_client()
|
||||
.send(proto::CloseBuffer {
|
||||
project_id: 0,
|
||||
|
@ -2151,7 +2164,8 @@ impl Project {
|
|||
let operation = language::proto::serialize_operation(operation);
|
||||
|
||||
if let Some(ssh) = &self.ssh_client {
|
||||
ssh.to_proto_client()
|
||||
ssh.read(cx)
|
||||
.to_proto_client()
|
||||
.send(proto::UpdateBuffer {
|
||||
project_id: 0,
|
||||
buffer_id: buffer_id.to_proto(),
|
||||
|
@ -2838,7 +2852,7 @@ impl Project {
|
|||
let (tx, rx) = smol::channel::unbounded();
|
||||
|
||||
let (client, remote_id): (AnyProtoClient, _) = if let Some(ssh_client) = &self.ssh_client {
|
||||
(ssh_client.to_proto_client(), 0)
|
||||
(ssh_client.read(cx).to_proto_client(), 0)
|
||||
} else if let Some(remote_id) = self.remote_id() {
|
||||
(self.client.clone().into(), remote_id)
|
||||
} else {
|
||||
|
@ -2973,12 +2987,14 @@ impl Project {
|
|||
exists.then(|| ResolvedPath::AbsPath(expanded))
|
||||
})
|
||||
} else if let Some(ssh_client) = self.ssh_client.as_ref() {
|
||||
let request = ssh_client
|
||||
.to_proto_client()
|
||||
.request(proto::CheckFileExists {
|
||||
project_id: SSH_PROJECT_ID,
|
||||
path: path.to_string(),
|
||||
});
|
||||
let request =
|
||||
ssh_client
|
||||
.read(cx)
|
||||
.to_proto_client()
|
||||
.request(proto::CheckFileExists {
|
||||
project_id: SSH_PROJECT_ID,
|
||||
path: path.to_string(),
|
||||
});
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = request.await.log_err()?;
|
||||
if response.exists {
|
||||
|
@ -3054,7 +3070,7 @@ impl Project {
|
|||
path: query,
|
||||
};
|
||||
|
||||
let response = session.to_proto_client().request(request);
|
||||
let response = session.read(cx).to_proto_client().request(request);
|
||||
cx.background_executor().spawn(async move {
|
||||
let response = response.await?;
|
||||
Ok(response.entries.into_iter().map(PathBuf::from).collect())
|
||||
|
@ -3482,7 +3498,7 @@ impl Project {
|
|||
let mut payload = envelope.payload.clone();
|
||||
payload.project_id = 0;
|
||||
cx.background_executor()
|
||||
.spawn(ssh.to_proto_client().request(payload))
|
||||
.spawn(ssh.read(cx).to_proto_client().request(payload))
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
this.buffer_store.clone()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue