1use crate::preset::Preset;
2#[cfg(feature = "online")]
3use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
4use serde::Deserialize;
5
6#[cfg(feature = "online")]
7const GH_API_URL: &str =
8 "https://api.github.com/repos/t-dantiau/community/git/trees/main?recursive=1";
9
10#[cfg(feature = "online")]
11const GH_COMMUNITY_PRESETS_URL: &str = "https://github.com/t-dantiau/Community/raw/main";
12
13
14pub struct Store {
15 pub base_path: String,
16 presets: Vec<Preset>,
17}
18
19#[derive(Deserialize, Debug)]
20pub struct GhApiUrlResponse {
21 pub tree: Vec<Tree>,
22 pub url: String,
23 pub sha: String,
24 pub truncated: bool,
25}
26
27#[derive(Deserialize, Debug)]
28pub struct Tree {
29 pub path: String,
30 pub mode: String,
31
32 #[serde(rename(deserialize = "type"))]
33 pub type_: String,
34 pub sha: String,
35 pub size: u32,
36 pub url: String,
37}
38
39impl Store {
40 pub fn new(base_path: String) -> Store {
41 if !std::path::Path::new(&base_path).exists() {
42 std::fs::create_dir_all(&base_path).unwrap();
43 }
44
45 Store {
46 base_path,
47 presets: Vec::new(),
48 }
49 }
50
51 pub fn load(&mut self) {
52 let paths = std::fs::read_dir(&self.base_path).unwrap();
53
54 for path in paths {
55 let path = path.unwrap().path();
56 let preset = Preset::from_file(&path.to_str().unwrap());
57 self.presets.push(preset);
58 }
59 }
60
61 pub fn add_preset(&mut self, preset: Preset) {
62 self.presets.push(preset);
63 }
64
65 pub fn remove_preset(&mut self, name: String) {
66 self.presets.retain(|p| p.name != name);
67
68 let path = format!("{}/{}.json", self.base_path, name);
69 std::fs::remove_file(path).unwrap();
70 }
71
72 pub fn get_preset(&self, name: String) -> Option<&Preset> {
73 self.presets.iter().find(|p| p.name == name)
74 }
75
76 pub fn save_presets(&self) {
77 for preset in &self.presets {
78 let path = format!("{}/{}.json", self.base_path, preset.name);
79 preset.to_file(&path);
80 }
81 }
82
83 #[cfg(feature = "online")]
84 fn construct_headers() -> HeaderMap {
85 let mut headers = HeaderMap::new();
86 headers.insert(USER_AGENT, HeaderValue::from_static("reqwest"));
87 headers
88 }
89
90 #[cfg(feature = "online")]
91 pub fn list_online_presets(&self) -> Vec<String> {
92 let client = reqwest::blocking::Client::new();
93 let res: GhApiUrlResponse = client
94 .get(GH_API_URL)
95 .headers(Store::construct_headers())
96 .send()
97 .unwrap()
98 .json()
99 .unwrap();
100
101 let mut online_presets = Vec::new();
102
103 for tree in res.tree {
104 let url = format!(
105 "{}/{}",
106 GH_COMMUNITY_PRESETS_URL, tree.path
107 );
108 online_presets.push(url);
109 }
110 online_presets
111 }
112
113 #[cfg(feature = "online")]
114 pub fn download_online_preset(&self, name: String) -> Result<Preset, reqwest::Error> {
115 let client = reqwest::blocking::Client::new();
116
117 let url = format!(
118 "{}/{}.json",
119 GH_COMMUNITY_PRESETS_URL, name
120 );
121
122 let resp = client
123 .get(&url)
124 .headers(Store::construct_headers())
125 .send()
126 .unwrap();
127 let content: Preset = resp.json().unwrap();
128 Ok(content)
129 }
130
131 pub fn list_local_presets(&self) -> Vec<String> {
132 let mut local_presets = Vec::new();
133 for preset in &self.presets {
134 local_presets.push(format!("{}/{}.json", self.base_path, preset.name));
135 }
136 local_presets
137 }
138}