aspero_engine/
standard.rs1use std::sync::Arc;
4
5use aspero_core::{Error, HttpClient, ResiliencePolicy};
6
7use crate::transport::{Paced, ReqwestClient};
8use crate::{Cache, Engine, EngineBuilder, Pacing};
9
10#[cfg(feature = "crossref")]
11pub use aspero_crossref::CrossrefConfig;
12#[cfg(feature = "datacite")]
13pub use aspero_datacite::DataciteConfig;
14#[cfg(feature = "doi")]
15pub use aspero_doi::DoiConfig;
16#[cfg(feature = "europepmc")]
17pub use aspero_europepmc::EuropePmcConfig;
18#[cfg(feature = "openalex")]
19pub use aspero_openalex::OpenAlexConfig;
20#[cfg(feature = "openlibrary")]
21pub use aspero_openlibrary::OpenLibraryConfig;
22
23#[derive(Clone, Default)]
25#[non_exhaustive]
26pub struct StandardConfig {
27 pub mailto: Option<String>,
29 pub cache: Option<Arc<dyn Cache>>,
31 pub pacing: Option<Arc<dyn Pacing>>,
34 #[cfg(feature = "openalex")]
35 pub openalex: Option<OpenAlexConfig>,
36 #[cfg(feature = "crossref")]
37 pub crossref: Option<CrossrefConfig>,
38 #[cfg(feature = "datacite")]
39 pub datacite: Option<DataciteConfig>,
40 #[cfg(feature = "doi")]
41 pub doi: Option<DoiConfig>,
42 #[cfg(feature = "europepmc")]
43 pub europepmc: Option<EuropePmcConfig>,
44 #[cfg(feature = "openlibrary")]
45 pub openlibrary: Option<OpenLibraryConfig>,
46}
47
48pub fn standard(config: StandardConfig) -> Result<Engine, Error> {
58 let user_agent = match &config.mailto {
59 Some(mailto) => format!("aspero/{} (mailto:{mailto})", env!("CARGO_PKG_VERSION")),
60 None => format!("aspero/{}", env!("CARGO_PKG_VERSION")),
61 };
62 #[allow(unused_variables)]
64 let client = |label: &str, policy: &ResiliencePolicy| -> Result<Arc<dyn HttpClient>, Error> {
65 let inner = Arc::new(ReqwestClient::new(&user_agent, policy.attempt_timeout)?);
66 let paced = Paced::new(label, inner, policy.min_interval);
67 Ok(Arc::new(match &config.pacing {
68 Some(pacing) => paced.shared(pacing.clone()),
69 None => paced,
70 }))
71 };
72
73 let mut builder: EngineBuilder = Engine::builder();
74 if let Some(cache) = config.cache {
75 builder = builder.cache(cache);
76 }
77
78 #[cfg(feature = "openalex")]
79 if let Some(oa) = config.openalex {
80 use aspero_openalex::OpenAlex;
81 let policy = OpenAlex::default_policy();
82 let provider = OpenAlex::new(oa, client("openalex", &policy)?);
83 builder = builder.provider(Arc::new(provider), policy, 10);
84 }
85
86 #[cfg(feature = "crossref")]
87 if let Some(mut cr) = config.crossref {
88 use aspero_crossref::Crossref;
89 if cr.mailto.is_none() {
90 cr.mailto = config.mailto.clone();
91 }
92 let policy = Crossref::default_policy();
93 let provider = Crossref::new(cr, client("crossref", &policy)?);
94 builder = builder.provider(Arc::new(provider), policy, 20);
95 }
96
97 #[cfg(feature = "datacite")]
98 if let Some(dc) = config.datacite {
99 use aspero_datacite::Datacite;
100 let policy = Datacite::default_policy();
101 let provider = Datacite::new(dc, client("datacite", &policy)?);
102 builder = builder.provider(Arc::new(provider), policy, 25);
103 }
104
105 #[cfg(feature = "doi")]
106 if let Some(doi) = config.doi {
107 use aspero_doi::DoiOrg;
108 let policy = DoiOrg::default_policy();
109 let provider = DoiOrg::new(doi, client("doi", &policy)?);
110 builder = builder.provider(Arc::new(provider), policy, 30);
111 }
112
113 #[cfg(feature = "europepmc")]
114 if let Some(epmc) = config.europepmc {
115 use aspero_europepmc::EuropePmc;
116 let policy = EuropePmc::default_policy();
117 let provider = EuropePmc::new(epmc, client("europepmc", &policy)?);
118 builder = builder.provider(Arc::new(provider), policy, 35);
119 }
120
121 #[cfg(feature = "openlibrary")]
122 if let Some(ol) = config.openlibrary {
123 use aspero_openlibrary::OpenLibrary;
124 let policy = OpenLibrary::default_policy();
125 let provider = OpenLibrary::new(ol, client("openlibrary", &policy)?);
126 builder = builder.provider(Arc::new(provider), policy, 40);
127 }
128
129 Ok(builder.build())
130}