#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("app_name shouldn't be None")]
AppNameNotSpecified,
#[error("app_path shouldn't be None")]
AppPathNotSpecified,
#[error("app path doesn't exist: {0}")]
AppPathDoesntExist(std::path::PathBuf),
#[error("app path is not absolute: {0}")]
AppPathIsNotAbsolute(std::path::PathBuf),
#[error("Failed to execute apple script with status: {0}")]
AppleScriptFailed(i32),
#[error("Failed to register app with SMAppService with status: {0}")]
SMAppServiceRegistrationFailed(u32),
#[error("Failed to unregister app with SMAppService with status: {0}")]
SMAppServiceUnregistrationFailed(u32),
#[error("Unsupported target os")]
UnsupportedOS,
#[error(transparent)]
Io(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
mod windows;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AutoLaunch {
pub(crate) app_name: String,
pub(crate) app_path: String,
pub(crate) args: Vec<String>,
#[cfg(target_os = "linux")]
pub(crate) launch_mode: LinuxLaunchMode,
#[cfg(target_os = "macos")]
pub(crate) launch_mode: MacOSLaunchMode,
#[cfg(target_os = "macos")]
pub(crate) bundle_identifiers: Vec<String>,
#[cfg(target_os = "macos")]
pub(crate) agent_extra_config: String,
#[cfg(windows)]
pub(crate) enable_mode: WindowsEnableMode,
}
impl AutoLaunch {
pub fn is_support() -> bool {
cfg!(any(
target_os = "linux",
target_os = "macos",
target_os = "windows",
))
}
pub fn get_app_name(&self) -> &str {
&self.app_name
}
pub fn get_app_path(&self) -> &str {
&self.app_path
}
pub fn get_args(&self) -> &[String] {
&self.args
}
}
#[derive(Debug, Default, Clone)]
pub struct AutoLaunchBuilder {
pub app_name: Option<String>,
pub app_path: Option<String>,
pub macos_launch_mode: MacOSLaunchMode,
pub bundle_identifiers: Option<Vec<String>>,
pub agent_extra_config: Option<String>,
pub windows_enable_mode: WindowsEnableMode,
pub linux_launch_mode: LinuxLaunchMode,
pub args: Option<Vec<String>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinuxLaunchMode {
XdgAutostart,
Systemd,
}
impl Default for LinuxLaunchMode {
fn default() -> Self {
Self::XdgAutostart
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MacOSLaunchMode {
LaunchAgent,
AppleScript,
SMAppService,
}
impl Default for MacOSLaunchMode {
fn default() -> Self {
Self::LaunchAgent
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowsEnableMode {
Dynamic,
CurrentUser,
System,
}
impl Default for WindowsEnableMode {
fn default() -> Self {
Self::Dynamic
}
}
impl AutoLaunchBuilder {
pub fn new() -> AutoLaunchBuilder {
AutoLaunchBuilder::default()
}
pub fn set_app_name(&mut self, name: &str) -> &mut Self {
self.app_name = Some(name.into());
self
}
pub fn set_app_path(&mut self, path: &str) -> &mut Self {
self.app_path = Some(path.into());
self
}
pub fn set_macos_launch_mode(&mut self, mode: MacOSLaunchMode) -> &mut Self {
self.macos_launch_mode = mode;
self
}
#[deprecated(since = "0.6.0", note = "Use `set_macos_launch_mode` instead")]
pub fn set_use_launch_agent(&mut self, use_launch_agent: bool) -> &mut Self {
self.macos_launch_mode = if use_launch_agent {
MacOSLaunchMode::LaunchAgent
} else {
MacOSLaunchMode::AppleScript
};
self
}
pub fn set_bundle_identifiers(&mut self, bundle_identifiers: &[impl AsRef<str>]) -> &mut Self {
self.bundle_identifiers = Some(
bundle_identifiers
.iter()
.map(|s| s.as_ref().to_string())
.collect(),
);
self
}
pub fn set_agent_extra_config(&mut self, config: &str) -> &mut Self {
self.agent_extra_config = Some(config.into());
self
}
pub fn set_windows_enable_mode(&mut self, mode: WindowsEnableMode) -> &mut Self {
self.windows_enable_mode = mode;
self
}
pub fn set_linux_launch_mode(&mut self, mode: LinuxLaunchMode) -> &mut Self {
self.linux_launch_mode = mode;
self
}
pub fn set_args(&mut self, args: &[impl AsRef<str>]) -> &mut Self {
self.args = Some(args.iter().map(|s| s.as_ref().to_string()).collect());
self
}
pub fn build(&self) -> Result<AutoLaunch> {
let default_str = String::new();
let (app_name, app_path) = if self.macos_launch_mode == MacOSLaunchMode::SMAppService {
let info = os_info::get();
match info.version() {
os_info::Version::Semantic(major, _, _) => {
if *major < 13 {
return Err(Error::UnsupportedOS);
}
}
_ => return Err(Error::UnsupportedOS),
};
(
self.app_name.as_ref().unwrap_or(&default_str),
self.app_path.as_ref().unwrap_or(&default_str),
)
} else {
(
self.app_name.as_ref().ok_or(Error::AppNameNotSpecified)?,
self.app_path.as_ref().ok_or(Error::AppPathNotSpecified)?,
)
};
let args = self.args.clone().unwrap_or_default();
let bundle_identifiers = self.bundle_identifiers.clone().unwrap_or_default();
let agent_extra_config = self.agent_extra_config.as_ref().map_or("", |v| v);
#[cfg(target_os = "linux")]
return Ok(AutoLaunch::new(
app_name,
app_path,
self.linux_launch_mode,
&args,
));
#[cfg(target_os = "macos")]
return Ok(AutoLaunch::new(
app_name,
app_path,
self.macos_launch_mode,
&args,
&bundle_identifiers,
agent_extra_config,
));
#[cfg(target_os = "windows")]
return Ok(AutoLaunch::new(
app_name,
app_path,
self.windows_enable_mode,
&args,
));
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
return Err(Error::UnsupportedOS);
}
}