feat(URL协议): 增强URL协议注册健壮性

- 新增check_url_protocol_status命令检测注册状态
- 新增unregister_url_protocol命令取消注册
- 改进register_url_protocol命令增加验证逻辑
- 前端增加状态检测、自动重试和操作日志功能
- 更新多语言翻译支持新功能
This commit is contained in:
Yukino_fox
2026-05-04 12:11:18 +08:00
parent 3e85c32c9c
commit a2ec923788
28 changed files with 3246 additions and 429 deletions
@@ -0,0 +1,238 @@
# URL 协议注册健壮性增强计划
## 目标
为 SecScore 的 URL 协议注册功能实现完整的健壮性增强,包括:状态检测、注册验证、自动重试(最多7次)、按钮状态自动切换、取消注册、以及全流程日志记录。
---
## 涉及文件
| 文件 | 操作 | 说明 |
| -------------------------------- | ---- | ---------------------------------------------------------------------------------------------- |
| `src-tauri/src/commands/app.rs` | 修改 | 新增 `check_url_protocol_status``unregister_url_protocol` 命令;增强 `register_url_protocol` |
| `src-tauri/src/lib.rs` | 修改 | 注册新命令到 invoke_handler |
| `src/preload/types.ts` | 修改 | 新增 API 类型定义 |
| `src/components/Settings.tsx` | 修改 | 重写 URL 协议 UI,加入状态显示、重试逻辑、按钮切换 |
| `src/i18n/locales/*.json` (10个) | 修改 | 新增 i18n 翻译键 |
---
## 步骤 1Rust 后端 - 新增 `UrlProtocolStatus` 结构体和 `check_url_protocol_status` 命令
**文件**: `src-tauri/src/commands/app.rs`
### 1.1 新增结构体
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UrlProtocolStatus {
pub registered: bool,
pub protocol: String,
pub platform: String,
pub details: String,
}
```
### 1.2 实现 `check_url_protocol_status` 命令
按平台实现 URL 协议状态检测:
- **Windows**: 查询注册表 `HKCU\Software\Classes\secscore` 是否存在,检查 `URL Protocol` 值和 `shell\open\command` 中的路径是否指向当前 exe
- **macOS**:
1. 先尝试通过 `lsregister -dump` 查询 `secscore://` scheme 的注册状态
2. 检查 `~/Library/LaunchAgents/com.secscore.url-handler.plist` 是否存在(非 .app bundle 场景)
- **Linux**:
1. 检查 `~/.local/share/applications/secscore.desktop` 是否存在且包含 `x-scheme-handler/secscore`
2. 通过 `xdg-settings get default-url-scheme-handler secscore` 验证是否为默认处理器
返回 `UrlProtocolStatus` 结构体,包含注册状态、当前平台、检测详情。
---
## 步骤 2Rust 后端 - 新增 `unregister_url_protocol` 命令
**文件**: `src-tauri/src/commands/app.rs`
按平台实现取消注册:
- **Windows**: 删除注册表 `HKCU\Software\Classes\secscore` 键 (`reg delete "HKCU\Software\Classes\secscore" /f`)
- **macOS**:
1. 如果存在 .app bundle,通过 `lsregister -u` 取消注册
2. 删除 `~/Library/LaunchAgents/com.secscore.url-handler.plist`
- **Linux**:
1. 删除 `~/.local/share/applications/secscore.desktop`
2. 运行 `update-desktop-database`
---
## 步骤 3Rust 后端 - 增强 `register_url_protocol` 命令
**文件**: `src-tauri/src/commands/app.rs`
改造现有 `register_url_protocol`
1. 执行注册操作后,不再盲目返回 `registered: Some(true)`
2. 注册完成后,自动调用状态检测逻辑验证注册是否成功
3. 返回实际检测到的注册状态(`registered` 字段反映真实结果)
4. 在每个关键步骤添加 `eprintln!` 日志输出(Rust 端日志)
---
## 步骤 4:Rust 后端 - 注册新命令
**文件**: `src-tauri/src/lib.rs`
`invoke_handler` 中添加:
- `check_url_protocol_status`
- `unregister_url_protocol`
---
## 步骤 5:前端 API 类型定义
**文件**: `src/preload/types.ts`
新增 API 方法:
```typescript
checkUrlProtocolStatus: (): Promise<{
success: boolean
data?: {
registered: boolean
protocol: string
platform: string
details: string
}
message?: string
}> => invoke("check_url_protocol_status"),
unregisterUrlProtocol: (): Promise<{
success: boolean
data?: { registered: boolean }
message?: string
}> => invoke("unregister_url_protocol"),
```
---
## 步骤 6:前端 Settings.tsx - 重写 URL 协议卡片 UI
**文件**: `src/components/Settings.tsx`
### 6.1 新增状态变量
```typescript
const [urlStatus, setUrlStatus] = useState<{ registered: boolean; details: string } | null>(null)
const [urlStatusLoading, setUrlStatusLoading] = useState(false)
const [urlOperationLogs, setUrlOperationLogs] = useState<string[]>([])
```
### 6.2 状态检测逻辑
- 组件加载 URL tab 时自动执行一次 `checkUrlProtocolStatus`
- 在 UI 中显示当前注册状态(Tag: 已注册/未注册 + 详情文本)
### 6.3 注册流程(含自动重试)
```
handleRegister():
1. 记录日志:"开始注册 URL 协议..."
2. 调用 registerUrlProtocol()
3. 记录日志:"注册命令已执行,开始验证..."
4. 调用 checkUrlProtocolStatus() 验证
5. IF 注册成功:
- 记录日志:"注册验证成功"
- 更新状态显示
- 完成
6. ELSE (注册失败):
- FOR retry = 1 TO 7:
- 记录日志:"注册失败,第 {retry}/7 次重试..."
- 延迟 retry * 1000 ms (递增延迟: 1s, 2s, 3s, ..., 7s)
- 调用 registerUrlProtocol()
- 调用 checkUrlProtocolStatus() 验证
- IF 成功:
- 记录日志:"第 {retry} 次重试成功"
- 更新状态,退出循环
- ELSE:
- 记录日志:"第 {retry} 次重试失败"
- IF 7次全部失败:
- 记录日志:"已达最大重试次数(7次),注册失败"
- 显示错误消息
```
### 6.4 按钮状态自动切换
根据 `urlStatus.registered` 动态渲染:
| 状态 | 按钮文本 | 按钮类型 | 点击行为 |
| ------ | --------------- | -------- | --------------------------------- |
| 未注册 | "注册 URL 协议" | primary | 执行注册(含重试) |
| 已注册 | "重新注册" | default | 执行注册(覆盖注册+验证) |
| 已注册 | "取消注册" | danger | 执行 unregisterUrlProtocol + 验证 |
### 6.5 操作日志展示
在 URL 协议卡片底部增加一个可折叠的 `<Collapse>` 或简洁的 `<Typography.Paragraph>` 区域,展示最近的操作日志(最多保留最新 20 条),使用 `fontSize: 12px, fontFamily: monospace` 样式。
---
## 步骤 7i18n 翻译
**文件**: `src/i18n/locales/` 下所有 10 个语言文件
`settings.url` 下新增以下键:
| 键 | zh-CN | en-US |
| ---------------------- | ----------------------------- | --------------------------------------------- |
| `checkStatus` | "检测状态" | "Check Status" |
| `reRegister` | "重新注册" | "Re-register" |
| `unregister` | "取消注册" | "Unregister" |
| `unregistered` | "URL 协议已取消注册" | "URL protocol unregistered" |
| `unregisterFailed` | "取消注册失败" | "Failed to unregister" |
| `statusRegistered` | "已注册" | "Registered" |
| `statusNotRegistered` | "未注册" | "Not Registered" |
| `statusCheckFailed` | "状态检测失败" | "Status check failed" |
| `retrying` | "重试中 ({current}/{max})" | "Retrying ({current}/{max})" |
| `retryFailed` | "已达最大重试次数,注册失败" | "Max retries reached, registration failed" |
| `retrySuccess` | "第 {n} 次重试成功" | "Retry #{n} succeeded" |
| `operationLog` | "操作日志" | "Operation Log" |
| `logRegisterStart` | "开始注册 URL 协议..." | "Starting URL protocol registration..." |
| `logRegisterVerify` | "注册命令已执行,正在验证..." | "Registration command executed, verifying..." |
| `logRegisterSuccess` | "注册验证成功" | "Registration verified successfully" |
| `logRegisterFailed` | "注册验证失败" | "Registration verification failed" |
| `logUnregisterStart` | "正在取消注册..." | "Unregistering..." |
| `logUnregisterSuccess` | "取消注册成功" | "Unregistered successfully" |
| `logUnregisterFailed` | "取消注册失败" | "Unregister failed" |
| `logMaxRetries` | "已达最大重试次数 (7次)" | "Max retries (7) reached" |
其余 9 个语言文件同步翻译。
---
## 步骤 8:运行测试与格式化
1. 执行 `pnpm run typecheck`(如有)检查前端类型
2. 执行 `cargo check` 检查 Rust 编译
3. 执行格式化命令
4. 运行测试套件
---
## 实现顺序
1. ✅ 步骤 1Rust - `check_url_protocol_status`
2. ✅ 步骤 2Rust - `unregister_url_protocol`
3. ✅ 步骤 3Rust - 增强 `register_url_protocol`
4. ✅ 步骤 4Rust - 注册新命令到 lib.rs
5. ✅ 步骤 5:前端 API 类型
6. ✅ 步骤 6:前端 Settings.tsx UI
7. ✅ 步骤 7i18n 翻译
8. ✅ 步骤 8:测试与格式化