1use std::{
2 collections::HashMap,
3 fs::File,
4 io::{self, Read},
5 path::Path,
6};
7
8use anyhow::Result;
9use serde::{Deserialize, Serialize};
10use serde_json::to_writer_pretty;
11
12#[derive(Debug, Serialize, Deserialize, Clone)]
14pub struct Dependency {
15 pub name: String,
16 pub version: String,
17}
18#[derive(Debug, Serialize, Deserialize)]
20pub struct PackageInfo {
21 pub package_name: String,
22 pub file_name: String,
23 pub version: String,
24 pub description: String,
25 pub hash: String,
26 pub dependencies: Option<Vec<Dependency>>,
27}
28
29impl PackageInfo {
30 pub fn new(
43 package_name: String,
44 file_name: String,
45 version: String,
46 description: String,
47 hash: String,
48 dependencies: Option<Vec<Dependency>>,
49 ) -> PackageInfo {
50 PackageInfo {
51 package_name,
52 file_name,
53 version,
54 description,
55 hash,
56 dependencies,
57 }
58 }
59}
60pub struct JsonStorage<T> {
62 _marker: std::marker::PhantomData<T>,
63}
64impl<T> JsonStorage<T>
65where
66 T: Serialize + for<'de> Deserialize<'de>,
67{
68 pub fn from_json(path: &Path) -> io::Result<T> {
76 let mut file_contents = String::new();
77 let mut file = File::open(path)?;
78 file.read_to_string(&mut file_contents)?;
79 let data: T = serde_json::from_str(&file_contents)?;
80 Ok(data)
81 }
82
83 pub fn to_json(data: &T, path: &Path) -> io::Result<()> {
89 let file = File::create(path)?;
90 to_writer_pretty(file, &data)?;
91 Ok(())
92 }
93
94 pub async fn from_url(url: &str) -> Result<T, Box<dyn std::error::Error>> {
102 let response = reqwest::get(url).await?.text().await?;
103 let repo_info: T = serde_json::from_str(&response)?;
104 Ok(repo_info)
105 }
106 pub fn from_str_to(file_contents: &str) -> io::Result<T> {
114 let data: T = serde_json::from_str(file_contents)?;
115 Ok(data)
116 }
117}
118
119#[derive(Debug, Serialize, Deserialize, Default)]
121pub struct RepoInfo {
122 packages: HashMap<String, PackageBasicInfo>,
124}
125#[derive(Debug, Serialize, Deserialize)]
126pub struct PackageBasicInfo {
128 pub url: String,
130 pub file_name: String,
132 pub version: String,
134 pub hash: String,
136 pub dependencies: Option<Vec<Dependency>>,
138}
139impl RepoInfo {
140 pub fn new() -> Self {
142 RepoInfo {
143 packages: HashMap::new(),
144 }
145 }
146 pub fn has_package(&self, package_name: &str) -> bool {
154 self.packages.contains_key(package_name)
155 }
156 pub fn get_package(&self, package_name: &str) -> Result<&PackageBasicInfo> {
164 match self.packages.get(package_name) {
165 Some(package) => Ok(package),
166 None => Err(anyhow::anyhow!("Package '{}' not found.", package_name)),
167 }
168 }
169}
170#[cfg(feature = "server")]
171impl RepoInfo {
172
173
174 pub fn add_package(
180 &mut self,
181 name: String,
182 url: String,
183 file_name: String,
184 version: String,
185 hash: String,
186 dependencies: Option<Vec<Dependency>>,
187 ) {
188 let package = PackageBasicInfo {
189 url,
190 file_name,
191 version,
192 hash,
193 dependencies,
194 };
195 self.packages.insert(name, package);
196 }
197 pub fn add_package_with_info(&mut self, name: String, info: PackageBasicInfo) {
199 self.packages.insert(name, info);
200 }
201
202 pub fn remove_package(&mut self, package_name: &str) -> Result<PackageBasicInfo> {
204 match self.packages.remove(package_name) {
205 Some(package) => Ok(package),
206 None => Err(anyhow::anyhow!("Package '{}' not found.", package_name)),
207 }
208 }
209 pub fn update_package(
211 &mut self,
212 package_name: &str,
213 url: Option<String>,
214 file_name: Option<String>,
215 version: Option<String>,
216 hash: Option<String>,
217 dependencies: Option<Vec<Dependency>>,
218 ) {
219 if let Some(existing_package) = self.packages.get_mut(package_name) {
220 if let Some(new_url) = url {
221 existing_package.url = new_url;
222 }
223 if let Some(new_file_name) = file_name {
224 existing_package.file_name = new_file_name;
225 }
226 if let Some(new_version) = version {
227 existing_package.version = new_version;
228 }
229 if let Some(new_hash) = hash {
230 existing_package.hash = new_hash;
231 }
232 if let Some(new_dependencies) = dependencies {
233 existing_package.dependencies = Some(new_dependencies);
234 }
235 } else {
236 self.packages.insert(
237 package_name.to_string(),
238 PackageBasicInfo {
239 url: url.unwrap_or_default(),
240 file_name: file_name.unwrap_or_default(),
241 version: version.unwrap_or_default(),
242 hash: hash.unwrap_or_default(),
243 dependencies: None,
244 },
245 );
246 }
247 }
248}
249
250#[cfg(feature = "client")]
251impl RepoInfo{
252
253}