launcher_plugin/
jsonrpc.rs

1use crate::error::LauncherError;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4/// JsonRPC 请求数据
5#[derive(Debug, Serialize, Deserialize)]
6pub struct JsonRpcRequest {
7    pub method: Method,
8    pub parameters: Vec<Option<String>>,
9    pub settings: serde_json::Value,
10    pub id: i32,
11    pub error: serde_json::Value,
12}
13
14/// JsonRPC 请求方法
15#[derive(Debug)]
16pub enum Method {
17    /// 查询方法
18    Query,
19    /// 设置菜单方法
20    ContextMenu,
21    /// 自定义方法
22    /// #[serde(untagged)] 可以让 method":{"custom":"copy"} 变成 method":"copy"
23    Custom(String),
24}
25
26/// 自定义序列化
27impl Serialize for Method {
28    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
29    where
30        S: Serializer,
31    {
32        match self {
33            Method::Query => serializer.serialize_str("query"),
34            Method::ContextMenu => serializer.serialize_str("context_menu"),
35            Method::Custom(s) => serializer.serialize_str(s),
36        }
37    }
38}
39
40/// 自定义反序列化
41impl<'de> Deserialize<'de> for Method {
42    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43    where
44        D: Deserializer<'de>,
45    {
46        let s = String::deserialize(deserializer)?;
47        match s.as_str() {
48            "query" => Ok(Method::Query),
49            "context_menu" => Ok(Method::ContextMenu),
50            _ => Ok(Method::Custom(s)),
51        }
52    }
53}
54
55impl JsonRpcRequest {
56    /// 将JsonRPC请求反序列化
57    pub fn from(argument: &String) -> Result<Self, LauncherError> {
58        let input = serde_json::from_str::<JsonRpcRequest>(argument)?;
59        Ok(input)
60    }
61
62    /// 获取第一个参数
63    pub fn get_parameter(&self) -> String {
64        self.parameters[0].clone().unwrap_or("".to_string())
65    }
66
67    /// 设置响应
68    pub fn set_response(&self, response: JsonRpcResponse) -> Result<(), LauncherError> {
69        println!("{}", response.to_unicode_string()?);
70        Ok(())
71    }
72
73    /// 设置简单响应
74    pub fn set_simple_response<S: Into<String>>(
75        &self,
76        title: S,
77        sub_title: S,
78        icon_path: S,
79        action: Option<JsonRpcAction>,
80    ) -> Result<(), LauncherError> {
81        let mut query_data = JsonRpcResponse::new();
82        let item = JsonRpcResponseDataBuilder::new()
83            .title(title)
84            .sub_title(sub_title)
85            .icon_path(icon_path)
86            .json_rpcaction(action)
87            .build();
88
89        query_data.add_data(item);
90        let response = query_data.to_unicode_string().unwrap();
91        tracing::info!("simple_response响应数据: {}", response);
92
93        println!("{}", response);
94        Ok(())
95    }
96
97    /// 转换为字符串,方便调试
98    pub fn to_string(&self) -> Result<String, LauncherError> {
99        Ok(serde_json::to_string(&self)?)
100    }
101}
102
103/// 点击后触发操作
104/// 有些操作,没有反应【不知道咋回事】
105/// 官方API:<https://www.flowlauncher.com/docs/#/json-rpc?id=api-list>
106#[derive(Debug, Serialize, Clone)]
107pub struct JsonRpcAction {
108    #[serde(rename = "method")]
109    pub method: String,
110    #[serde(rename = "parameters")]
111    pub parameters: Vec<String>,
112}
113
114impl JsonRpcAction {
115    /// 自定义动作,需要自己手动处理响应
116    /// method: 自定义名称
117    pub fn custom<S: Into<String>>(method: S, parameters: Vec<S>) -> Self {
118        Self {
119            method: method.into(),
120            parameters: parameters.into_iter().map(|s| s.into()).collect(),
121        }
122    }
123
124    /// 官方API: change flow launcher query
125    /// 更改流程启动器查询
126    pub fn change_query<S: Into<String>>(query: S, requery: bool) -> Self {
127        Self {
128            method: "Flow.Launcher.ChangeQuery".to_string(),
129            parameters: vec![query.into(), requery.to_string()],
130        }
131    }
132
133    /// 官方API: restart Flow Launcher
134    /// 重启 Flow Launcher
135    pub fn restart_app() -> Self {
136        Self {
137            method: "Flow.Launcher.RestartApp".to_string(),
138            parameters: vec![],
139        }
140    }
141
142    /// 官方API:关闭 Flow Launcher
143    pub fn close_app() -> Self {
144        Self {
145            method: "Flow.Launcher.CloseApp".to_string(),
146            parameters: vec![],
147        }
148    }
149
150    /// 官方API:Save everything, all of Flow Launcher and plugins' data and settings
151    /// 保存所有内容,包括 Flow Launcher 和插件的所有数据和设置
152    pub fn save_app_all_setings() -> Self {
153        Self {
154            method: "Flow.Launcher.SaveAppAllSettings".to_string(),
155            parameters: vec![],
156        }
157    }
158
159    /// 官方API: 检查更新
160    pub fn check_for_new_update() -> Self {
161        Self {
162            method: "Flow.Launcher.CheckForNewUpdate".to_string(),
163            parameters: vec![],
164        }
165    }
166
167    /// 官方API: run shell commands
168    /// 运行shell命令
169    pub fn shell_run<S: Into<String>>(cmd: S) -> Self {
170        Self {
171            method: "Flow.Launcher.ShellRun".to_string(),
172            parameters: vec![cmd.into()],
173        }
174    }
175
176    /// 官方API:隐藏 Flow Launcher
177    pub fn hide_app() -> Self {
178        Self {
179            method: "Flow.Launcher.HideApp".to_string(),
180            parameters: vec![],
181        }
182    }
183
184    /// 官方API:显示 Flow Launcher
185    pub fn show_app() -> Self {
186        Self {
187            method: "Flow.Launcher.ShowApp".to_string(),
188            parameters: vec![],
189        }
190    }
191
192    /// 官方API: show messagebox
193    /// 显示消息框
194    pub fn show_msg<S: Into<String>>(title: S, sub_title: S, ico_path: S) -> Self {
195        Self {
196            method: "Flow.Launcher.ShowMsg".to_string(),
197            parameters: vec![title.into(), sub_title.into(), ico_path.into()],
198        }
199    }
200
201    /// 官方API: 获取当前语言的翻译
202    pub fn get_translation() -> Self {
203        Self {
204            method: "Flow.Launcher.GetTranslation".to_string(),
205            parameters: vec![],
206        }
207    }
208    /// 官方API: 打开设置对话框
209    pub fn open_setting_dialog() -> Self {
210        Self {
211            method: "Flow.Launcher.OpenSettingDialog".to_string(),
212            parameters: vec![],
213        }
214    }
215
216    /// 官方API: 获取所有插件
217    pub fn get_all_plugins() -> Self {
218        Self {
219            method: "Flow.Launcher.GetAllPlugins".to_string(),
220            parameters: vec![],
221        }
222    }
223
224    /// 官方API: 启动加载动画
225    pub fn start_loading_bar() -> Self {
226        Self {
227            method: "Flow.Launcher.StartLoadingBar".to_string(),
228            parameters: vec![],
229        }
230    }
231
232    /// 官方API: 关闭加载动画
233    pub fn stop_loading_bar() -> Self {
234        Self {
235            method: "Flow.Launcher.StopLoadingBar".to_string(),
236            parameters: vec![],
237        }
238    }
239
240    /// 官方API: 重新加载插件数据
241    pub fn reload_all_plugin_data() -> Self {
242        Self {
243            method: "Flow.Launcher.ReloadAllPluginData".to_string(),
244            parameters: vec![],
245        }
246    }
247}
248
249/// JsonRPC 响应数据
250#[derive(Debug, Serialize)]
251pub struct JsonRpcResponseData {
252    #[serde(rename = "Title")]
253    pub title: String,
254    #[serde(rename = "SubTitle")]
255    pub sub_title: String,
256    /// 排名....
257    #[serde(rename = "score")]
258    #[serde(skip_serializing_if = "Option::is_none")]
259    pub score: Option<i32>,
260    #[serde(rename = "IcoPath")]
261    pub ico_path: String,
262    #[serde(rename = "JsonRPCAction")]
263    #[serde(skip_serializing_if = "Option::is_none")]
264    pub json_rpcaction: Option<JsonRpcAction>,
265}
266
267/// JsonRPC 响应数据
268#[derive(Debug, Serialize)]
269pub struct JsonRpcResponse {
270    #[serde(rename = "result")]
271    pub result: Vec<JsonRpcResponseData>,
272}
273
274impl JsonRpcResponse {
275    pub fn new() -> Self {
276        Self { result: Vec::new() }
277    }
278    /// 添加响应数据
279    pub fn add_data(&mut self, data: JsonRpcResponseData) {
280        self.result.push(data);
281    }
282
283    /// 有中文会报错,使用unicode转义
284    pub fn to_unicode_string(&self) -> Result<String, LauncherError> {
285        let data = serde_json::to_string(&self)?;
286        Ok(self.escape_non_ascii(&data))
287    }
288
289    /// 将中文转换为 unicode
290    fn escape_non_ascii(&self, s: &str) -> String {
291        let mut escaped = String::with_capacity(s.len());
292        for ch in s.chars() {
293            if ch.is_ascii() {
294                escaped.push(ch);
295            } else {
296                let code = ch as u32;
297                escaped.push_str(&format!("\\u{:04x}", code));
298            }
299        }
300        escaped
301    }
302}
303
304/// JsonRpcResponse 构建器
305pub struct JsonRpcResponseDataBuilder {
306    /// 标题
307    pub title: String,
308    /// 副标题
309    pub sub_title: String,
310    /// 排名分数,0-100,分数越大越靠前
311    pub score: Option<i32>,
312    /// 显示图标
313    pub ico_path: String,
314    /// 点击触发操作
315    pub json_rpcaction: Option<JsonRpcAction>,
316}
317impl JsonRpcResponseDataBuilder {
318    pub fn new() -> JsonRpcResponseDataBuilder {
319        Self {
320            title: "".to_string(),
321            sub_title: "".to_string(),
322            score: None,
323            ico_path: "".to_string(),
324            json_rpcaction: None,
325        }
326    }
327    /// 设置标题
328    pub fn title<S: Into<String>>(mut self, title: S) -> Self {
329        self.title = title.into();
330        self
331    }
332
333    /// 设置副标题
334    pub fn sub_title<S: Into<String>>(mut self, sub_title: S) -> Self {
335        self.sub_title = sub_title.into();
336        self
337    }
338
339    /// 设置Score
340    pub fn score(mut self, score: i32) -> Self {
341        self.score = Some(score);
342        self
343    }
344
345    /// 设置图标
346    pub fn icon_path<S: Into<String>>(mut self, ico_path: S) -> Self {
347        self.ico_path = ico_path.into();
348        self
349    }
350
351    /// 设置点击触发执行操作
352    pub fn json_rpcaction(mut self, json_rpcaction: Option<JsonRpcAction>) -> Self {
353        self.json_rpcaction = json_rpcaction;
354        self
355    }
356
357    /// 构建JsonRpcResponseData 响应数据
358    pub fn build(&self) -> JsonRpcResponseData {
359        JsonRpcResponseData {
360            title: self.title.clone(),
361            sub_title: self.sub_title.clone(),
362            score: self.score,
363            ico_path: self.ico_path.clone(),
364            json_rpcaction: self.json_rpcaction.clone(),
365        }
366    }
367}