Files
qiming/qimingclaw/specs/agent-client/vendorsdoc/auto-launch.md

431 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# auto-launch
## 项目概述
跨平台应用开机自启动库,支持 Windows、macOS 和 Linux。
**GitHub**: https://github.com/zzzgydi/auto-launch.git
**本地路径**: `vendors/auto-launch`
## 目录结构
```
auto-launch/
├── src/
│ ├── lib.rs # 公共 API
│ ├── windows.rs # Windows 实现
│ ├── macos.rs # macOS 实现
│ ├── linux.rs # Linux 实现
│ └── error.rs # 错误处理
├── Cargo.toml
└── README.md
```
## 核心依赖
```toml
[dependencies]
thiserror = "1.0"
os_info = "7.0"
# Windows
windows-registry = "0.2"
windows-result = "0.2"
# macOS
smappservice-rs = "0.3"
# Linux
dirs = "5.0"
```
## 核心 API
### AutoLaunchBuilder
```rust
// lib.rs
pub struct AutoLaunchBuilder {
app_name: Option<String>,
app_path: Option<String>,
macos_launch_mode: MacOSLaunchMode,
bundle_identifiers: Option<Vec<String>>,
agent_extra_config: Option<String>,
windows_enable_mode: WindowsEnableMode,
linux_launch_mode: LinuxLaunchMode,
args: Option<Vec<String>>,
}
impl AutoLaunchBuilder {
pub fn new() -> Self;
/// 设置应用名称
pub fn set_app_name(&mut self, name: &str) -> &mut Self;
/// 设置应用路径
pub fn set_app_path(&mut self, path: &str) -> &mut Self;
/// 设置 macOS 启动模式
pub fn set_macos_launch_mode(&mut self, mode: MacOSLaunchMode) -> &mut Self;
/// 设置 Windows 启用模式
pub fn set_windows_enable_mode(&mut self, mode: WindowsEnableMode) -> &mut Self;
/// 设置 Linux 启动模式
pub fn set_linux_launch_mode(&mut self, mode: LinuxLaunchMode) -> &mut Self;
/// 设置启动参数
pub fn set_args(&mut self, args: &[impl AsRef<str>]) -> &mut Self;
/// 构建 AutoLaunch
pub fn build(&self) -> Result<AutoLaunch>;
}
```
### AutoLaunch
```rust
pub struct AutoLaunch {
app_name: String,
app_path: String,
args: Vec<String>,
// 平台特定配置...
}
impl AutoLaunch {
/// 启用自启动
pub async fn enable(&self) -> Result<()>;
/// 禁用自启动
pub async fn disable(&self) -> Result<()>;
/// 检查是否已启用
pub async fn is_enabled(&self) -> Result<bool>;
}
```
### 平台特定枚举
```rust
pub enum MacOSLaunchMode {
/// 使用 SMAppService (macOS 13+)
SMAppService,
/// 使用 LaunchAgent
LaunchAgent,
/// 使用 AppleScript
AppleScript,
}
pub enum WindowsEnableMode {
/// 动态尝试(系统级 -> 用户级)
Dynamic,
/// 仅当前用户
CurrentUser,
/// 所有用户(需管理员权限)
System,
}
pub enum LinuxLaunchMode {
/// 使用 XDG Autostart
XdgAutostart,
/// 使用 systemd
Systemd,
}
```
## 使用示例
```rust
use auto_launch::AutoLaunch;
#[tokio::main]
async fn main() -> Result<()> {
let auto = AutoLaunchBuilder::new()
.set_app_name("qiming-agent")
.set_app_path("/Applications/qiming-agent.app")
.set_args(&["--hidden", "--minimize"])
.set_macos_launch_mode(MacOSLaunchMode::SMAppService)
.build()?;
// 检查是否已启用
let is_enabled = auto.is_enabled().await?;
println!("Auto launch enabled: {}", is_enabled);
// 启用自启动
if !is_enabled {
auto.enable().await?;
}
Ok(())
}
```
## 平台实现
| 平台 | 实现方式 | 配置位置 |
|------|----------|----------|
| Windows | 注册表 | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` |
| macOS | SMAppService | `~/Library/LaunchAgents/` |
| Linux | XDG | `~/.config/autostart/` |
## 与 agent-client 集成场景
### 场景1设置界面的自启动开关
```rust
// 在设置界面中集成自启动管理
use auto_launch::{AutoLaunch, AutoLaunchBuilder, MacOSLaunchMode};
pub struct AutoLaunchManager {
auto_launch: AutoLaunch,
// 当前状态(缓存,避免频繁读取)
cached_enabled: bool,
}
impl AutoLaunchManager {
pub fn new(app_name: &str, app_path: &str) -> Result<Self> {
let auto = AutoLaunchBuilder::new()
.set_app_name(app_name)
.set_app_path(app_path)
.set_macos_launch_mode(MacOSLaunchMode::SMAppService) // macOS 13+
.build()?;
Ok(Self {
auto_launch: auto,
cached_enabled: false,
})
}
/// 获取当前自启动状态
pub async fn is_enabled(&self) -> Result<bool> {
self.auto_launch.is_enabled().await
}
/// 启用自启动
pub async fn enable(&self) -> Result<()> {
self.auto_launch.enable().await
}
/// 禁用自启动
pub async fn disable(&self) -> Result<()> {
self.auto_launch.disable().await
}
/// 切换自启动状态
pub async fn toggle(&self) -> Result<bool> {
let enabled = self.is_enabled().await?;
if enabled {
self.disable().await?;
} else {
self.enable().await?;
}
Ok(!enabled)
}
}
/// 设置界面中的自启动开关组件
pub struct AutoLaunchSwitch {
manager: AutoLaunchManager,
enabled: bool,
loading: bool,
}
impl AutoLaunchSwitch {
pub fn new(manager: AutoLaunchManager) -> Self {
Self {
manager,
enabled: false,
loading: true,
}
}
/// 初始化时检查状态
pub fn refresh_status(&mut self) {
let manager = self.manager.clone();
cx.spawn(|this, mut cx| async move {
let enabled = manager.is_enabled().await.unwrap_or(false);
this.update(&mut cx, |this, _| {
this.enabled = enabled;
this.loading = false;
});
});
}
}
impl Render for AutoLaunchSwitch {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
div()
.flex()
.items_center()
.justify_between()
.p_4()
.rounded_md()
.bg(cx.theme().colors.surface)
.border_1()
.border_color(cx.theme().colors.border)
.child(
div()
.flex()
.flex_col()
.gap_1()
.child(
div()
.font_medium()
.child("Auto Launch")
)
.child(
div()
.text_sm()
.text_color(cx.theme().colors.muted)
.child("Start application when system boots")
)
)
.child(
match self.loading {
true => Loading::new().into_any_element(),
false => Switch::new(self.enabled, |enabled, _| {
// 切换自启动
let manager = self.manager.clone();
cx.spawn(|this, mut cx| async move {
let result = if enabled {
manager.disable().await
} else {
manager.enable().await
};
match result {
Ok(_) => {
this.update(&mut cx, |this, _| {
this.enabled = !enabled;
});
}
Err(e) => {
// 显示错误提示
tracing::error!("Failed to toggle auto-launch: {}", e);
}
}
});
}).into_any_element(),
}
)
}
}
```
### 场景2应用启动时检查自启动状态
```rust
// 应用启动时的初始化逻辑
pub struct AppInitializer {
auto_launch_manager: Option<AutoLaunchManager>,
}
impl AppInitializer {
pub async fn initialize(&mut self, app_path: &str) -> Result<()> {
// 1. 初始化自启动管理器
self.auto_launch_manager = Some(
AutoLaunchManager::new("qiming-agent", app_path).ok()
);
// 2. 检查自启动是否已启用
if let Some(manager) = &self.auto_launch_manager {
let is_enabled = manager.is_enabled().await.unwrap_or(false);
tracing::info!("Auto-launch enabled: {}", is_enabled);
}
// 3. 根据启动参数决定行为
let args: Vec<String> = std::env::args().collect();
// 如果是通过自启动触发的,可能需要最小化到托盘
if args.iter().any(|arg| arg == "--minimize") {
// 最小化到托盘,不显示主窗口
}
Ok(())
}
}
```
### 场景3跨平台注意事项
```rust
// 不同平台的自启动行为差异处理
#[cfg(target_os = "windows")]
mod windows_impl {
use auto_launch::WindowsEnableMode;
pub fn get_app_path() -> String {
// Windows: 使用完整路径
std::env::current_exe()
.unwrap()
.to_string_lossy()
.into_owned()
}
pub fn build_auto_launch(name: &str, path: &str) -> auto_launch::AutoLaunchBuilder {
AutoLaunchBuilder::new()
.set_app_name(name)
.set_app_path(path)
.set_windows_enable_mode(WindowsEnableMode::CurrentUser) // 当前用户
}
}
#[cfg(target_os = "macos")]
mod macos_impl {
use auto_launch::MacOSLaunchMode;
pub fn get_app_path() -> String {
// macOS: 使用 .app 路径
std::env::current_exe()
.unwrap()
.to_string_lossy()
.into_owned()
}
pub fn build_auto_launch(name: &str, path: &str) -> auto_launch::AutoLaunchBuilder {
AutoLaunchBuilder::new()
.set_app_name(name)
.set_app_path(path)
.set_macos_launch_mode(MacOSLaunchMode::SMAppService) // macOS 13+
}
}
#[cfg(target_os = "linux")]
mod linux_impl {
use auto_launch::LinuxLaunchMode;
pub fn get_app_path() -> String {
std::env::current_exe()
.unwrap()
.to_string_lossy()
.into_owned()
}
pub fn build_auto_launch(name: &str, path: &str) -> auto_launch::AutoLaunchBuilder {
AutoLaunchBuilder::new()
.set_app_name(name)
.set_app_path(path)
.set_linux_launch_mode(LinuxLaunchMode::XdgAutostart)
}
}
```
## 在本项目中的使用
用于实现 agent-client 的开机自启动功能:
```
agent-client
└── auto-launch
├── 检测自启动状态 (设置界面开关)
├── 启用自启动 (用户勾选开关)
├── 禁用自启动 (用户取消勾选)
└── 应用启动时最小化到托盘
```