framework-startup
提供开机自启的注册、注销与启停能力,Windows、Linux、macOS 使用同一套 API。
平台实现
| 级别 | Windows | Linux | macOS |
|---|---|---|---|
Startup::root |
计划任务 onstart,以 SYSTEM 身份运行 |
/etc/systemd/system/<name>.service |
/Library/LaunchDaemons/<name>.plist |
Startup::user |
计划任务 onlogon,以当前用户身份运行 |
~/.config/systemd/user/<name>.service |
~/Library/LaunchAgents/<name>.plist |
系统级随系统启动,不依赖用户登录,注册与启停通常需要管理员或 root 权限;用户级随当前用户登录启动, 无需提权。Linux 用户级还要求该用户存在可用的 systemd 用户实例。
实现方式为「写入自启定义文件 + 调用系统命令」:Windows 调用 schtasks,Linux 调用 systemctl
(用户级附加 --user),macOS 调用 launchctl。命令失败时会带上退出码与完整输出,便于直接展示给用户。
外部命令通过 framework-system 的 CommandExt 执行,错误信息与命令行
由该扩展统一生成。sysinfo 仅在 Windows 目标下参与编译,用于按可执行文件路径判断运行状态。
用法
use ;
// 以当前可执行文件为启动目标,注册随当前用户登录启动
let mut config = new;
config.description = "个人使用的轻量网关".to_string;
config.args = vec!;
config.working_directory = Some;
let startup = user?;
// install 已注册时不重复执行;需要让配置变更生效时用 install_force
startup.install?;
// start 已在运行时跳过,stop 未运行时跳过
startup.start?;
startup.restart?;
# Ok::
系统级自启把 Startup::user 换成 Startup::root 即可,其余调用完全一致。
配置
StartupConfig 的字段:
| 字段 | 说明 |
|---|---|
name |
自启名称,同时作为计划任务名、systemd 单元名与 launchd 标签 |
description |
自启描述,写入 systemd 单元的 Description |
program |
要启动的可执行文件绝对路径;为空时取当前运行中的可执行文件 |
args |
启动参数 |
working_directory |
工作目录;为空表示由系统决定 |
ignore_not_installed |
未注册时 start / stop / is_run / restart / uninstall 是忽略还是报错,默认为 true |
highest |
仅 Windows 编译时存在。为 true 时用户级任务追加 /rl highest,登录后以提权令牌启动且不弹 UAC;账号不在管理员组时注册会失败。系统级任务固定以 SYSTEM 运行,该字段对它无意义。默认为 false |
StartupConfig::new(name) 只设置名称,其余字段按需赋值。
API
| 方法 | 说明 |
|---|---|
Startup::root(config) |
创建系统级自启 |
Startup::user(config) |
创建当前用户级自启 |
exists() |
查询自启是否已注册 |
is_run() |
查询自启的进程是否正在运行 |
install() |
注册自启;已注册时不重复执行,直接返回成功 |
install_force() |
注册自启并覆盖已存在的同名自启,用于让配置变更生效 |
uninstall() |
注销自启,不停止正在运行的进程 |
start() |
立即启动;已在运行时直接返回成功 |
stop() |
立即停止;未运行时直接返回成功 |
restart() |
重启:未运行时直接启动,正在运行时停止后再启动 |
start()、stop()、is_run()、restart() 与 uninstall() 只对已注册的自启执行;未注册时按
StartupConfig::ignore_not_installed 决定忽略(默认,is_run() 返回假)还是报错。
start() 与 stop() 还会先判断运行状态,因此重复调用不会重复触发底层命令。
restart() 只探测一次运行状态,需要重启时等价于一次 stop() 加一次 start(),但少一次探测。
uninstall() 与 stop() 相互独立:需要注销的同时结束进程时,先调 stop() 再调 uninstall()。
平台差异
- Windows 计划任务的启动目标是完整命令行;systemd 单元的
ExecStart与 launchd 的ProgramArguments由同一份配置生成,含空格的路径会自动加引号或拆分。 - Windows 的权限级别:系统级任务以
SYSTEM身份运行(/ru SYSTEM /rl highest),用户级任务默认用 未提权的令牌启动;只有StartupConfig::highest为真时才追加/rl highest。 - Windows 计划任务名在任务树的根目录下唯一,系统级与用户级不能使用同名任务;systemd 与 launchd 的两种级别存放于不同目录,可以同名。
- Linux 用户级单元的
[Install]目标为default.target(系统级为multi-user.target)。 - launchd 的
start/stop只作用于已加载的作业,install会以launchctl load -w加载并 清除 disabled 标记。 is_run()的判定方式:Linux 用systemctl is-active,macOS 用launchctl list是否带PID键, Windows 按可执行文件完整路径比对进程(sysinfo),因此手动启动同一路径的程序同样算作运行中。