lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

outcome.rs (4521B)


      1 #![forbid(unsafe_code)]
      2 
      3 use serde::{Deserialize, Serialize};
      4 
      5 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
      6 pub enum RadrootsRelayOutcomeKind {
      7     Accepted,
      8     DuplicateAccepted,
      9     Blocked,
     10     RateLimited,
     11     Invalid,
     12     PowRequired,
     13     Restricted,
     14     AuthRequired,
     15     Muted,
     16     Unsupported,
     17     PaymentRequired,
     18     Error,
     19     Timeout,
     20     ConnectionFailed,
     21     RelayUrlRejected,
     22     SkippedAlreadyAccepted,
     23     Unknown,
     24 }
     25 
     26 impl RadrootsRelayOutcomeKind {
     27     pub fn counts_toward_quorum(self) -> bool {
     28         matches!(
     29             self,
     30             Self::Accepted | Self::DuplicateAccepted | Self::SkippedAlreadyAccepted
     31         )
     32     }
     33 
     34     pub fn is_retryable(self) -> bool {
     35         matches!(
     36             self,
     37             Self::RateLimited
     38                 | Self::PowRequired
     39                 | Self::AuthRequired
     40                 | Self::Error
     41                 | Self::Timeout
     42                 | Self::ConnectionFailed
     43                 | Self::Unknown
     44         )
     45     }
     46 
     47     pub fn is_terminal_failure(self) -> bool {
     48         matches!(
     49             self,
     50             Self::Blocked
     51                 | Self::Invalid
     52                 | Self::Restricted
     53                 | Self::Muted
     54                 | Self::Unsupported
     55                 | Self::PaymentRequired
     56                 | Self::RelayUrlRejected
     57         )
     58     }
     59 }
     60 
     61 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
     62 pub struct RadrootsRelayOutcome {
     63     pub kind: RadrootsRelayOutcomeKind,
     64     pub message: Option<String>,
     65 }
     66 
     67 impl RadrootsRelayOutcome {
     68     pub fn accepted() -> Self {
     69         Self {
     70             kind: RadrootsRelayOutcomeKind::Accepted,
     71             message: None,
     72         }
     73     }
     74 
     75     pub fn duplicate_accepted(message: impl Into<String>) -> Self {
     76         Self {
     77             kind: RadrootsRelayOutcomeKind::DuplicateAccepted,
     78             message: Some(message.into()),
     79         }
     80     }
     81 
     82     pub fn connection_failed(message: impl Into<String>) -> Self {
     83         Self {
     84             kind: RadrootsRelayOutcomeKind::ConnectionFailed,
     85             message: Some(message.into()),
     86         }
     87     }
     88 
     89     pub fn timeout(message: impl Into<String>) -> Self {
     90         Self {
     91             kind: RadrootsRelayOutcomeKind::Timeout,
     92             message: Some(message.into()),
     93         }
     94     }
     95 
     96     pub fn relay_url_rejected(message: impl Into<String>) -> Self {
     97         Self {
     98             kind: RadrootsRelayOutcomeKind::RelayUrlRejected,
     99             message: Some(message.into()),
    100         }
    101     }
    102 
    103     pub fn skipped_already_accepted(message: impl Into<String>) -> Self {
    104         Self {
    105             kind: RadrootsRelayOutcomeKind::SkippedAlreadyAccepted,
    106             message: Some(message.into()),
    107         }
    108     }
    109 
    110     pub fn classify(message: impl AsRef<str>) -> Self {
    111         let message = message.as_ref().trim();
    112         let lower = message.to_ascii_lowercase();
    113         let kind = if lower.starts_with("duplicate:") {
    114             RadrootsRelayOutcomeKind::DuplicateAccepted
    115         } else if lower.starts_with("blocked:") {
    116             RadrootsRelayOutcomeKind::Blocked
    117         } else if lower.starts_with("rate-limited:") {
    118             RadrootsRelayOutcomeKind::RateLimited
    119         } else if lower.starts_with("invalid:") {
    120             RadrootsRelayOutcomeKind::Invalid
    121         } else if lower.starts_with("pow:") {
    122             RadrootsRelayOutcomeKind::PowRequired
    123         } else if lower.starts_with("restricted:") {
    124             RadrootsRelayOutcomeKind::Restricted
    125         } else if lower.starts_with("auth-required:") {
    126             RadrootsRelayOutcomeKind::AuthRequired
    127         } else if lower.starts_with("mute:") {
    128             RadrootsRelayOutcomeKind::Muted
    129         } else if lower.starts_with("unsupported:") {
    130             RadrootsRelayOutcomeKind::Unsupported
    131         } else if lower.starts_with("payment-required:") {
    132             RadrootsRelayOutcomeKind::PaymentRequired
    133         } else if lower.starts_with("error:") {
    134             RadrootsRelayOutcomeKind::Error
    135         } else if lower.starts_with("timeout:") {
    136             RadrootsRelayOutcomeKind::Timeout
    137         } else {
    138             RadrootsRelayOutcomeKind::Unknown
    139         };
    140         Self {
    141             kind,
    142             message: Some(message.to_owned()),
    143         }
    144     }
    145 
    146     pub fn counts_toward_quorum(&self) -> bool {
    147         self.kind.counts_toward_quorum()
    148     }
    149 
    150     pub fn is_retryable(&self) -> bool {
    151         self.kind.is_retryable()
    152     }
    153 
    154     pub fn is_terminal_failure(&self) -> bool {
    155         self.kind.is_terminal_failure()
    156     }
    157 }