1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 14:22:37 +03:00

Allow deferred attach of domains

This adds some plumbing so that a domain can indicate whether it is
attached or not, but is not yet smart enough to detect a closed
connection and mark itself as detached.
This commit is contained in:
Wez Furlong 2019-06-25 08:13:06 -07:00
parent b5266078a9
commit c9489d391b
4 changed files with 107 additions and 37 deletions

View File

@ -16,10 +16,10 @@ mod opengl;
mod ratelim;
mod server;
use crate::frontend::FrontEndSelection;
use crate::mux::domain::{alloc_domain_id, Domain, LocalDomain};
use crate::mux::domain::{Domain, LocalDomain};
use crate::mux::Mux;
use crate::server::client::Client;
use crate::server::domain::ClientDomain;
use crate::server::domain::{ClientDomain, ClientDomainConfig};
use portable_pty::cmdbuilder::CommandBuilder;
mod font;
@ -171,30 +171,30 @@ fn run_terminal_gui(config: Arc<config::Config>, opts: &StartCommand) -> Fallibl
let gui = front_end.try_new(&mux)?;
domain.attach()?;
fn attach_client(mux: &Rc<Mux>, client: ClientDomain) -> Fallible<()> {
fn record_domain(mux: &Rc<Mux>, client: ClientDomain) -> Fallible<Arc<dyn Domain>> {
let domain: Arc<dyn Domain> = Arc::new(client);
mux.add_domain(&domain);
domain.attach()
Ok(domain)
}
if front_end != FrontEndSelection::MuxServer && !opts.no_auto_connect {
for unix_dom in &config.unix_domains {
let dom = record_domain(
&mux,
ClientDomain::new(ClientDomainConfig::Unix(unix_dom.clone())),
)?;
if unix_dom.connect_automatically {
let domain_id = alloc_domain_id();
attach_client(
&mux,
ClientDomain::new(Client::new_unix_domain(domain_id, &config, unix_dom)?),
)?;
dom.attach()?;
}
}
for tls_client in &config.tls_clients {
let dom = record_domain(
&mux,
ClientDomain::new(ClientDomainConfig::Tls(tls_client.clone())),
)?;
if tls_client.connect_automatically {
let domain_id = alloc_domain_id();
attach_client(
&mux,
ClientDomain::new(Client::new_tls(domain_id, &config, tls_client)?),
)?;
dom.attach()?;
}
}
}
@ -207,6 +207,10 @@ fn run_terminal_gui(config: Arc<config::Config>, opts: &StartCommand) -> Fallibl
gui.spawn_new_window(mux.config(), &fontconfig, &tab, window_id)?;
}
for dom in mux.iter_domains() {
log::error!("domain {} state {:?}", dom.domain_id(), dom.state());
}
gui.run_forever()
}

View File

@ -21,6 +21,12 @@ use std::sync::Arc;
static DOMAIN_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
pub type DomainId = usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DomainState {
Detached,
Attached,
}
pub fn alloc_domain_id() -> DomainId {
DOMAIN_ID.fetch_add(1, ::std::sync::atomic::Ordering::Relaxed)
}
@ -40,6 +46,12 @@ pub trait Domain: Downcast {
/// Re-attach to any tabs that might be pre-existing in this domain
fn attach(&self) -> Fallible<()>;
/// Detach all tabs
fn detach(&self) -> Fallible<()>;
/// Indicates the state of the domain
fn state(&self) -> DomainState;
}
impl_downcast!(Domain);
@ -105,4 +117,12 @@ impl Domain for LocalDomain {
fn attach(&self) -> Fallible<()> {
Ok(())
}
fn detach(&self) -> Fallible<()> {
failure::bail!("detach not implemented");
}
fn state(&self) -> DomainState {
DomainState::Attached
}
}

View File

@ -269,6 +269,10 @@ impl Mux {
pub fn iter_windows(&self) -> Vec<WindowId> {
self.windows.borrow().keys().cloned().collect()
}
pub fn iter_domains(&self) -> Vec<Arc<dyn Domain>> {
self.domains.borrow().values().cloned().collect()
}
}
#[derive(Debug, Fail)]

View File

