1use crate::{
2 core::{App, start_new_entry},
3 os::wakeup_window,
4 ui::EntryData,
5 utils::LogErr,
6};
7use crossfire::mpsc;
8use interprocess::local_socket::{
9 GenericNamespaced, ListenerOptions,
10 tokio::{Stream, prelude::*},
11};
12use serde::{Deserialize, Serialize};
13use slint::VecModel;
14use std::{process::exit, rc::Rc};
15use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
16use url::Url;
17
18pub const NS_NAME: &str = "top.s121.fd.sock";
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct DownloadOptions {
23 pub url: Url,
24 pub headers: Option<String>,
25 pub save_dir: Option<String>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(tag = "type")]
30pub enum IpcMessage {
31 WakeUp,
32 Download(DownloadOptions),
33}
34
35pub async fn check_ipc_and_wake() -> color_eyre::Result<()> {
37 let ns_name = NS_NAME.to_ns_name::<GenericNamespaced>()?;
38 if let Ok(mut stream) = Stream::connect(ns_name).await {
39 tracing::info!("发现已有实例,正在发送唤醒信号...");
40 let msg = IpcMessage::WakeUp;
41 if let Ok(json) = serde_json::to_string(&msg) {
42 let _ = stream.write_all(format!("{json}\n").as_bytes()).await;
43 }
44 exit(0);
45 }
46 Ok(())
47}
48
49pub async fn init_ipc(app: App, list_model: Rc<VecModel<EntryData>>) -> color_eyre::Result<()> {
51 let ns_name = NS_NAME.to_ns_name::<GenericNamespaced>()?;
52 let listener = ListenerOptions::new()
53 .name(ns_name)
54 .try_overwrite(true)
55 .create_tokio()?;
56
57 let (tx, rx) = mpsc::unbounded_async::<IpcMessage>();
58
59 let ui_weak = app.ui.clone();
60 slint::spawn_local(async move {
61 while let Ok(msg) = rx.recv().await {
62 match msg {
63 IpcMessage::WakeUp => {
64 tracing::info!("收到唤醒信号");
65 let _ = ui_weak.upgrade_in_event_loop(|ui| wakeup_window(&ui));
66 }
67 IpcMessage::Download(e) => {
68 tracing::info!("收到外部下载请求: {}", e.url);
69 let mut config = app.db.get_ui_download_config();
70 if let Some(s) = e.headers {
71 config.headers = s.into();
72 }
73 if let Some(s) = e.save_dir {
74 config.save_dir = s.into();
75 }
76 start_new_entry(&app, e.url, &config, &list_model);
77 }
78 }
79 }
80 })
81 .log_err("IPC 消息处理任务失败")?;
82
83 tokio::spawn(async move {
84 loop {
85 match listener.accept().await {
86 Ok(conn) => {
87 let tx = tx.clone();
88 tokio::spawn(async move {
89 let mut reader = BufReader::new(conn);
90 let mut buffer = String::new();
91 if reader.read_line(&mut buffer).await.is_ok()
92 && let Ok(msg) = serde_json::from_str::<IpcMessage>(&buffer)
93 {
94 let _ = tx.send(msg);
95 }
96 });
97 }
98 Err(e) => tracing::error!(err = ?e, "监听连接出错"),
99 }
100 }
101 });
102 Ok(())
103}