use std::ffi::OsString;
use std::fmt;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use super::Server;
#[cfg(feature = "control-mode")]
use crate::ControlClientLimits;
use crate::internal::core::{BuildContext, Core, CoreConfiguration, SocketSelection};
use crate::{DispatchLimits, Error, OutputLimits, ServerConfigurationErrorKind};
#[must_use = "a server builder has no effect until build is called"]
pub struct ServerBuilder {
socket_name: Option<OsString>,
socket_path: Option<PathBuf>,
config_file: Option<PathBuf>,
colors: Option<u16>,
executable: OsString,
timeout: Duration,
output_limits: OutputLimits,
dispatch_limits: DispatchLimits,
#[cfg(feature = "control-mode")]
control_client_limits: ControlClientLimits,
#[cfg(feature = "test-support")]
prevent_server_start: bool,
}
impl fmt::Debug for ServerBuilder {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = formatter.debug_struct("ServerBuilder");
debug
.field(
"socket_name",
&self.socket_name.as_ref().map(|_| "<redacted>"),
)
.field(
"socket_path",
&self.socket_path.as_ref().map(|_| "<redacted>"),
)
.field(
"config_file",
&self.config_file.as_ref().map(|_| "<redacted>"),
)
.field("colors", &self.colors)
.field("timeout", &self.timeout)
.field("output_limits", &self.output_limits)
.field("dispatch_limits", &self.dispatch_limits);
#[cfg(feature = "control-mode")]
debug.field("control_client_limits", &self.control_client_limits);
debug.finish_non_exhaustive()
}
}
impl ServerBuilder {
pub(super) fn new() -> Self {
Self {
socket_name: None,
socket_path: None,
config_file: None,
colors: None,
executable: OsString::from("tmux"),
timeout: CoreConfiguration::default_timeout(),
output_limits: OutputLimits::default(),
dispatch_limits: DispatchLimits::default(),
#[cfg(feature = "control-mode")]
control_client_limits: ControlClientLimits::default(),
#[cfg(feature = "test-support")]
prevent_server_start: false,
}
}
#[must_use = "use the returned builder to retain the limits"]
pub const fn output_limits(mut self, limits: OutputLimits) -> Self {
self.output_limits = limits;
self
}
#[must_use = "use the returned builder to retain the limits"]
pub const fn dispatch_limits(mut self, limits: DispatchLimits) -> Self {
self.dispatch_limits = limits;
self
}
#[cfg(feature = "control-mode")]
#[must_use = "use the returned builder to retain the limits"]
pub const fn control_client_limits(mut self, limits: ControlClientLimits) -> Self {
self.control_client_limits = limits;
self
}
#[must_use = "use the returned builder to retain the socket name"]
pub fn socket_name(mut self, name: impl Into<OsString>) -> Self {
self.socket_name = Some(name.into());
self
}
#[must_use = "use the returned builder to retain the socket path"]
pub fn socket_path(mut self, path: impl Into<PathBuf>) -> Self {
self.socket_path = Some(path.into());
self
}
#[must_use = "use the returned builder to retain the config path"]
pub fn config_file(mut self, path: impl Into<PathBuf>) -> Self {
self.config_file = Some(path.into());
self
}
#[must_use = "use the returned builder to retain the color mode"]
pub const fn colors(mut self, colors: u16) -> Self {
self.colors = Some(colors);
self
}
#[must_use = "use the returned builder to retain the executable"]
pub fn tmux_executable(mut self, executable: impl Into<OsString>) -> Self {
self.executable = executable.into();
self
}
#[must_use = "use the returned builder to retain the timeout"]
pub const fn default_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
#[cfg(feature = "test-support")]
pub(crate) const fn prevent_server_start(mut self) -> Self {
self.prevent_server_start = true;
self
}
pub fn build(self) -> Result<Server, Error> {
let selection = match (self.socket_name, self.socket_path) {
(Some(name), None) => SocketSelection::Name(name),
(None, Some(path)) => SocketSelection::Path(path),
(None, None) => SocketSelection::Automatic,
(Some(_), Some(_)) => {
return Err(Error::invalid_server_configuration(
ServerConfigurationErrorKind::ConflictingSocketSelectors,
));
}
};
let configuration = CoreConfiguration::resolve(
&selection,
self.config_file,
self.colors,
self.executable,
self.timeout,
BuildContext::capture(),
)
.map_err(Error::invalid_server_configuration)?
.with_limits(self.output_limits, self.dispatch_limits);
#[cfg(feature = "control-mode")]
let configuration = configuration.with_control_client_limits(self.control_client_limits);
#[cfg(feature = "test-support")]
let configuration = if self.prevent_server_start {
configuration.prevent_server_start()
} else {
configuration
};
Ok(Server {
core: Arc::new(Core::new(configuration)),
})
}
}