1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use serde::Deserialize;
#[derive(Deserialize, Debug, PartialEq)]
#[allow(non_snake_case)]
struct Distribution {
identifier: String,
downloadURL: String,
modified: Option<String>,
mediaType: Option<String>,
}
impl Distribution {
fn am_i_right(self: &Self, r: &Regex) -> bool {
return r.is_match(&self.downloadURL);
}
}
#[derive(Deserialize, Debug, PartialEq)]
#[allow(non_snake_case)]
struct DataSets {
distributions: Vec<Distribution>,
}
#[derive(Deserialize, Debug, PartialEq)]
#[allow(non_snake_case)]
struct SearchDSResult {
dataSets: Vec<DataSets>,
}
use regex::Regex;
macro_rules! matcher_regex {
($re:expr $(,)?) => {{
static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
RE.get_or_init(|| regex::Regex::new($re).unwrap())
}};
}
use crate::settings::MatcherSettingsDerive;
quick_error! {
#[derive(Debug)]
pub enum FetcherMatcherError {
API(err: reqwest::Error) {
display("{}", err)
from()
}
Io(err: std::io::Error) {
source(err)
from()
}
}
}
pub async fn fetcher_matcher(
settings: &MatcherSettingsDerive,
) -> Result<Vec<String>, FetcherMatcherError> {
let set_matcher = settings.matcher.as_ref().expect("matcher must be set");
let set_url = settings.rest_url.as_ref().expect("rest_url must be set");
let set_query = settings.query.as_ref().expect("query must be set");
let re_valid_filename = matcher_regex!(&set_matcher);
let client = reqwest::Client::new();
let response = client
.get(set_url)
.query(&[("query", set_query)])
.send()
.await?;
let search_result: SearchDSResult = response.json().await?;
let matches: Vec<_> = search_result
.dataSets
.iter()
.flat_map(|ds| {
ds.distributions
.iter()
.filter(|dist| dist.am_i_right(&re_valid_filename))
.map(|dist| dist.downloadURL.clone())
})
.collect();
Ok(matches)
}