mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +03:00
gui: allow wezterm connect sshdomnomux
If an ssh domain is set to use_multiplexer=false, it is now possible to `wezterm connect` to it. Previously, it was only possible to connect to domains that used the mux client. refs: https://github.com/wez/wezterm/issues/1456
This commit is contained in:
parent
0676eed42f
commit
f84c0632d8
@ -7,6 +7,7 @@ use crate::window::WindowId;
|
||||
use crate::Mux;
|
||||
use anyhow::{anyhow, bail, Context, Error};
|
||||
use async_trait::async_trait;
|
||||
use config::{SshBackend, SshDomain};
|
||||
use filedescriptor::{poll, pollfd, socketpair, AsRawSocketDescriptor, FileDescriptor, POLLIN};
|
||||
use portable_pty::cmdbuilder::CommandBuilder;
|
||||
use portable_pty::{ChildKiller, ExitStatus, MasterPty, PtySize};
|
||||
@ -134,11 +135,58 @@ pub fn ssh_connect_with_ui(
|
||||
/// interactive setup. The bulk of that is driven by `connect_ssh_session`.
|
||||
pub struct RemoteSshDomain {
|
||||
session: RefCell<Option<Session>>,
|
||||
ssh_config: ConfigMap,
|
||||
config: RemoteSshConfig,
|
||||
id: DomainId,
|
||||
name: String,
|
||||
}
|
||||
|
||||
enum RemoteSshConfig {
|
||||
AdHoc(ConfigMap),
|
||||
Domain(SshDomain),
|
||||
}
|
||||
|
||||
pub fn ssh_domain_to_ssh_config(ssh_dom: &SshDomain) -> anyhow::Result<ConfigMap> {
|
||||
let mut ssh_config = wezterm_ssh::Config::new();
|
||||
ssh_config.add_default_config_files();
|
||||
|
||||
let (remote_host_name, port) = {
|
||||
let parts: Vec<&str> = ssh_dom.remote_address.split(':').collect();
|
||||
|
||||
if parts.len() == 2 {
|
||||
(parts[0], Some(parts[1].parse::<u16>()?))
|
||||
} else {
|
||||
(ssh_dom.remote_address.as_str(), None)
|
||||
}
|
||||
};
|
||||
|
||||
let mut ssh_config = ssh_config.for_host(&remote_host_name);
|
||||
ssh_config.insert(
|
||||
"wezterm_ssh_backend".to_string(),
|
||||
match ssh_dom
|
||||
.ssh_backend
|
||||
.unwrap_or_else(|| config::configuration().ssh_backend)
|
||||
{
|
||||
SshBackend::Ssh2 => "ssh2",
|
||||
SshBackend::LibSsh => "libssh",
|
||||
}
|
||||
.to_string(),
|
||||
);
|
||||
for (k, v) in &ssh_dom.ssh_option {
|
||||
ssh_config.insert(k.to_string(), v.to_string());
|
||||
}
|
||||
|
||||
if let Some(username) = &ssh_dom.username {
|
||||
ssh_config.insert("user".to_string(), username.to_string());
|
||||
}
|
||||
if let Some(port) = port {
|
||||
ssh_config.insert("port".to_string(), port.to_string());
|
||||
}
|
||||
if ssh_dom.no_agent_auth {
|
||||
ssh_config.insert("identitiesonly".to_string(), "yes".to_string());
|
||||
}
|
||||
Ok(ssh_config)
|
||||
}
|
||||
|
||||
impl RemoteSshDomain {
|
||||
pub fn with_ssh_config(name: &str, ssh_config: ConfigMap) -> anyhow::Result<Self> {
|
||||
let id = alloc_domain_id();
|
||||
@ -146,9 +194,26 @@ impl RemoteSshDomain {
|
||||
id,
|
||||
name: format!("SSH to {}", name),
|
||||
session: RefCell::new(None),
|
||||
ssh_config,
|
||||
config: RemoteSshConfig::AdHoc(ssh_config),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_ssh_domain(dom: &SshDomain) -> anyhow::Result<Self> {
|
||||
let id = alloc_domain_id();
|
||||
Ok(Self {
|
||||
id,
|
||||
name: dom.name.clone(),
|
||||
session: RefCell::new(None),
|
||||
config: RemoteSshConfig::Domain(dom.clone()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ssh_config(&self) -> anyhow::Result<ConfigMap> {
|
||||
match &self.config {
|
||||
RemoteSshConfig::AdHoc(config) => Ok(config.clone()),
|
||||
RemoteSshConfig::Domain(dom) => ssh_domain_to_ssh_config(dom),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Carry out the authentication process and create the initial pty.
|
||||
@ -475,7 +540,7 @@ impl Domain for RemoteSshDomain {
|
||||
writer = Box::new(pty.try_clone_writer()?);
|
||||
} else {
|
||||
// We're starting the session
|
||||
let (session, events) = Session::connect(self.ssh_config.clone())?;
|
||||
let (session, events) = Session::connect(self.ssh_config()?)?;
|
||||
self.session.borrow_mut().replace(session.clone());
|
||||
|
||||
// We get to establish the session!
|
||||
@ -682,11 +747,10 @@ impl Domain for RemoteSshDomain {
|
||||
}
|
||||
|
||||
fn state(&self) -> DomainState {
|
||||
if self.session.borrow().is_some() {
|
||||
DomainState::Attached
|
||||
} else {
|
||||
DomainState::Detached
|
||||
}
|
||||
// Just pretend that we are always attached, as we don't
|
||||
// have a defined attach operation that is distinct from
|
||||
// a spawn.
|
||||
DomainState::Attached
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use anyhow::{anyhow, bail, Context};
|
||||
use async_ossl::AsyncSslStream;
|
||||
use async_trait::async_trait;
|
||||
use codec::*;
|
||||
use config::{configuration, SshBackend, SshDomain, TlsDomainClient, UnixDomain, UnixTarget};
|
||||
use config::{configuration, SshDomain, TlsDomainClient, UnixDomain, UnixTarget};
|
||||
use filedescriptor::FileDescriptor;
|
||||
use futures::FutureExt;
|
||||
use mux::connui::ConnectionUI;
|
||||
@ -502,44 +502,7 @@ impl Reconnectable {
|
||||
initial: bool,
|
||||
ui: &mut ConnectionUI,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut ssh_config = wezterm_ssh::Config::new();
|
||||
ssh_config.add_default_config_files();
|
||||
|
||||
let (remote_host_name, port) = {
|
||||
let parts: Vec<&str> = ssh_dom.remote_address.split(':').collect();
|
||||
|
||||
if parts.len() == 2 {
|
||||
(parts[0], Some(parts[1].parse::<u16>()?))
|
||||
} else {
|
||||
(ssh_dom.remote_address.as_str(), None)
|
||||
}
|
||||
};
|
||||
|
||||
let mut ssh_config = ssh_config.for_host(&remote_host_name);
|
||||
ssh_config.insert(
|
||||
"wezterm_ssh_backend".to_string(),
|
||||
match ssh_dom
|
||||
.ssh_backend
|
||||
.unwrap_or_else(|| configuration().ssh_backend)
|
||||
{
|
||||
SshBackend::Ssh2 => "ssh2",
|
||||
SshBackend::LibSsh => "libssh",
|
||||
}
|
||||
.to_string(),
|
||||
);
|
||||
for (k, v) in &ssh_dom.ssh_option {
|
||||
ssh_config.insert(k.to_string(), v.to_string());
|
||||
}
|
||||
|
||||
if let Some(username) = &ssh_dom.username {
|
||||
ssh_config.insert("user".to_string(), username.to_string());
|
||||
}
|
||||
if let Some(port) = port {
|
||||
ssh_config.insert("port".to_string(), port.to_string());
|
||||
}
|
||||
if ssh_dom.no_agent_auth {
|
||||
ssh_config.insert("identitiesonly".to_string(), "yes".to_string());
|
||||
}
|
||||
let ssh_config = mux::ssh::ssh_domain_to_ssh_config(&ssh_dom)?;
|
||||
|
||||
let sess = ssh_connect_with_ui(ssh_config, ui)?;
|
||||
let proxy_bin = Self::wezterm_bin_path(&ssh_dom.remote_wezterm_path);
|
||||
|
@ -6,6 +6,7 @@ use anyhow::{anyhow, Context};
|
||||
use config::{ConfigHandle, SshBackend};
|
||||
use mux::activity::Activity;
|
||||
use mux::domain::{Domain, LocalDomain};
|
||||
use mux::ssh::RemoteSshDomain;
|
||||
use mux::Mux;
|
||||
use portable_pty::cmdbuilder::CommandBuilder;
|
||||
use promise::spawn::block_on;
|
||||
@ -240,17 +241,14 @@ async fn async_run_with_domain_as_default(
|
||||
spawn_tab_in_default_domain_if_mux_is_empty(cmd).await
|
||||
}
|
||||
|
||||
async fn async_run_mux_client(
|
||||
config: config::ConfigHandle,
|
||||
opts: ConnectCommand,
|
||||
) -> anyhow::Result<()> {
|
||||
async fn async_run_mux_client(opts: ConnectCommand) -> anyhow::Result<()> {
|
||||
if let Some(cls) = opts.class.as_ref() {
|
||||
crate::set_window_class(cls);
|
||||
}
|
||||
|
||||
let client_config = client_domains(&config)
|
||||
.into_iter()
|
||||
.find(|c| c.name() == opts.domain_name)
|
||||
let domain = Mux::get()
|
||||
.unwrap()
|
||||
.get_domain_by_name(&opts.domain_name)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"no multiplexer domain with name `{}` was found in the configuration",
|
||||
@ -258,7 +256,6 @@ async fn async_run_mux_client(
|
||||
)
|
||||
})?;
|
||||
|
||||
let domain: Arc<dyn Domain> = Arc::new(ClientDomain::new(client_config));
|
||||
let opts = opts.clone();
|
||||
let cmd = if !opts.prog.is_empty() {
|
||||
let builder = CommandBuilder::from_argv(opts.prog);
|
||||
@ -270,12 +267,12 @@ async fn async_run_mux_client(
|
||||
async_run_with_domain_as_default(domain, cmd).await
|
||||
}
|
||||
|
||||
fn run_mux_client(config: config::ConfigHandle, opts: ConnectCommand) -> anyhow::Result<()> {
|
||||
fn run_mux_client(opts: ConnectCommand) -> anyhow::Result<()> {
|
||||
let activity = Activity::new();
|
||||
build_initial_mux(&config::configuration(), None)?;
|
||||
let gui = crate::frontend::try_new()?;
|
||||
promise::spawn::spawn(async {
|
||||
if let Err(err) = async_run_mux_client(config, opts).await {
|
||||
if let Err(err) = async_run_mux_client(opts).await {
|
||||
terminate_with_error(err);
|
||||
}
|
||||
drop(activity);
|
||||
@ -327,18 +324,26 @@ async fn spawn_tab_in_default_domain_if_mux_is_empty(
|
||||
fn update_mux_domains(config: &ConfigHandle) -> anyhow::Result<()> {
|
||||
let mux = Mux::get().unwrap();
|
||||
|
||||
fn record_domain(mux: &Rc<Mux>, client: ClientDomain) -> anyhow::Result<Arc<dyn Domain>> {
|
||||
if let Some(domain) = mux.get_domain_by_name(client.domain_name()) {
|
||||
Ok(domain)
|
||||
} else {
|
||||
let domain: Arc<dyn Domain> = Arc::new(client);
|
||||
mux.add_domain(&domain);
|
||||
Ok(domain)
|
||||
for client_config in client_domains(&config) {
|
||||
if mux.get_domain_by_name(client_config.name()).is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let domain: Arc<dyn Domain> = Arc::new(ClientDomain::new(client_config));
|
||||
mux.add_domain(&domain);
|
||||
}
|
||||
|
||||
for client_config in client_domains(&config) {
|
||||
record_domain(&mux, ClientDomain::new(client_config))?;
|
||||
for ssh_dom in &config.ssh_domains {
|
||||
if ssh_dom.use_multiplexer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if mux.get_domain_by_name(&ssh_dom.name).is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let domain: Arc<dyn Domain> = Arc::new(RemoteSshDomain::with_ssh_domain(&ssh_dom)?);
|
||||
mux.add_domain(&domain);
|
||||
}
|
||||
|
||||
for wsl_dom in &config.wsl_domains {
|
||||
@ -860,7 +865,7 @@ fn run() -> anyhow::Result<()> {
|
||||
}
|
||||
SubCommand::Ssh(ssh) => run_ssh(ssh),
|
||||
SubCommand::Serial(serial) => run_serial(config, &serial),
|
||||
SubCommand::Connect(connect) => run_mux_client(config, connect),
|
||||
SubCommand::Connect(connect) => run_mux_client(connect),
|
||||
SubCommand::LsFonts(cmd) => run_ls_fonts(config, &cmd),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user