zerolaunch_plugin_api/plugin/plugin_trait.rs
1use crate::config::configurable::Configurable;
2use crate::host::plugin_handle::PluginHandle;
3use crate::plugin::trigger::keyword_trigger_match;
4use crate::plugin::types::{PanelInteraction, PluginContext, PluginError, Query, QueryResponse};
5use async_trait::async_trait;
6use std::sync::Arc;
7
8/// 所有插件对象都需实现的核心契约。
9/// 服务于插件生命周期管理、查询处理与动作执行。
10/// 配置管理能力由 Configurable trait 提供。
11#[async_trait]
12pub trait Plugin: Configurable {
13 /// 插件初始化钩子。
14 ///
15 /// `handle` 为宿主注入的平台服务句柄:进程内(内置)插件持有
16 /// `Some(Arc<PluginHandle>)`;远端插件进程无宿主句柄(跨进程不可序列化),
17 /// 收到 `None`,平台能力经 SDK `host()` 的 host/* RPC 访问。
18 async fn init(
19 &self,
20 ctx: &PluginContext,
21 handle: Option<Arc<PluginHandle>>,
22 ) -> Result<(), PluginError>;
23
24 /// 插件退出钩子:宿主在关闭插件前调用,插件在此完成收尾
25 /// (保存状态、停止后台任务、释放外部资源等)。
26 ///
27 /// 由宿主统一调用,插件类型不改变语义:内置插件进程内直调;远端插件由宿主
28 /// 适配器翻译为 `plugin/shutdown` RPC(有超时上限),超时或失败仍继续关闭。
29 /// 进程崩溃时不会调用(进程已不可达)。
30 ///
31 /// 默认实现为空操作,插件按需覆盖。
32 async fn on_shutdown(&self, _ctx: &PluginContext) -> Result<(), PluginError> {
33 Ok(())
34 }
35
36 async fn query(&self, ctx: &PluginContext, query: &Query)
37 -> Result<QueryResponse, PluginError>;
38
39 /// 执行插件动作。
40 /// `action_id` 为插件在 `ListItem.actions` / `CustomPanel.actions` / 面板按键
41 /// 绑定中声明的动作标识;`payload` 形状由触发通道决定(插件应两种都兼容):
42 /// - 候选确认通道(搜索栏结果列表 / 行内参数 / 参数面板确认):
43 /// `{"candidate_id": <u64>, "query_text": <str>, "user_args": [<str>]}`;
44 /// - 面板动作通道(`PanelKeyAction::Custom` 面板按键绑定):插件自定义自由 JSON,
45 /// 宿主原样透传。
46 async fn execute_action(
47 &self,
48 ctx: &PluginContext,
49 action_id: &str,
50 payload: serde_json::Value,
51 ) -> Result<(), PluginError>;
52
53 /// 返回插件当前生效的交互策略(防抖延迟、提交行为等)。
54 /// 这是一次快速、同步的调用,不涉及 IO 或网络。
55 /// 默认返回无防抖、Execute 提交的交互策略。
56 fn interaction_policy(&self) -> PanelInteraction {
57 PanelInteraction::default()
58 }
59
60 /// 查询匹配:判定当前原始输入是否由本插件接管(行内插件路由的唯一判定入口)。
61 ///
62 /// 默认实现即**框架的关键词判定**:`declared_trigger_keywords`(宿主随判定请求传入的、
63 /// 该插件在清单/代码中声明的触发词)中任一项等于输入首词且其后有内容时返回 `true`。
64 /// 因此不覆盖本方法的插件行为与旧版关键词路由完全一致。
65 ///
66 /// 需要自定义判定的插件覆盖本方法即可(如形态检测器),自行决定何时返回 `true`。
67 ///
68 /// 契约:必须快速、**不涉及 IO 或网络**(每次按键都会执行,慢判定直接体现为输入延迟);
69 /// 存在性/可达性等需要 IO 的判定放到 `query()` 内(那里是 async 且可自行超时)。
70 /// 远端插件经 `plugin/match_query` RPC 调用;旧 SDK 未实现该方法时宿主按
71 /// `METHOD_NOT_FOUND` 用同一份关键词判定兜底,失败/超时按不命中处理。
72 async fn match_query(&self, raw_query: &str, declared_trigger_keywords: &[String]) -> bool {
73 keyword_trigger_match(declared_trigger_keywords, raw_query).is_some()
74 }
75}