1use std::collections::HashMap;
32use std::fmt::Debug;
33use serde::Deserialize;
34use rayon::prelude::*;
35use crate::error::Error;
36
37#[derive(Deserialize)]
38struct Releases {
39 #[serde(rename = "$value")]
40 releases: Vec<Release>
41}
42
43#[derive(Deserialize, Eq, PartialEq, Debug)]
45pub struct Release {
46 pub id: String,
47 pub name: String,
48 pub publisher: String,
49 pub region: String,
50 pub languages: String,
51 pub group: String,
52 #[serde(alias = "imagesize")]
53 pub image_size: u64,
54 pub serial: String,
55 #[serde(alias = "titleid")]
56 pub title_id: String,
57 #[serde(alias = "imgcrc")]
58 pub img_crc: String,
59 pub filename: String,
60 #[serde(alias = "releasename")]
61 pub release_name: String,
62 #[serde(alias = "trimmedsize")]
63 pub trimmed_size: u64,
64 pub firmware: String,
65 #[serde(alias = "type")]
66 pub _type: String,
67 pub card: String,
68}
69
70pub async fn get_releases_async() -> Result<Vec<Release>, Error> {
72 let response = reqwest::get("http://3dsdb.com/xml.php").await?;
73 let text = response.text().await?;
74 let release: Releases = serde_xml_rs::from_str(&text)?;
75 Ok(release.releases)
76}
77
78pub fn get_releases() -> Result<Vec<Release>, Error> {
80 let response = reqwest::blocking::get("http://3dsdb.com/xml.php")?;
81 let release: Releases = serde_xml_rs::from_reader(response)?;
82 Ok(release.releases)
83
84}
85
86pub fn get_releases_map() -> Result<HashMap<String, Release>, Error> {
96 let releases = get_releases()?;
97 Ok(releases.into_par_iter()
98 .map(|release| (release.title_id.clone(), release))
99 .collect())
100}
101
102impl From<serde_xml_rs::Error> for Error {
103 fn from(value: serde_xml_rs::Error) -> Self {
104 Error { message: format!("{}", value) }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use std::ops::Deref;
111 use once_cell::sync::Lazy;
112 use rstest::rstest;
113 use super::*;
114
115 static EXPECTED_RELEASE: Lazy<Release> = Lazy::new(|| Release {
116 id: "1".to_string(),
117 name: "Tom Clancys Ghost Recon: Shadow Wars".to_string(),
118 publisher: "Ubisoft".to_string(),
119 region: "EUR".to_string(),
120 languages: "en,fr,de,it,es".to_string(),
121 group: "Legacy".to_string(),
122 image_size: 2048,
123 serial: "CTR-AGRP".to_string(),
124 title_id: "0004000000037500".to_string(),
125 img_crc: "5BD0B123".to_string(),
126 filename: "lgc-grsw".to_string(),
127 release_name: "Tom_Clancys_Ghost_Recon_Shadow_Wars_EUR_3DS-LGC".to_string(),
128 trimmed_size: 229750272,
129 firmware: "1.0.0E".to_string(),
130 _type: "1".to_string(),
131 card: "1".to_string()
132 });
133
134 #[rstest]
135 fn get_releases_gets_valid_information() {
136 let value = get_releases().unwrap();
137 let actual = value.get(0).unwrap();
138 assert_eq!(actual, EXPECTED_RELEASE.deref())
139 }
140
141 #[rstest]
142 async fn get_releases_async_gets_valid_information() {
143 let value = get_releases_async().await.unwrap();
144 let actual = value.get(0).unwrap();
145 assert_eq!(actual, EXPECTED_RELEASE.deref())
146 }
147
148 #[rstest]
149 fn get_releases_map_gets_valid_information() {
150 let releases_map = get_releases_map().unwrap();
151 let actual = releases_map.get(&EXPECTED_RELEASE.title_id).unwrap();
152 assert_eq!(actual, EXPECTED_RELEASE.deref())
153 }
154}