framework-startup 26.8.151

lingting framework
Documentation

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 framework_startup::{Startup, StartupConfig};

// 以当前可执行文件为启动目标,注册随当前用户登录启动
let mut config = StartupConfig::new("my-app");
config.description = "个人使用的轻量网关".to_string();
config.args = vec!["--port".to_string(), "8080".to_string()];
config.working_directory = Some("/opt/my-app".into());

let startup = Startup::user(config)?;

// install 已注册时不重复执行;需要让配置变更生效时用 install_force
startup.install()?;
// start 已在运行时跳过,stop 未运行时跳过
startup.start()?;
startup.restart()?;

# Ok::<(), anyhow::Error>(())

系统级自启把 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),因此手动启动同一路径的程序同样算作运行中。