@ -1,14 +1,16 @@
use crate::config::{TlsDomainClient, UnixDomain};
use crate::font::{FontConfiguration, FontSystemSelection};
use crate::frontend::front_end;
use crate::mux::domain::{Domain, DomainId};
use crate::mux::domain::{alloc_domain_id, Domain, DomainId, DomainState};
use crate::mux::tab::{Tab, TabId};
use crate::mux::window::WindowId;
use crate::mux::Mux;
use crate::server::client::Client;
use crate::server::codec::Spawn;
use crate::server::tab::ClientTab;
use failure::Fallible;
use failure::{err_msg, Fallible};
use portable_pty::{CommandBuilder, PtySize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
@ -52,13 +54,13 @@ impl ClientInner {
}
}
pub struct ClientDomain {
inner: Arc<ClientInner>,
pub enum ClientDomainConfig {
Unix(UnixDomain),
Tls(TlsDomainClient),
}
impl ClientInner {
pub fn new(client: Client) -> Self {
let local_domain_id = client.local_domain_id();
pub fn new(local_domain_id: DomainId, client: Client) -> Self {
// Assumption: that the domain id on the other end is
// always the first created default domain. In the future
// we'll add a way to discover/enumerate domains to populate
@ -74,14 +76,29 @@ impl ClientInner {
}
}
pub struct ClientDomain {
config: ClientDomainConfig,
inner: RefCell<Option<Arc<ClientInner>>>,
local_domain_id: DomainId,
}
impl ClientDomain {
pub fn new(client: Client) -> Self {
let inner = Arc::new(ClientInner::new(client));
Self { inner }
pub fn new(config: ClientDomainConfig) -> Self {
let local_domain_id = alloc_domain_id();
Self {
config,
inner: RefCell::new(None),
local_domain_id,
}
}
fn inner(&self) -> Option<Arc<ClientInner>> {
self.inner.borrow().as_ref().map(|i| Arc::clone(i))
}
pub fn remote_to_local_tab_id(&self, remote_tab_id: TabId) -> Option<TabId> {
let mut tab_map = self.inner.remote_to_local_tab.lock().unwrap();
let inner = self.inner()?;
let mut tab_map = inner.remote_to_local_tab.lock().unwrap();
if let Some(id) = tab_map.get(&remote_tab_id) {
return Some(*id);
@ -104,7 +121,7 @@ impl ClientDomain {
impl Domain for ClientDomain {
fn domain_id(&self) -> DomainId {
self.inner.local_domain_id
self.local_domain_id
}
fn spawn(
@ -113,24 +130,25 @@ impl Domain for ClientDomain {
command: Option<CommandBuilder>,
window: WindowId,
) -> Fallible<Rc<dyn Tab>> {
let inner = self
.inner()
.ok_or_else(|| err_msg("domain is not attached"))?;
let remote_tab_id = {
let result = self
.inner
let result = inner
.client
.spawn(Spawn {
domain_id: self.inner.remote_domain_id,
window_id: self.inner.local_to_remote_window(window),
domain_id: inner.remote_domain_id,
window_id: inner.local_to_remote_window(window),
size,
command,
})
.wait()?;
self.inner
.record_remote_to_local_window_mapping(result.window_id, window);
inner.record_remote_to_local_window_mapping(result.window_id, window);
result.tab_id
};
let tab: Rc<dyn Tab> = Rc::new(ClientTab::new(&self.inner, remote_tab_id, size));
let tab: Rc<dyn Tab> = Rc::new(ClientTab::new(&inner, remote_tab_id, size));
let mux = Mux::get().unwrap();
mux.add_tab(&tab)?;
mux.add_tab_to_window(&tab, window)?;
@ -140,7 +158,19 @@ impl Domain for ClientDomain {
fn attach(&self) -> Fallible<()> {
let mux = Mux::get().unwrap();
let tabs = self.inner.client.list_tabs().wait()?;
let client = match &self.config {
ClientDomainConfig::Unix(unix) => {
Client::new_unix_domain(self.local_domain_id, mux.config(), unix)?
}
ClientDomainConfig::Tls(tls) => {
Client::new_tls(self.local_domain_id, mux.config(), tls)?
}
};
let inner = Arc::new(ClientInner::new(self.local_domain_id, client));
*self.inner.borrow_mut() = Some(Arc::clone(&inner));
let tabs = inner.client.list_tabs().wait()?;
log::error!("ListTabs result {:#?}", tabs);
for entry in tabs.tabs.iter() {
@ -150,10 +180,10 @@ impl Domain for ClientDomain {
entry.window_id,
entry.title
);
let tab: Rc<dyn Tab> = Rc::new(ClientTab::new(&self.inner, entry.tab_id, entry.size));
let tab: Rc<dyn Tab> = Rc::new(ClientTab::new(&inner, entry.tab_id, entry.size));
mux.add_tab(&tab)?;
if let Some(local_window_id) = self.inner.remote_to_local_window(entry.window_id) {
if let Some(local_window_id) = inner.remote_to_local_window(entry.window_id) {
let mut window = mux
.get_window_mut(local_window_id)
.expect("no such window!?");
@ -166,8 +196,7 @@ impl Domain for ClientDomain {
FontSystemSelection::get_default(),
));
let local_window_id = mux.new_empty_window();
self.inner
.record_remote_to_local_window_mapping(entry.window_id, local_window_id);
inner.record_remote_to_local_window_mapping(entry.window_id, local_window_id);
mux.add_tab_to_window(&tab, local_window_id)?;
front_end()
@ -176,6 +205,19 @@ impl Domain for ClientDomain {
.unwrap();
}
}
Ok(())
}
fn detach(&self) -> Fallible<()> {
failure::bail!("detach not implemented");
}
fn state(&self) -> DomainState {
if self.inner.borrow().is_some() {
DomainState::Attached
} else {
DomainState::Detached
}
}
}