volo_http/client/
callopt.rs

1//! Call options for requests
2//!
3//! See [`CallOpt`] for more details.
4
5use std::time::Duration;
6
7use faststr::FastStr;
8use metainfo::{FastStrMap, TypeMap};
9use volo::{client::Apply, context::Context};
10
11use crate::{context::ClientContext, error::ClientError};
12
13/// Call options for requests
14#[derive(Debug, Default)]
15pub struct CallOpt {
16    /// Timeout of the whole request
17    ///
18    /// This timeout includes connect, sending request headers, receiving response headers, but
19    /// without receiving streaming data.
20    pub timeout: Option<Duration>,
21    /// Additional information of the endpoint.
22    ///
23    /// Users can use `tags` to store custom data, such as the datacenter name or the region name,
24    /// which can be used by the service discoverer.
25    pub tags: TypeMap,
26    /// A optimized typemap for storing additional information of the endpoint.
27    ///
28    /// Use [`FastStrMap`] instead of [`TypeMap`] can reduce the Box allocation.
29    ///
30    /// This is mainly for performance optimization.
31    pub faststr_tags: FastStrMap,
32}
33
34impl CallOpt {
35    /// Create a new [`CallOpt`].
36    #[inline]
37    pub fn new() -> Self {
38        Self::default()
39    }
40
41    /// Set a timeout for the [`CallOpt`].
42    pub fn set_timeout(&mut self, timeout: Duration) {
43        self.timeout = Some(timeout);
44    }
45
46    /// Consume current [`CallOpt`] and return a new one with the given timeout.
47    pub fn with_timeout(mut self, timeout: Duration) -> Self {
48        self.timeout = Some(timeout);
49        self
50    }
51
52    /// Check if [`CallOpt`] tags contain entry.
53    #[inline]
54    pub fn contains<T: 'static>(&self) -> bool {
55        self.tags.contains::<T>()
56    }
57
58    /// Insert a tag into this [`CallOpt`].
59    #[inline]
60    pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
61        self.tags.insert(val);
62    }
63
64    /// Consume current [`CallOpt`] and return a new one with the tag.
65    #[inline]
66    pub fn with<T: Send + Sync + 'static>(mut self, val: T) -> Self {
67        self.tags.insert(val);
68        self
69    }
70
71    /// Get a reference to a tag previously inserted on this [`CallOpt`].
72    #[inline]
73    pub fn get<T: 'static>(&self) -> Option<&T> {
74        self.tags.get::<T>()
75    }
76
77    /// Check if [`CallOpt`] tags contain entry.
78    #[inline]
79    pub fn contains_faststr<T: 'static>(&self) -> bool {
80        self.faststr_tags.contains::<T>()
81    }
82
83    /// Insert a tag into this [`CallOpt`].
84    #[inline]
85    pub fn insert_faststr<T: Send + Sync + 'static>(&mut self, val: FastStr) {
86        self.faststr_tags.insert::<T>(val);
87    }
88
89    /// Consume current [`CallOpt`] and return a new one with the tag.
90    #[inline]
91    pub fn with_faststr<T: Send + Sync + 'static>(mut self, val: FastStr) -> Self {
92        self.faststr_tags.insert::<T>(val);
93        self
94    }
95
96    /// Get a reference to a tag previously inserted on this [`CallOpt`].
97    #[inline]
98    pub fn get_faststr<T: 'static>(&self) -> Option<&FastStr> {
99        self.faststr_tags.get::<T>()
100    }
101}
102
103impl Apply<ClientContext> for CallOpt {
104    type Error = ClientError;
105
106    fn apply(self, cx: &mut ClientContext) -> Result<(), Self::Error> {
107        {
108            let callee = cx.rpc_info_mut().callee_mut();
109            if !self.tags.is_empty() {
110                callee.tags.extend(self.tags);
111            }
112            if !self.faststr_tags.is_empty() {
113                callee.faststr_tags.extend(self.faststr_tags);
114            }
115        }
116        {
117            let config = cx.rpc_info_mut().config_mut();
118            if self.timeout.is_some() {
119                config.set_timeout(self.timeout);
120            }
121        }
122        Ok(())
123    }
124}