Skip to main content

paper_gap/
provider.rs

1use crate::Error;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5pub struct ProviderOutcome {
6    pub provider: String,
7    pub status: ProviderStatus,
8    #[serde(skip_serializing_if = "Option::is_none")]
9    pub message: Option<String>,
10}
11
12#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub enum ProviderStatus {
15    Success,
16    Unavailable,
17    RateLimited,
18    Failed,
19}
20
21impl ProviderOutcome {
22    pub fn success(provider: impl Into<String>) -> Self {
23        Self {
24            provider: provider.into(),
25            status: ProviderStatus::Success,
26            message: None,
27        }
28    }
29
30    pub fn from_error(provider: impl Into<String>, error: &Error) -> Self {
31        let status = match error {
32            Error::Reqwest(error)
33                if error.status() == Some(reqwest::StatusCode::TOO_MANY_REQUESTS) =>
34            {
35                ProviderStatus::RateLimited
36            }
37            Error::Reqwest(error) if error.is_timeout() || error.is_connect() => {
38                ProviderStatus::Unavailable
39            }
40            _ => ProviderStatus::Failed,
41        };
42        Self {
43            provider: provider.into(),
44            status,
45            message: Some(error.to_string()),
46        }
47    }
48
49    pub fn succeeded(&self) -> bool {
50        self.status == ProviderStatus::Success
51    }
52
53    pub fn aggregate(provider: impl Into<String>, outcomes: &[Self]) -> Self {
54        let status = outcomes
55            .iter()
56            .map(|outcome| outcome.status)
57            .max_by_key(|status| match status {
58                ProviderStatus::Success => 0,
59                ProviderStatus::Unavailable => 1,
60                ProviderStatus::RateLimited => 2,
61                ProviderStatus::Failed => 3,
62            })
63            .unwrap_or(ProviderStatus::Success);
64        let messages: Vec<_> = outcomes
65            .iter()
66            .filter_map(|outcome| outcome.message.as_deref())
67            .collect();
68        Self {
69            provider: provider.into(),
70            status,
71            message: (!messages.is_empty()).then(|| messages.join("; ")),
72        }
73    }
74}
75
76pub fn default_success() -> ProviderOutcome {
77    ProviderOutcome::success("legacy")
78}