Skip to main content

openwire_core/
policy.rs

1use std::sync::Arc;
2
3use http::{Method, StatusCode, Uri};
4
5use crate::WireError;
6
7pub trait RetryPolicy: Send + Sync + 'static {
8    fn should_retry(&self, ctx: &RetryContext<'_>) -> Option<&'static str>;
9}
10
11impl<T> RetryPolicy for Arc<T>
12where
13    T: RetryPolicy + ?Sized,
14{
15    fn should_retry(&self, ctx: &RetryContext<'_>) -> Option<&'static str> {
16        (**self).should_retry(ctx)
17    }
18}
19
20pub struct RetryContext<'a> {
21    error: &'a WireError,
22    attempt: u32,
23    is_body_replayable: bool,
24    request_method: &'a Method,
25}
26
27impl<'a> RetryContext<'a> {
28    pub fn new(
29        error: &'a WireError,
30        attempt: u32,
31        is_body_replayable: bool,
32        request_method: &'a Method,
33    ) -> Self {
34        Self {
35            error,
36            attempt,
37            is_body_replayable,
38            request_method,
39        }
40    }
41
42    pub fn error(&self) -> &'a WireError {
43        self.error
44    }
45
46    pub fn attempt(&self) -> u32 {
47        self.attempt
48    }
49
50    pub fn is_body_replayable(&self) -> bool {
51        self.is_body_replayable
52    }
53
54    pub fn request_method(&self) -> &'a Method {
55        self.request_method
56    }
57}
58
59pub trait RedirectPolicy: Send + Sync + 'static {
60    fn should_redirect(&self, ctx: &RedirectContext<'_>) -> RedirectDecision;
61}
62
63impl<T> RedirectPolicy for Arc<T>
64where
65    T: RedirectPolicy + ?Sized,
66{
67    fn should_redirect(&self, ctx: &RedirectContext<'_>) -> RedirectDecision {
68        (**self).should_redirect(ctx)
69    }
70}
71
72pub struct RedirectContext<'a> {
73    request_method: &'a Method,
74    request_uri: &'a Uri,
75    response_status: StatusCode,
76    location: &'a Uri,
77    redirect_count: u32,
78    is_body_replayable: bool,
79}
80
81impl<'a> RedirectContext<'a> {
82    pub fn new(
83        request_method: &'a Method,
84        request_uri: &'a Uri,
85        response_status: StatusCode,
86        location: &'a Uri,
87        redirect_count: u32,
88        is_body_replayable: bool,
89    ) -> Self {
90        Self {
91            request_method,
92            request_uri,
93            response_status,
94            location,
95            redirect_count,
96            is_body_replayable,
97        }
98    }
99
100    pub fn request_method(&self) -> &'a Method {
101        self.request_method
102    }
103
104    pub fn request_uri(&self) -> &'a Uri {
105        self.request_uri
106    }
107
108    pub fn response_status(&self) -> StatusCode {
109        self.response_status
110    }
111
112    pub fn location(&self) -> &'a Uri {
113        self.location
114    }
115
116    pub fn redirect_count(&self) -> u32 {
117        self.redirect_count
118    }
119
120    pub fn is_body_replayable(&self) -> bool {
121        self.is_body_replayable
122    }
123}
124
125pub enum RedirectDecision {
126    Follow,
127    Stop,
128    Error(WireError),
129}