tauri_elm/
lib.rs

1use directories::ProjectDirs;
2use std::{
3    error::Error,
4    fmt,
5    fs::create_dir_all,
6    io::{Read, Write},
7    sync::Mutex,
8};
9use tauri::{plugin::TauriPlugin, Manager, Runtime};
10
11pub fn init<R: Runtime>() -> TauriPlugin<R> {
12    tauri::plugin::Builder::new("tauri-elm")
13        .invoke_handler(tauri::generate_handler![
14            http_request,
15            read_file,
16            write_file,
17        ])
18        .setup(|app_handler| {
19            if let Some(proj_dir) = ProjectDirs::from("com", "tauri-elm", "test-app") {
20                if let Err(err) = create_dir_all(proj_dir.data_dir()) {
21                    Err(Box::new(SetupError(format!(
22                        "Could not create data dir: {}",
23                        err
24                    ))))
25                } else {
26                    app_handler.manage(default_state(proj_dir));
27                    Ok(())
28                }
29            } else {
30                Err(Box::new(SetupError("Could not setup plugin".into())))
31            }
32        })
33        .build()
34}
35
36#[derive(Debug)]
37struct SetupError(String);
38
39impl fmt::Display for SetupError {
40    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41        write!(f, "There is an error: {}", self.0)
42    }
43}
44
45impl Error for SetupError {}
46
47#[derive(serde::Serialize)]
48struct Response {
49    status: u16,
50    body: String,
51}
52
53#[derive(serde::Deserialize)]
54struct Request {
55    url: String,
56}
57
58#[tauri::command(async)]
59async fn http_request(request: Request) -> Result<Response, String> {
60    let resp = reqwest::get(request.url).await;
61    match resp {
62        Ok(r) => {
63            let status_code = r.status().as_u16();
64            match r.text().await {
65                Ok(b) => Ok(Response {
66                    body: b,
67                    status: status_code,
68                }),
69                Err(err) => Err(format!("Could not get text from response: {}", err)),
70            }
71        }
72        Err(err) => Err(format!("Could not make request: {}", err)),
73    }
74}
75
76#[tauri::command]
77fn read_file(state: tauri::State<AppState>, name: String) -> Result<String, String> {
78    let app_state = state.0.lock().unwrap();
79    let path = app_state.proj_dir.data_dir().join(name);
80
81    let file = std::fs::OpenOptions::new()
82        .write(true)
83        .read(true)
84        .create(true)
85        .open(&path);
86
87    match file {
88        Ok(mut f) => {
89            let mut buf = String::new();
90            match f.read_to_string(&mut buf) {
91                Ok(_) => Ok(buf),
92                Err(err) => Err(format!("--- {}", err)),
93            }
94        }
95        Err(err) => Err(format!("<<< {} {}", path.display().to_string(), err)),
96    }
97}
98
99#[tauri::command]
100fn write_file(state: tauri::State<AppState>, name: String, data: String) -> Result<(), String> {
101    let app_state = state.0.lock().unwrap();
102    let path = app_state.proj_dir.data_dir().join(name);
103
104    let file = std::fs::OpenOptions::new()
105        .write(true)
106        .create(true)
107        .open(&path);
108
109    println!("saving the data: {}", data);
110
111    match file {
112        Ok(mut f) => match f.write_all(&data.as_bytes()) {
113            Ok(()) => Ok(()),
114            Err(err) => Err(err.to_string()),
115        },
116        Err(err) => Err(format!("{} {}", path.display().to_string(), err)),
117    }
118}
119
120struct AppState(Mutex<App>);
121
122struct App {
123    // authenticate: bool,
124    // keys: std::collections::HashMap<String, String>,
125    proj_dir: ProjectDirs,
126}
127
128fn default_state(proj_dir: ProjectDirs) -> AppState {
129    AppState(Mutex::new(App {
130        // authenticate: false,
131        // keys: std::collections::HashMap::new(),
132        proj_dir,
133    }))
134}