Skip to main content

zerolaunch_plugin_api/host/
plugin_host.rs

1//! PluginHost — 宿主操作契约(插件 → 宿主的单向中转接缝)。
2//!
3//! 插件持有的 `PluginHandle` 只保存插件身份/配置/能力集,不保存任何服务实现;
4//! 全部可调用操作通过本契约委托给宿主执行(进程内实现为 src-tauri 的 `HostApi`,
5//! 测试实现为 mock 桩宿主)。宿主在实现中决定「直接处理宿主级服务」还是
6//! 「转发到平台实现」(`crates/plugin-api/src/platform` 的 PlatformServices)。
7//!
8//! 作用域约定:需要按插件隔离的操作(资源/缓存路径、回调 ID 前缀、图标缓存等级)
9//! 由委托方(PluginHandle / RPC 宿主侧接收端)显式传入插件身份参数,
10//! 使宿主可复用同一执行节点服务所有插件。
11
12use std::collections::HashMap;
13use std::path::Path;
14use std::time::Duration;
15
16use async_trait::async_trait;
17
18use crate::host::{CacheLevel, HostApiError, OpenTarget};
19use crate::services::app::AppInfo;
20use crate::services::focus_monitor::FocusCallback;
21use crate::services::hotkey::types::{HotkeyCallback, HotkeyEventFilter};
22use crate::services::installation_monitor::types::InstallationCallback;
23use crate::services::model::{
24    ModelChatRequest, ModelChatResponse, ModelEmbeddingRequest, ModelEmbeddingResponse, ModelError,
25    ModelInfo, ModelSimilarityRequest, ModelSimilarityResponse,
26};
27use crate::services::parameter::types::ParameterSnapshot;
28use crate::services::path::path_resolver::KnownPath;
29use crate::services::shell::CommandRunMode;
30use crate::services::theme::Theme;
31use crate::services::timer::types::{TimerCallback, TimerId};
32use crate::services::IconRequest;
33
34/// 宿主操作契约。实现方为宿主(真实 HostApi)或测试桩宿主。
35#[async_trait]
36pub trait PluginHost: Send + Sync {
37    // ===== 图标服务 =====
38
39    /// 根据图标请求提取图标数据,行为由缓存等级决定。
40    /// 参数:request - 图标请求;level - 插件配置的缓存等级。
41    /// 返回:WebP 格式的图标字节数据(回退路径可能为 PNG),失败返回 HostApiError。
42    async fn get_icon(
43        &self,
44        request: &IconRequest,
45        level: CacheLevel,
46    ) -> Result<Vec<u8>, HostApiError>;
47
48    /// 提取图标数据,失败时回退到默认图标(永不返回错误)。
49    async fn get_icon_or_default(&self, request: &IconRequest, level: CacheLevel) -> Vec<u8>;
50
51    /// 强制从磁盘提取图标数据并根据缓存等级更新缓存(跳过缓存读取)。
52    async fn get_icon_and_update_cache(
53        &self,
54        request: &IconRequest,
55        level: CacheLevel,
56    ) -> Result<Vec<u8>, HostApiError>;
57
58    /// 覆盖指定 IconRequest 的缓存图标为自定义图标文件。
59    /// 参数:original_request - 需要覆盖图标的原始 IconRequest;
60    ///       custom_icon_path - 用户选择的自定义图标文件路径。
61    async fn override_icon_cache(
62        &self,
63        original_request: &IconRequest,
64        custom_icon_path: &str,
65    ) -> Result<(), HostApiError>;
66
67    // ===== Shell 服务 =====
68
69    /// 使用系统默认方式打开目标(文件/网址/文件夹)。
70    async fn shell_open(&self, target: OpenTarget) -> Result<(), HostApiError>;
71
72    /// 在文件资源管理器中打开指定路径的父目录并选中该文件。
73    async fn shell_open_folder(&self, path: &str) -> Result<(), HostApiError>;
74
75    /// 以管理员权限启动程序。
76    async fn shell_execute_elevation(&self, path: &str) -> Result<(), HostApiError>;
77
78    /// 执行命令字符串。
79    /// 参数:command - 要执行的命令字符串;mode - 执行方式(后台静默 / 可见控制台窗口)。
80    async fn shell_execute_command(
81        &self,
82        command: &str,
83        mode: CommandRunMode,
84    ) -> Result<(), HostApiError>;
85
86    // ===== 窗口服务 =====
87
88    /// 根据进程名(如 "chrome.exe")激活已存在的窗口。
89    /// 返回:成功激活返回 Ok(true),未找到窗口返回 Ok(false)。
90    async fn activate_window_by_process(&self, process_name: &str) -> Result<bool, HostApiError>;
91
92    /// 根据窗口标题的部分内容激活已存在的窗口。
93    async fn activate_window_by_title(&self, title: &str) -> Result<bool, HostApiError>;
94
95    /// 根据进程 PID 激活已存在的窗口。
96    async fn activate_window_by_pid(&self, pid: u32) -> Result<bool, HostApiError>;
97
98    // ===== 路径服务 =====
99
100    /// 根据已知路径类型解析实际文件系统路径。
101    fn resolve_path(&self, path: KnownPath) -> Result<String, HostApiError>;
102
103    // ===== 剪贴板服务 =====
104
105    /// 将文本写入系统剪贴板。
106    fn set_clipboard_text(&self, text: &str) -> Result<(), HostApiError>;
107
108    // ===== 应用服务 =====
109
110    /// 枚举当前平台已安装的应用。
111    async fn enumerate_apps(&self) -> Vec<AppInfo>;
112
113    /// 启动指定应用。返回:成功返回 Ok(pid)。
114    async fn launch_app(&self, app_id: &str, args: Option<&[String]>) -> Result<u32, HostApiError>;
115
116    // ===== 应用资源服务 =====
117
118    /// 根据名称获取内置图标资源的文件系统路径,未注册则返回 None。
119    fn get_app_icon_path(&self, name: &str) -> Option<String>;
120
121    // ===== 快捷方式解析 =====
122
123    /// 解析 .lnk 快捷方式文件的目标路径,失败返回 None。
124    fn resolve_lnk_target(&self, lnk_path: &str) -> Option<String>;
125
126    /// 解析指定目录下的 desktop.ini 文件,提取 [LocalizedFileNames] 部分。
127    fn parse_localized_names_from_dir(&self, dir_path: &Path) -> HashMap<String, String>;
128
129    // ===== 主题服务 =====
130
131    /// 查询宿主当前实际生效的界面主题。
132    /// 显式 light/dark 配置直接返回;system 模式委托平台读取系统主题。
133    fn get_theme(&self) -> Result<Theme, HostApiError>;
134
135    /// 查询系统主题(未应用宿主显式 light/dark 配置),供前端 system 模式跟随。
136    fn get_system_theme(&self) -> Result<Theme, HostApiError>;
137
138    // ===== 模型服务 =====
139
140    /// 全网模型清单(聚合缓存,含所有已注册提供方)。
141    fn model_list(&self) -> Vec<ModelInfo>;
142
143    /// 按 model_id 调用文本生成。
144    async fn model_chat(&self, req: ModelChatRequest) -> Result<ModelChatResponse, ModelError>;
145
146    /// 按 model_id 调用文本向量化(task_type 必填,宿主对缺失/未知值返回 InvalidRequest)。
147    async fn model_embedding(
148        &self,
149        req: ModelEmbeddingRequest,
150    ) -> Result<ModelEmbeddingResponse, ModelError>;
151
152    /// 按 model_id 计算查询向量与多个目标向量的相似度。
153    async fn model_similarity(
154        &self,
155        req: ModelSimilarityRequest,
156    ) -> Result<ModelSimilarityResponse, ModelError>;
157
158    // ===== 参数解析服务 =====
159
160    /// 解析参数模板。返回:填充后的完整字符串。
161    async fn resolve_parameters(
162        &self,
163        template: &str,
164        user_args: &[String],
165        snapshot: &ParameterSnapshot,
166    ) -> Result<String, HostApiError>;
167
168    /// 统计模板中需要用户输入的参数数量。
169    fn count_user_parameters(&self, template: &str) -> usize;
170
171    /// 检查模板是否包含系统参数。
172    fn has_system_parameters(&self, template: &str) -> bool;
173
174    // ===== 定时器服务(插件作用域) =====
175
176    /// 创建一个一次性定时器,在指定延迟后触发回调。
177    /// 参数:plugin_id - 插件 ID(记录定时器归属,供按插件取消);
178    ///       delay - 延迟时长;callback - 到期回调。
179    async fn set_timeout(
180        &self,
181        plugin_id: &str,
182        delay: Duration,
183        callback: TimerCallback,
184    ) -> Result<TimerId, HostApiError>;
185
186    /// 创建一个重复定时器,每隔指定间隔触发回调。
187    /// 参数:plugin_id - 插件 ID(记录定时器归属,供按插件取消);
188    ///       interval - 触发间隔;callback - 每次到期的回调。
189    async fn set_interval(
190        &self,
191        plugin_id: &str,
192        interval: Duration,
193        callback: TimerCallback,
194    ) -> Result<TimerId, HostApiError>;
195
196    /// 取消指定插件的指定定时器。
197    /// 语义:未知 ID(从未创建 / 已触发移除)幂等成功;仅归属明确属于他插件时返回错误。
198    async fn cancel_timer(&self, plugin_id: &str, id: TimerId) -> Result<(), HostApiError>;
199
200    /// 取消指定插件的全部定时器(不影响其他插件的定时器,best-effort 逐个取消)。
201    async fn cancel_all_timers(&self, plugin_id: &str) -> Result<(), HostApiError>;
202
203    // ===== 资源管理(插件作用域) =====
204
205    /// 上传资源文件到指定插件的资源空间。
206    /// 参数:plugin_id - 插件 ID(决定存储命名空间)。
207    async fn resource_upload(
208        &self,
209        plugin_id: &str,
210        resource_id: &str,
211        file_path: &str,
212        max_size: Option<u64>,
213    ) -> Result<String, HostApiError>;
214
215    /// 直接写入资源字节数据,无需本地路径。
216    async fn resource_put(
217        &self,
218        plugin_id: &str,
219        resource_id: &str,
220        data: &[u8],
221    ) -> Result<(), HostApiError>;
222
223    /// 获取资源文件内容。
224    async fn resource_get(
225        &self,
226        plugin_id: &str,
227        resource_id: &str,
228    ) -> Result<Vec<u8>, HostApiError>;
229
230    /// 删除资源文件。
231    async fn resource_delete(&self, plugin_id: &str, resource_id: &str)
232        -> Result<(), HostApiError>;
233
234    /// 列出指定插件的所有资源。
235    async fn resource_list(&self, plugin_id: &str) -> Result<Vec<String>, HostApiError>;
236
237    // ===== 本地缓存(插件作用域) =====
238
239    /// 写入插件本地缓存(可再生的本地数据,不经 StorageService,仅落在本地缓存目录)。
240    async fn cache_put(
241        &self,
242        plugin_id: &str,
243        domain: &str,
244        key: &str,
245        data: &[u8],
246    ) -> Result<(), HostApiError>;
247
248    /// 读取插件本地缓存;缓存不存在时返回 Ok(None)。
249    async fn cache_get(
250        &self,
251        plugin_id: &str,
252        domain: &str,
253        key: &str,
254    ) -> Result<Option<Vec<u8>>, HostApiError>;
255
256    /// 删除插件本地缓存条目;缓存不存在时视为成功。
257    async fn cache_delete(
258        &self,
259        plugin_id: &str,
260        domain: &str,
261        key: &str,
262    ) -> Result<(), HostApiError>;
263
264    /// 容量控制:缓存域条目超过 max_entries 时按修改时间删除最旧条目。
265    async fn cache_cleanup(
266        &self,
267        plugin_id: &str,
268        domain: &str,
269        max_entries: usize,
270    ) -> Result<(), HostApiError>;
271
272    // ===== 推送式回调注册(插件作用域) =====
273
274    /// 注册按键事件回调。ID 自动前缀化为 "{plugin_id}:{id}"。
275    fn register_hotkey_callback(
276        &self,
277        plugin_id: &str,
278        id: &str,
279        filter: HotkeyEventFilter,
280        callback: HotkeyCallback,
281    );
282
283    /// 注销按键事件回调。
284    fn unregister_hotkey_callback(&self, plugin_id: &str, id: &str);
285
286    /// 注册安装事件回调。ID 自动前缀化为 "{plugin_id}:{id}"。
287    fn register_installation_callback(
288        &self,
289        plugin_id: &str,
290        id: &str,
291        callback: InstallationCallback,
292    );
293
294    /// 注销安装事件回调。
295    fn unregister_installation_callback(&self, plugin_id: &str, id: &str);
296
297    /// 注册焦点事件回调。ID 自动前缀化为 "{plugin_id}:{id}"。
298    fn register_focus_callback(&self, plugin_id: &str, id: &str, callback: FocusCallback);
299
300    /// 注销焦点事件回调。
301    fn unregister_focus_callback(&self, plugin_id: &str, id: &str);
302}