Add reconnection logic to remote server (#9289)
Migrated from /Users/kevinyang/Documents/GitHub/warp-internal via `script/migrate-private-to-public`. ## Commits - 823458b Add reconnect logic to remote server - 104aafb tech spec - c4039c3 clippy - c4e3a39 nit
This commit is contained in:
@@ -36,6 +36,9 @@ use crate::server::telemetry::{BootstrappingInfo, TelemetryEvent};
|
||||
use crate::terminal::event::ExecutedExecutorCommandEvent;
|
||||
use crate::terminal::ShellHost;
|
||||
use crate::terminal::ShellLaunchData;
|
||||
#[cfg(feature = "local_tty")]
|
||||
use command_executor::remote_server_executor::RemoteServerCommandExecutor;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
use crate::terminal::shell::{Shell, ShellType};
|
||||
use crate::terminal::warpify::SubshellSource;
|
||||
@@ -172,6 +175,18 @@ impl Sessions {
|
||||
| RemoteServerManagerEvent::BinaryInstallComplete { .. }
|
||||
| RemoteServerManagerEvent::ClientRequestFailed { .. }
|
||||
| RemoteServerManagerEvent::ServerMessageDecodingError { .. } => {}
|
||||
RemoteServerManagerEvent::SessionReconnected {
|
||||
session_id: sid,
|
||||
client,
|
||||
..
|
||||
} => {
|
||||
if let Some(session) = sessions.sessions.get(sid) {
|
||||
let new_executor =
|
||||
Arc::new(RemoteServerCommandExecutor::new(*sid, client.clone()));
|
||||
session.set_command_executor(new_executor);
|
||||
log::info!("Swapped command executor for session {sid:?} after reconnect");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#[cfg(not(feature = "local_tty"))]
|
||||
@@ -847,14 +862,16 @@ impl From<BootstrapSessionType> for SessionType {
|
||||
pub struct Session {
|
||||
info: SessionInfo,
|
||||
external_commands: Arc<OnceCell<HashSet<SmolStr>>>,
|
||||
command_executor: Arc<dyn CommandExecutor>,
|
||||
/// The command executor for this session. Behind a `RwLock` so it can be
|
||||
/// swapped after a remote server reconnect (via `set_command_executor`).
|
||||
command_executor: RwLock<Arc<dyn CommandExecutor>>,
|
||||
load_external_commands_future: OnceCell<Shared<BoxFuture<'static, ()>>>,
|
||||
command_case_sensitivity: TopLevelCommandCaseSensitivity,
|
||||
/// The authoritative session type, initially derived from the
|
||||
/// [`BootstrapSessionType`] in `SessionInfo` and updated by [`Sessions`]
|
||||
/// when `RemoteServerManager` reports a connected session (to fill in the
|
||||
/// `host_id`). Interior mutability allows updating through `Arc<Session>`.
|
||||
session_type: parking_lot::Mutex<SessionType>,
|
||||
session_type: Mutex<SessionType>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
@@ -873,10 +890,10 @@ impl Session {
|
||||
Self {
|
||||
info: session_info,
|
||||
external_commands: Arc::new(OnceCell::new()),
|
||||
command_executor,
|
||||
command_executor: RwLock::new(command_executor),
|
||||
load_external_commands_future: Default::default(),
|
||||
command_case_sensitivity,
|
||||
session_type: parking_lot::Mutex::new(session_type),
|
||||
session_type: Mutex::new(session_type),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,9 +1042,17 @@ impl Session {
|
||||
&self.info.subshell_info
|
||||
}
|
||||
|
||||
/// Replaces the command executor for this session. Used after a remote
|
||||
/// server reconnect to swap in a new `RemoteServerCommandExecutor`
|
||||
/// backed by the reconnected client.
|
||||
pub fn set_command_executor(&self, executor: Arc<dyn CommandExecutor>) {
|
||||
*self.command_executor.write() = executor;
|
||||
}
|
||||
|
||||
/// Returns true if the session is employing in-band command execution to run generators.
|
||||
pub fn is_using_in_band_command_execution(&self) -> bool {
|
||||
self.command_executor
|
||||
.read()
|
||||
.as_ref()
|
||||
.as_any()
|
||||
.downcast_ref::<InBandCommandExecutor>()
|
||||
@@ -1089,8 +1114,8 @@ impl Session {
|
||||
.path
|
||||
.as_deref()
|
||||
.map(|path| HashMap::from_iter([("PATH".to_string(), path.to_string())]));
|
||||
let windows_results = self
|
||||
.command_executor
|
||||
let executor = self.command_executor.read().clone();
|
||||
let windows_results = executor
|
||||
.execute_command(
|
||||
ShellType::PowerShell.shell_command_to_get_executables(),
|
||||
&Shell::new(ShellType::PowerShell, None, None, Default::default(), None),
|
||||
@@ -1381,7 +1406,10 @@ impl Session {
|
||||
environment_variables: Option<HashMap<String, String>>,
|
||||
execute_command_options: ExecuteCommandOptions,
|
||||
) -> Result<CommandOutput> {
|
||||
self.command_executor
|
||||
// Clone the Arc out of the lock so we don't hold the read guard
|
||||
// across the await point.
|
||||
let executor = self.command_executor.read().clone();
|
||||
executor
|
||||
.execute_command(
|
||||
command,
|
||||
&self.info.shell,
|
||||
@@ -1394,11 +1422,13 @@ impl Session {
|
||||
|
||||
/// Whether the backing executor for the session supports execution of commands in parallel.
|
||||
pub fn supports_parallel_command_execution(&self) -> bool {
|
||||
self.command_executor.supports_parallel_command_execution()
|
||||
self.command_executor
|
||||
.read()
|
||||
.supports_parallel_command_execution()
|
||||
}
|
||||
|
||||
pub fn cancel_active_commands(&self) {
|
||||
self.command_executor.cancel_active_commands();
|
||||
self.command_executor.read().cancel_active_commands();
|
||||
}
|
||||
|
||||
pub async fn git_branches_for_command_corrections(&self, working_dir: &str) -> Vec<String> {
|
||||
@@ -1644,10 +1674,10 @@ pub mod testing {
|
||||
Self {
|
||||
info,
|
||||
external_commands: Default::default(),
|
||||
command_executor: Arc::new(TestCommandExecutor::default()),
|
||||
command_executor: RwLock::new(Arc::new(TestCommandExecutor::default())),
|
||||
load_external_commands_future: Default::default(),
|
||||
command_case_sensitivity: TopLevelCommandCaseSensitivity::CaseSensitive,
|
||||
session_type: parking_lot::Mutex::new(session_type),
|
||||
session_type: Mutex::new(session_type),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1659,10 +1689,10 @@ pub mod testing {
|
||||
Self {
|
||||
info,
|
||||
external_commands: Default::default(),
|
||||
command_executor: Arc::new(TestCommandExecutor::default()),
|
||||
command_executor: RwLock::new(Arc::new(TestCommandExecutor::default())),
|
||||
load_external_commands_future: Default::default(),
|
||||
command_case_sensitivity: TopLevelCommandCaseSensitivity::CaseSensitive,
|
||||
session_type: parking_lot::Mutex::new(session_type),
|
||||
session_type: Mutex::new(session_type),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4376,6 +4376,7 @@ impl TerminalView {
|
||||
}
|
||||
}
|
||||
RemoteServerManagerEvent::SessionConnecting { .. }
|
||||
| RemoteServerManagerEvent::SessionReconnected { .. }
|
||||
| RemoteServerManagerEvent::HostConnected { .. }
|
||||
| RemoteServerManagerEvent::HostDisconnected { .. }
|
||||
| RemoteServerManagerEvent::RepoMetadataSnapshot { .. }
|
||||
|
||||
Reference in New Issue
Block a user