ssh remoting: Add infrastructure to handle reconnects (#18572)

This restructures the code in `remote` so that it's easier to replace
the current SSH connection with a new one in case of
disconnects/reconnects.

Right now, it successfully reconnects, BUT we're still missing the big
piece on the server-side: keeping the server process alive and
reconnecting to the same process that keeps the project-state.

Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-10-01 12:16:44 +02:00 committed by GitHub
parent 527c9097f8
commit 7ce8797d78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 562 additions and 401 deletions

View file

@ -10,7 +10,7 @@ use project::{
worktree_store::WorktreeStore,
LspStore, LspStoreEvent, PrettierStore, ProjectPath, WorktreeId,
};
use remote::SshSession;
use remote::ssh_session::ChannelClient;
use rpc::{
proto::{self, SSH_PEER_ID, SSH_PROJECT_ID},
AnyProtoClient, TypedEnvelope,
@ -41,7 +41,7 @@ impl HeadlessProject {
project::Project::init_settings(cx);
}
pub fn new(session: Arc<SshSession>, fs: Arc<dyn Fs>, cx: &mut ModelContext<Self>) -> Self {
pub fn new(session: Arc<ChannelClient>, fs: Arc<dyn Fs>, cx: &mut ModelContext<Self>) -> Self {
let languages = Arc::new(LanguageRegistry::new(cx.background_executor().clone()));
let node_runtime = NodeRuntime::unavailable();

View file

@ -6,7 +6,6 @@ use gpui::Context as _;
use remote::{
json_log::LogRecord,
protocol::{read_message, write_message},
SshSession,
};
use remote_server::HeadlessProject;
use smol::{io::AsyncWriteExt, stream::StreamExt as _, Async};
@ -24,6 +23,8 @@ fn main() {
#[cfg(not(windows))]
fn main() {
use remote::ssh_session::ChannelClient;
env_logger::builder()
.format(|buf, record| {
serde_json::to_writer(&mut *buf, &LogRecord::new(record))?;
@ -55,7 +56,7 @@ fn main() {
let mut stdin = Async::new(io::stdin()).unwrap();
let mut stdout = Async::new(io::stdout()).unwrap();
let session = SshSession::server(incoming_rx, outgoing_tx, cx);
let session = ChannelClient::new(incoming_rx, outgoing_tx, cx);
let project = cx.new_model(|cx| {
HeadlessProject::new(
session.clone(),

View file

@ -15,7 +15,7 @@ use project::{
search::{SearchQuery, SearchResult},
Project, ProjectPath,
};
use remote::SshSession;
use remote::SshRemoteClient;
use serde_json::json;
use settings::{Settings, SettingsLocation, SettingsStore};
use smol::stream::StreamExt;
@ -616,7 +616,7 @@ async fn init_test(
cx: &mut TestAppContext,
server_cx: &mut TestAppContext,
) -> (Model<Project>, Model<HeadlessProject>, Arc<FakeFs>) {
let (client_ssh, server_ssh) = SshSession::fake(cx, server_cx);
let (ssh_remote_client, ssh_server_client) = SshRemoteClient::fake(cx, server_cx);
init_logger();
let fs = FakeFs::new(server_cx.executor());
@ -642,8 +642,9 @@ async fn init_test(
);
server_cx.update(HeadlessProject::init);
let headless = server_cx.new_model(|cx| HeadlessProject::new(server_ssh, fs.clone(), cx));
let project = build_project(client_ssh, cx);
let headless =
server_cx.new_model(|cx| HeadlessProject::new(ssh_server_client, fs.clone(), cx));
let project = build_project(ssh_remote_client, cx);
project
.update(cx, {
@ -654,7 +655,7 @@ async fn init_test(
(project, headless, fs)
}
fn build_project(ssh: Arc<SshSession>, cx: &mut TestAppContext) -> Model<Project> {
fn build_project(ssh: Arc<SshRemoteClient>, cx: &mut TestAppContext) -> Model<Project> {
cx.update(|cx| {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);