Skip to main content

framework_startup/
startup.rs

1//! 统一自启入口。
2
3use anyhow::{Result, anyhow};
4
5use crate::config::StartupConfig;
6use crate::platform::{Platform, current_platform};
7use crate::scope::Scope;
8
9/// 开机自启入口;按当前操作系统选择实现,并记录注册级别。
10pub struct Startup {
11    config: StartupConfig,
12    scope: Scope,
13    platform: Box<dyn Platform>,
14}
15
16impl Startup {
17    /// 创建系统级自启:随系统启动,不依赖用户登录;注册与启停通常需要管理员或 root 权限。
18    pub fn root(config: StartupConfig) -> Result<Self> {
19        Self::new(config, Scope::Root)
20    }
21
22    /// 创建当前用户级自启:随当前用户登录启动,无需管理员或 root 权限。
23    ///
24    /// 同一名称在系统级与用户级下互不冲突(systemd 与 launchd 存放于不同目录),
25    /// 但 Windows 计划任务名在整个任务树的根目录下唯一,因此系统级与用户级不能使用同名任务。
26    pub fn user(config: StartupConfig) -> Result<Self> {
27        Self::new(config, Scope::User)
28    }
29
30    /// 查询自启是否已注册。
31    pub fn exists(&self) -> Result<bool> {
32        self.platform.exists(&self.config, self.scope)
33    }
34
35    /// 查询自启的进程是否正在运行。
36    ///
37    /// 未注册时的行为由 [`StartupConfig::ignore_not_installed`] 决定:忽略时返回假,否则报错。
38    pub fn is_run(&self) -> Result<bool> {
39        if self.not_installed()? {
40            return Ok(false);
41        }
42
43        self.running()
44    }
45
46    /// 注册自启;已注册时不重复执行,直接返回成功。
47    pub fn install(&self) -> Result<()> {
48        if self.exists()? {
49            return Ok(());
50        }
51
52        self.platform.install(&self.config, self.scope)
53    }
54
55    /// 注册自启并覆盖已存在的同名自启,用于让配置变更生效。
56    pub fn install_force(&self) -> Result<()> {
57        self.platform.install(&self.config, self.scope)
58    }
59
60    /// 注销自启;不停止正在运行的进程,需要先停止时由调用方先调 [`Startup::stop`]。
61    ///
62    /// 未注册时的行为由 [`StartupConfig::ignore_not_installed`] 决定。
63    pub fn uninstall(&self) -> Result<()> {
64        if self.not_installed()? {
65            return Ok(());
66        }
67
68        self.platform.uninstall(&self.config, self.scope)
69    }
70
71    /// 立即启动;未注册时与已在运行时都不重复执行,直接返回成功。
72    pub fn start(&self) -> Result<()> {
73        if self.not_installed()? || self.running()? {
74            return Ok(());
75        }
76
77        self.platform.start(&self.config, self.scope)
78    }
79
80    /// 立即停止;未注册时与未运行时都不重复执行,直接返回成功。
81    pub fn stop(&self) -> Result<()> {
82        if self.not_installed()? || !self.running()? {
83            return Ok(());
84        }
85
86        self.platform.stop(&self.config, self.scope)
87    }
88
89    /// 重启:先停止再启动。
90    ///
91    /// 只探测一次运行状态:未运行时直接启动,正在运行时停止后再启动。
92    /// 停止阶段的错误只说明进程本来就已退出,不阻断后续启动。
93    pub fn restart(&self) -> Result<()> {
94        if self.not_installed()? {
95            return Ok(());
96        }
97
98        if self.running()? {
99            let _ = self.platform.stop(&self.config, self.scope);
100        }
101
102        self.platform.start(&self.config, self.scope)
103    }
104
105    /// 查询运行状态;调用方需先确认自启已注册。
106    fn running(&self) -> Result<bool> {
107        self.platform.is_run(&self.config, self.scope)
108    }
109
110    /// 判断自启未注册;未注册且要求忽略时返回真,未注册且要求报错时返回错误。
111    fn not_installed(&self) -> Result<bool> {
112        if self.exists()? {
113            return Ok(false);
114        }
115        if self.config.ignore_not_installed {
116            return Ok(true);
117        }
118
119        Err(anyhow!("自启 {} 未注册", self.config.name))
120    }
121
122    fn new(config: StartupConfig, scope: Scope) -> Result<Self> {
123        Ok(Self {
124            config: config.resolve()?,
125            scope,
126            platform: current_platform()?,
127        })
128    }
129}