diff --git a/src/main.rs b/src/main.rs index b684318c5..5dfa406d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, opts: &StartCommand) -> Fallibl let gui = front_end.try_new(&mux)?; domain.attach()?; - fn attach_client(mux: &Rc, client: ClientDomain) -> Fallible<()> { + fn record_domain(mux: &Rc, client: ClientDomain) -> Fallible> { let domain: Arc = 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, 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() } diff --git a/src/mux/domain.rs b/src/mux/domain.rs index f3e33a3b8..0ead880b9 100644 --- a/src/mux/domain.rs +++ b/src/mux/domain.rs @@ -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 + } } diff --git a/src/mux/mod.rs b/src/mux/mod.rs index 195432007..e9a58124e 100644 --- a/src/mux/mod.rs +++ b/src/mux/mod.rs @@ -269,6 +269,10 @@ impl Mux { pub fn iter_windows(&self) -> Vec { self.windows.borrow().keys().cloned().collect() } + + pub fn iter_domains(&self) -> Vec> { + self.domains.borrow().values().cloned().collect() + } } #[derive(Debug, Fail)] diff --git a/src/server/domain.rs b/src/server/domain.rs index 1c7b4f90f..df27c7a0e 100644 --- a/src/server/domain.rs +++ b/src/server/domain.rs @@ -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, +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>>, + 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> { + self.inner.borrow().as_ref().map(|i| Arc::clone(i)) } pub fn remote_to_local_tab_id(&self, remote_tab_id: TabId) -> Option { - 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, window: WindowId, ) -> Fallible> { + 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 = Rc::new(ClientTab::new(&self.inner, remote_tab_id, size)); + let tab: Rc = 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 = Rc::new(ClientTab::new(&self.inner, entry.tab_id, entry.size)); + let tab: Rc = 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 + } + } }