Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,9 @@ pub enum Event {
},
RemoteIdChanged(Option<u64>),
DisconnectedFromHost,
DisconnectedFromRemote,
DisconnectedFromRemote {
server_not_running: bool,
},
Closed,
DeletedEntry(WorktreeId, ProjectEntryId),
CollaboratorUpdated {
Expand Down Expand Up @@ -3321,7 +3323,7 @@ impl Project {
cx: &mut Context<Self>,
) {
match event {
remote::RemoteClientEvent::Disconnected => {
&remote::RemoteClientEvent::Disconnected { server_not_running } => {
self.worktree_store.update(cx, |store, cx| {
store.disconnected_from_host(cx);
});
Expand All @@ -3331,7 +3333,7 @@ impl Project {
self.lsp_store.update(cx, |lsp_store, _cx| {
lsp_store.disconnected_from_ssh_remote()
});
cx.emit(Event::DisconnectedFromRemote);
cx.emit(Event::DisconnectedFromRemote { server_not_running });
}
}
}
Expand Down
29 changes: 21 additions & 8 deletions crates/recent_projects/src/disconnected_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::open_remote_project;

enum Host {
CollabGuestProject,
RemoteServerProject(RemoteConnectionOptions),
RemoteServerProject(RemoteConnectionOptions, bool),
}

pub struct DisconnectedOverlay {
Expand Down Expand Up @@ -57,15 +57,24 @@ impl DisconnectedOverlay {
|workspace, project, event, window, cx| {
if !matches!(
event,
project::Event::DisconnectedFromHost | project::Event::DisconnectedFromRemote
project::Event::DisconnectedFromHost
| project::Event::DisconnectedFromRemote { .. }
) {
return;
}
let handle = cx.entity().downgrade();

let remote_connection_options = project.read(cx).remote_connection_options(cx);
let host = if let Some(remote_connection_options) = remote_connection_options {
Host::RemoteServerProject(remote_connection_options)
Host::RemoteServerProject(
remote_connection_options,
matches!(
event,
project::Event::DisconnectedFromRemote {
server_not_running: true
}
),
)
} else {
Host::CollabGuestProject
};
Expand All @@ -85,7 +94,7 @@ impl DisconnectedOverlay {
self.finished = true;
cx.emit(DismissEvent);

if let Host::RemoteServerProject(remote_connection_options) = &self.host {
if let Host::RemoteServerProject(remote_connection_options, _) = &self.host {
self.reconnect_to_remote_project(remote_connection_options.clone(), window, cx);
}
}
Expand Down Expand Up @@ -137,13 +146,13 @@ impl DisconnectedOverlay {

impl Render for DisconnectedOverlay {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let can_reconnect = matches!(self.host, Host::RemoteServerProject(_));
let can_reconnect = matches!(self.host, Host::RemoteServerProject(..));

let message = match &self.host {
Host::CollabGuestProject => {
"Your connection to the remote project has been lost.".to_string()
}
Host::RemoteServerProject(options) => {
Host::RemoteServerProject(options, server_not_running) => {
let autosave = if ProjectSettings::get_global(cx)
.session
.restore_unsaved_buffers
Expand All @@ -152,10 +161,14 @@ impl Render for DisconnectedOverlay {
} else {
""
};
let reason = if *server_not_running {
"process exiting unexpectedly"
} else {
"not responding"
};
format!(
"Your connection to {} has been lost.{}",
"Your connection to {} has been lost due to the server {reason}.{autosave}",
options.display_name(),
autosave
)
}
};
Expand Down
17 changes: 8 additions & 9 deletions crates/remote/src/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use thiserror::Error;

#[derive(Error, Debug)]
#[derive(Copy, Clone, Error, Debug)]
#[repr(i32)]
pub enum ProxyLaunchError {
// We're using 90 as the exit code, because 0-78 are often taken
// by shells and other conventions and >128 also has certain meanings
// in certain contexts.
#[error("Attempted reconnect, but server not running.")]
ServerNotRunning,
ServerNotRunning = 90,
}

impl ProxyLaunchError {
pub fn to_exit_code(&self) -> i32 {
match self {
// We're using 90 as the exit code, because 0-78 are often taken
// by shells and other conventions and >128 also has certain meanings
// in certain contexts.
Self::ServerNotRunning => 90,
}
pub fn to_exit_code(self) -> i32 {
self as i32
}

pub fn from_exit_code(exit_code: i32) -> Option<Self> {
Expand Down
6 changes: 4 additions & 2 deletions crates/remote/src/remote_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ pub struct RemoteClient {

#[derive(Debug)]
pub enum RemoteClientEvent {
Disconnected,
Disconnected { server_not_running: bool },
}

impl EventEmitter<RemoteClientEvent> for RemoteClient {}
Expand Down Expand Up @@ -881,7 +881,9 @@ impl RemoteClient {
self.state.replace(state);

if is_reconnect_exhausted || is_server_not_running {
cx.emit(RemoteClientEvent::Disconnected);
cx.emit(RemoteClientEvent::Disconnected {
server_not_running: is_server_not_running,
});
}
cx.notify();
}
Expand Down
12 changes: 8 additions & 4 deletions crates/remote/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,14 @@ fn handle_rpc_messages_over_child_process_stdio(
result.context("stderr")
}
};
let status = remote_proxy_process.status().await?.code().unwrap_or(1);
if status != 0 {
anyhow::bail!("Remote server exited with status {status}");
}
let exit_status = remote_proxy_process.status().await?;
let status = exit_status.code().unwrap_or_else(|| {
#[cfg(unix)]
let status = std::os::unix::process::ExitStatusExt::signal(&exit_status).unwrap_or(1);
#[cfg(not(unix))]
let status = 1;
status
});
match result {
Ok(_) => Ok(status),
Err(error) => Err(error),
Expand Down
15 changes: 14 additions & 1 deletion crates/remote_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,20 @@ fn main() -> anyhow::Result<()> {

#[cfg(not(windows))]
if let Some(command) = cli.command {
remote_server::run(command)
use remote_server::unix::ExecuteProxyError;

let res = remote_server::run(command);
if let Err(e) = &res
&& let Some(e) = e.downcast_ref::<ExecuteProxyError>()
{
eprintln!("{e:#}");
// It is important for us to report the proxy spawn exit code here
// instead of the generic 1 that result returns
// The client reads the exit code to determine if the server process has died when trying to reconnect
// signaling that it needs to try spawning a new server
std::process::exit(e.to_exit_code());
}
res
} else {
eprintln!("usage: remote <run|proxy|version>");
std::process::exit(1);
Expand Down
Loading