Remoting: Fix connecting to servers with long hostnames (#20093)
Closes #20018 Release Notes: - Remoting: Fixed connecting to hosts with long (>~50 character) hostnames
This commit is contained in:
parent
273173ec8a
commit
b5c38e9a09
7 changed files with 50 additions and 34 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -14765,7 +14765,6 @@ dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"postage",
|
"postage",
|
||||||
"project",
|
"project",
|
||||||
"release_channel",
|
|
||||||
"remote",
|
"remote",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -16,6 +16,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use picker::Picker;
|
use picker::Picker;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
|
use remote::ssh_session::ConnectionIdentifier;
|
||||||
use remote::SshConnectionOptions;
|
use remote::SshConnectionOptions;
|
||||||
use remote::SshRemoteClient;
|
use remote::SshRemoteClient;
|
||||||
use settings::update_settings_file;
|
use settings::update_settings_file;
|
||||||
|
@ -384,7 +385,7 @@ impl RemoteServerProjects {
|
||||||
let ssh_prompt = cx.new_view(|cx| SshPrompt::new(&connection_options, cx));
|
let ssh_prompt = cx.new_view(|cx| SshPrompt::new(&connection_options, cx));
|
||||||
|
|
||||||
let connection = connect_over_ssh(
|
let connection = connect_over_ssh(
|
||||||
connection_options.remote_server_identifier(),
|
ConnectionIdentifier::Setup,
|
||||||
connection_options.clone(),
|
connection_options.clone(),
|
||||||
ssh_prompt.clone(),
|
ssh_prompt.clone(),
|
||||||
cx,
|
cx,
|
||||||
|
@ -475,7 +476,7 @@ impl RemoteServerProjects {
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let connect = connect_over_ssh(
|
let connect = connect_over_ssh(
|
||||||
connection_options.remote_server_identifier(),
|
ConnectionIdentifier::Setup,
|
||||||
connection_options.clone(),
|
connection_options.clone(),
|
||||||
prompt,
|
prompt,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -14,6 +14,7 @@ use gpui::{AppContext, Model};
|
||||||
use language::CursorShape;
|
use language::CursorShape;
|
||||||
use markdown::{Markdown, MarkdownStyle};
|
use markdown::{Markdown, MarkdownStyle};
|
||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
|
use remote::ssh_session::ConnectionIdentifier;
|
||||||
use remote::{SshConnectionOptions, SshPlatform, SshRemoteClient};
|
use remote::{SshConnectionOptions, SshPlatform, SshRemoteClient};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -534,7 +535,7 @@ pub fn is_connecting_over_ssh(workspace: &Workspace, cx: &AppContext) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_over_ssh(
|
pub fn connect_over_ssh(
|
||||||
unique_identifier: String,
|
unique_identifier: ConnectionIdentifier,
|
||||||
connection_options: SshConnectionOptions,
|
connection_options: SshConnectionOptions,
|
||||||
ui: View<SshPrompt>,
|
ui: View<SshPrompt>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
|
|
@ -202,17 +202,6 @@ impl SshConnectionOptions {
|
||||||
host
|
host
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniquely identifies dev server projects on a remote host. Needs to be
|
|
||||||
// stable for the same dev server project.
|
|
||||||
pub fn remote_server_identifier(&self) -> String {
|
|
||||||
let mut identifier = format!("dev-server-{:?}", self.host);
|
|
||||||
if let Some(username) = self.username.as_ref() {
|
|
||||||
identifier.push('-');
|
|
||||||
identifier.push_str(&username);
|
|
||||||
}
|
|
||||||
identifier
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -520,14 +509,43 @@ pub enum SshRemoteEvent {
|
||||||
|
|
||||||
impl EventEmitter<SshRemoteEvent> for SshRemoteClient {}
|
impl EventEmitter<SshRemoteEvent> for SshRemoteClient {}
|
||||||
|
|
||||||
|
// Identifies the socket on the remote server so that reconnects
|
||||||
|
// can re-join the same project.
|
||||||
|
pub enum ConnectionIdentifier {
|
||||||
|
Setup,
|
||||||
|
Workspace(i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionIdentifier {
|
||||||
|
// This string gets used in a socket name, and so must be relatively short.
|
||||||
|
// The total length of:
|
||||||
|
// /home/{username}/.local/share/zed/server_state/{name}/stdout.sock
|
||||||
|
// Must be less than about 100 characters
|
||||||
|
// https://unix.stackexchange.com/questions/367008/why-is-socket-path-length-limited-to-a-hundred-chars
|
||||||
|
// So our strings should be at most 20 characters or so.
|
||||||
|
fn to_string(&self, cx: &AppContext) -> String {
|
||||||
|
let identifier_prefix = match ReleaseChannel::global(cx) {
|
||||||
|
ReleaseChannel::Stable => "".to_string(),
|
||||||
|
release_channel => format!("{}-", release_channel.dev_name()),
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
Self::Setup => format!("{identifier_prefix}setup"),
|
||||||
|
Self::Workspace(workspace_id) => {
|
||||||
|
format!("{identifier_prefix}workspace-{workspace_id}",)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SshRemoteClient {
|
impl SshRemoteClient {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
unique_identifier: String,
|
unique_identifier: ConnectionIdentifier,
|
||||||
connection_options: SshConnectionOptions,
|
connection_options: SshConnectionOptions,
|
||||||
cancellation: oneshot::Receiver<()>,
|
cancellation: oneshot::Receiver<()>,
|
||||||
delegate: Arc<dyn SshClientDelegate>,
|
delegate: Arc<dyn SshClientDelegate>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<Result<Option<Model<Self>>>> {
|
) -> Task<Result<Option<Model<Self>>>> {
|
||||||
|
let unique_identifier = unique_identifier.to_string(cx);
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
let success = Box::pin(async move {
|
let success = Box::pin(async move {
|
||||||
let (outgoing_tx, outgoing_rx) = mpsc::unbounded::<Envelope>();
|
let (outgoing_tx, outgoing_rx) = mpsc::unbounded::<Envelope>();
|
||||||
|
@ -1096,7 +1114,15 @@ impl SshRemoteClient {
|
||||||
) -> Model<Self> {
|
) -> Model<Self> {
|
||||||
let (_tx, rx) = oneshot::channel();
|
let (_tx, rx) = oneshot::channel();
|
||||||
client_cx
|
client_cx
|
||||||
.update(|cx| Self::new("fake".to_string(), opts, rx, Arc::new(fake::Delegate), cx))
|
.update(|cx| {
|
||||||
|
Self::new(
|
||||||
|
ConnectionIdentifier::Setup,
|
||||||
|
opts,
|
||||||
|
rx,
|
||||||
|
Arc::new(fake::Delegate),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::headless_project::HeadlessProject;
|
||||||
use client::{Client, UserStore};
|
use client::{Client, UserStore};
|
||||||
use clock::FakeSystemClock;
|
use clock::FakeSystemClock;
|
||||||
use fs::{FakeFs, Fs};
|
use fs::{FakeFs, Fs};
|
||||||
use gpui::{Context, Model, TestAppContext};
|
use gpui::{Context, Model, SemanticVersion, TestAppContext};
|
||||||
use http_client::{BlockedHttpClient, FakeHttpClient};
|
use http_client::{BlockedHttpClient, FakeHttpClient};
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::{language_settings, AllLanguageSettings},
|
language_settings::{language_settings, AllLanguageSettings},
|
||||||
|
@ -1184,6 +1184,9 @@ pub async fn init_test(
|
||||||
server_cx: &mut TestAppContext,
|
server_cx: &mut TestAppContext,
|
||||||
) -> (Model<Project>, Model<HeadlessProject>) {
|
) -> (Model<Project>, Model<HeadlessProject>) {
|
||||||
let server_fs = server_fs.clone();
|
let server_fs = server_fs.clone();
|
||||||
|
cx.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
init_logger();
|
init_logger();
|
||||||
|
|
||||||
let (opts, ssh_server_client) = SshRemoteClient::fake_server(cx, server_cx);
|
let (opts, ssh_server_client) = SshRemoteClient::fake_server(cx, server_cx);
|
||||||
|
|
|
@ -49,7 +49,6 @@ parking_lot.workspace = true
|
||||||
postage.workspace = true
|
postage.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
task.workspace = true
|
task.workspace = true
|
||||||
release_channel.workspace = true
|
|
||||||
remote.workspace = true
|
remote.workspace = true
|
||||||
schemars.workspace = true
|
schemars.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|
|
@ -64,8 +64,7 @@ use postage::stream::Stream;
|
||||||
use project::{
|
use project::{
|
||||||
DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId,
|
DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId,
|
||||||
};
|
};
|
||||||
use release_channel::ReleaseChannel;
|
use remote::{ssh_session::ConnectionIdentifier, SshClientDelegate, SshConnectionOptions};
|
||||||
use remote::{SshClientDelegate, SshConnectionOptions};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use session::AppSession;
|
use session::AppSession;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
@ -5496,26 +5495,14 @@ pub fn open_ssh_project(
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let release_channel = ReleaseChannel::global(cx);
|
|
||||||
|
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
let (serialized_ssh_project, workspace_id, serialized_workspace) =
|
let (serialized_ssh_project, workspace_id, serialized_workspace) =
|
||||||
serialize_ssh_project(connection_options.clone(), paths.clone(), &cx).await?;
|
serialize_ssh_project(connection_options.clone(), paths.clone(), &cx).await?;
|
||||||
|
|
||||||
let identifier_prefix = match release_channel {
|
|
||||||
ReleaseChannel::Stable => None,
|
|
||||||
_ => Some(format!("{}-", release_channel.dev_name())),
|
|
||||||
};
|
|
||||||
let unique_identifier = format!(
|
|
||||||
"{}workspace-{}",
|
|
||||||
identifier_prefix.unwrap_or_default(),
|
|
||||||
workspace_id.0
|
|
||||||
);
|
|
||||||
|
|
||||||
let session = match cx
|
let session = match cx
|
||||||
.update(|cx| {
|
.update(|cx| {
|
||||||
remote::SshRemoteClient::new(
|
remote::SshRemoteClient::new(
|
||||||
unique_identifier,
|
ConnectionIdentifier::Workspace(workspace_id.0),
|
||||||
connection_options,
|
connection_options,
|
||||||
cancel_rx,
|
cancel_rx,
|
||||||
delegate,
|
delegate,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue