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