Skip to content

feat: 为开机计划任务增加后缀#236

Open
litwak913 wants to merge 2 commits into
MistEO:mainfrom
litwak913:autostart-suffix
Open

feat: 为开机计划任务增加后缀#236
litwak913 wants to merge 2 commits into
MistEO:mainfrom
litwak913:autostart-suffix

Conversation

@litwak913

@litwak913 litwak913 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Close #213

开机启动计划任务名会使用 PI 中的 name 作为后缀。

Summary by Sourcery

为 Windows 自启动计划任务提供基于后缀的命名支持,并将其贯穿集成到 Tauri 命令和设置界面中。

新功能:

  • 允许为 Windows 自启动计划任务名称指定后缀,该名称由项目接口名派生而来。

错误修复:

  • 确保在 schtasks 执行失败时,自启动禁用操作能够正确上报错误。

增强改进:

  • 优化 Windows 自启动的迁移和刷新逻辑,以适配新的可选任务名称后缀。
  • 整理系统命令模块中的日志记录和 sleep 调用的使用方式。
Original summary in English

Summary by Sourcery

Support suffix-based naming for Windows autostart scheduled tasks and wire it through the Tauri commands and settings UI.

New Features:

  • Allow specifying a suffix for Windows autostart scheduled task names derived from the project interface name.

Bug Fixes:

  • Ensure autostart disable correctly reports errors when schtasks execution fails.

Enhancements:

  • Refine Windows autostart migration and refresh logic to work with the new optional task name suffix.
  • Tidy logging and time-sleep usage in the system commands module.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体性的反馈:

  • create_schtask_autostartautostart_disableautostart_is_enabled 中,你在 match 分支里返回 &format!(...),这会创建对临时字符串的引用;建议改为先构造一个 String(例如 let task_name = suffix.map(|s| format!("MXU-{}", s)).unwrap_or_else(|| "MXU".to_string());),然后将 &task_name 传递给 args
  • get_web_server_port 中将 std::time::Duration::from_millis(100) 改为 Duration::from_millis(100) 后,需要将 Duration 引入作用域(use std::time::Duration;),否则代码将无法编译。
  • 在 Tauri 这边,autostart_enable 现在接受的是 suffix: String(非可选),但前端传入的是可能为 undefinedprojectInterface?.name;可以考虑将 Rust 端参数改为 Option<String>(与 autostart_disable / autostart_is_enabled 保持一致),或者在前端进行保护,确保总是传入一个已定义的字符串。
提供给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- In `create_schtask_autostart`, `autostart_disable`, and `autostart_is_enabled`, you are returning `&format!(...)` from a `match` arm, which creates a reference to a temporary string; instead, build a `String` (e.g. `let task_name = suffix.map(|s| format!("MXU-{}", s)).unwrap_or_else(|| "MXU".to_string());`) and pass `&task_name` to `args`.
- The change from `std::time::Duration::from_millis(100)` to `Duration::from_millis(100)` in `get_web_server_port` requires importing `Duration` into scope (`use std::time::Duration;`), otherwise this will not compile.
- On the Tauri side `autostart_enable` now takes `suffix: String` (non-optional), but the frontend passes `projectInterface?.name` which can be `undefined`; consider making the Rust parameter `Option<String>` (consistent with `autostart_disable`/`autostart_is_enabled`) or guarding on the frontend so a defined string is always provided.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/system.rs" line_range="683" />
<code_context>
     use std::os::windows::process::CommandExt;
     let exe_path = std::env::current_exe().map_err(|e| format!("获取程序路径失败: {}", e))?;
     let exe = exe_path.to_string_lossy();
+    let task_name = match suffix {
+        Some(name) => &format!("MXU-{}", name),
+        None => "MXU",
</code_context>
<issue_to_address>
**issue (bug_risk):** Borrowing from `format!` here creates a dangling reference; `task_name` should own its `String`.

The `Some(name) => &format!(...)` arm returns a reference to a temporary `String` that’s dropped at the end of the `match`, so `task_name` would reference freed memory. Instead, make `task_name` an owned `String`, for example:

```rust
let task_name = suffix
    .map(|s| format!("MXU-{}", s))
    .unwrap_or_else(|| "MXU".to_string());
```

and then pass `&task_name` into `args`.
</issue_to_address>

### Comment 2
<location path="src/components/settings/GeneralSection.tsx" line_range="96" />
<code_context>
       if (isWindowsRef.current) {
         const { invoke } = await import('@tauri-apps/api/core');
-        await invoke(enabled ? 'autostart_enable' : 'autostart_disable');
+        await invoke(enabled ? 'autostart_enable' : 'autostart_disable',
+            {suffix: projectInterface?.name});
       } else {
</code_context>
<issue_to_address>
**issue (bug_risk):** Mismatch between `autostart_enable`’s required `String` parameter and the optional `suffix` passed from the UI.

`autostart_enable` expects a non-optional `suffix: String`, but this call may pass `undefined` when `projectInterface` is missing, which can break deserialization. Either change the Rust parameter to `Option<String>` (as with `autostart_disable` / `autostart_is_enabled`) or ensure the UI always passes a concrete string (e.g., guard the toggle on `projectInterface` or use a default).
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的代码评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In create_schtask_autostart, autostart_disable, and autostart_is_enabled, you are returning &format!(...) from a match arm, which creates a reference to a temporary string; instead, build a String (e.g. let task_name = suffix.map(|s| format!("MXU-{}", s)).unwrap_or_else(|| "MXU".to_string());) and pass &task_name to args.
  • The change from std::time::Duration::from_millis(100) to Duration::from_millis(100) in get_web_server_port requires importing Duration into scope (use std::time::Duration;), otherwise this will not compile.
  • On the Tauri side autostart_enable now takes suffix: String (non-optional), but the frontend passes projectInterface?.name which can be undefined; consider making the Rust parameter Option<String> (consistent with autostart_disable/autostart_is_enabled) or guarding on the frontend so a defined string is always provided.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `create_schtask_autostart`, `autostart_disable`, and `autostart_is_enabled`, you are returning `&format!(...)` from a `match` arm, which creates a reference to a temporary string; instead, build a `String` (e.g. `let task_name = suffix.map(|s| format!("MXU-{}", s)).unwrap_or_else(|| "MXU".to_string());`) and pass `&task_name` to `args`.
- The change from `std::time::Duration::from_millis(100)` to `Duration::from_millis(100)` in `get_web_server_port` requires importing `Duration` into scope (`use std::time::Duration;`), otherwise this will not compile.
- On the Tauri side `autostart_enable` now takes `suffix: String` (non-optional), but the frontend passes `projectInterface?.name` which can be `undefined`; consider making the Rust parameter `Option<String>` (consistent with `autostart_disable`/`autostart_is_enabled`) or guarding on the frontend so a defined string is always provided.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/system.rs" line_range="683" />
<code_context>
     use std::os::windows::process::CommandExt;
     let exe_path = std::env::current_exe().map_err(|e| format!("获取程序路径失败: {}", e))?;
     let exe = exe_path.to_string_lossy();
+    let task_name = match suffix {
+        Some(name) => &format!("MXU-{}", name),
+        None => "MXU",
</code_context>
<issue_to_address>
**issue (bug_risk):** Borrowing from `format!` here creates a dangling reference; `task_name` should own its `String`.

The `Some(name) => &format!(...)` arm returns a reference to a temporary `String` that’s dropped at the end of the `match`, so `task_name` would reference freed memory. Instead, make `task_name` an owned `String`, for example:

```rust
let task_name = suffix
    .map(|s| format!("MXU-{}", s))
    .unwrap_or_else(|| "MXU".to_string());
```

and then pass `&task_name` into `args`.
</issue_to_address>

### Comment 2
<location path="src/components/settings/GeneralSection.tsx" line_range="96" />
<code_context>
       if (isWindowsRef.current) {
         const { invoke } = await import('@tauri-apps/api/core');
-        await invoke(enabled ? 'autostart_enable' : 'autostart_disable');
+        await invoke(enabled ? 'autostart_enable' : 'autostart_disable',
+            {suffix: projectInterface?.name});
       } else {
</code_context>
<issue_to_address>
**issue (bug_risk):** Mismatch between `autostart_enable`’s required `String` parameter and the optional `suffix` passed from the UI.

`autostart_enable` expects a non-optional `suffix: String`, but this call may pass `undefined` when `projectInterface` is missing, which can break deserialization. Either change the Rust parameter to `Option<String>` (as with `autostart_disable` / `autostart_is_enabled`) or ensure the UI always passes a concrete string (e.g., guard the toggle on `projectInterface` or use a default).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src-tauri/src/commands/system.rs
Comment thread src/components/settings/GeneralSection.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

潜在的计划任务命名冲突

1 participant