1use std::time::Duration;
2
3use reqwest::Certificate;
4use url::Url;
5
6use crate::identity::AnonymousDistinctId;
7use crate::storage::Storage;
8use crate::transport::TransportsError;
9use crate::{system_snapshot::SystemSnapshotter, DeviceId, DistinctId, Map};
10use crate::{Recorder, Worker};
11
12#[derive(Default)]
13pub struct Builder {
14 device_id: Option<DeviceId>,
15 distinct_id: Option<DistinctId>,
16 anonymous_distinct_id: Option<AnonymousDistinctId>,
17 enable_reporting: bool,
18 endpoint: Option<String>,
19 facts: Option<Map>,
20 groups: Option<Map>,
21 proxy: Option<Url>,
22 certificate: Option<Certificate>,
23 timeout: Option<Duration>,
24}
25
26impl Builder {
27 pub fn new() -> Self {
28 Builder {
29 device_id: None,
30 distinct_id: None,
31 anonymous_distinct_id: None,
32 enable_reporting: true,
33 endpoint: None,
34 facts: None,
35 groups: None,
36 proxy: None,
37 certificate: None,
38 timeout: None,
39 }
40 }
41
42 pub fn set_anonymous_distinct_id(
43 mut self,
44 anonymous_distinct_id: Option<AnonymousDistinctId>,
45 ) -> Self {
46 self.anonymous_distinct_id = anonymous_distinct_id;
47 self
48 }
49
50 pub fn set_distinct_id(mut self, distinct_id: Option<DistinctId>) -> Self {
51 self.distinct_id = distinct_id;
52 self
53 }
54
55 pub fn set_device_id(mut self, device_id: Option<DeviceId>) -> Self {
56 self.device_id = device_id;
57 self
58 }
59
60 pub fn set_facts(mut self, facts: Option<Map>) -> Self {
61 self.facts = facts;
62 self
63 }
64
65 pub fn set_groups(mut self, groups: Option<Map>) -> Self {
66 self.groups = groups;
67 self
68 }
69
70 pub fn add_fact(
71 mut self,
72 key: impl Into<String> + std::fmt::Debug,
73 value: impl Into<serde_json::Value>,
74 ) -> Self {
75 self.facts
76 .get_or_insert_with(Default::default)
77 .insert(key.into(), value.into());
78 self
79 }
80
81 pub fn set_endpoint(mut self, endpoint: Option<String>) -> Self {
82 self.endpoint = endpoint;
83 self
84 }
85
86 pub fn set_enable_reporting(mut self, enable_reporting: bool) -> Self {
108 self.enable_reporting = enable_reporting;
109 self
110 }
111
112 pub fn set_timeout(mut self, duration: Option<Duration>) -> Self {
113 self.timeout = duration;
114 self
115 }
116
117 pub fn set_certificate(mut self, certificate: Option<Certificate>) -> Self {
118 self.certificate = certificate;
119 self
120 }
121
122 pub fn set_proxy(mut self, proxy: Option<Url>) -> Self {
123 self.proxy = proxy;
124 self
125 }
126
127 #[tracing::instrument(skip(self))]
128 pub async fn try_build(mut self) -> Result<(Recorder, Worker), TransportsError> {
129 let transport = self.transport().await?;
130
131 Ok(self
132 .build_with(
133 transport,
134 crate::system_snapshot::Generic::default(),
135 crate::storage::Generic::default(),
136 )
137 .await)
138 }
139
140 #[tracing::instrument(skip(self))]
141 pub async fn build_or_default(mut self) -> (Recorder, Worker) {
142 let transport = self.transport_or_default().await;
143
144 self.build_with(
145 transport,
146 crate::system_snapshot::Generic::default(),
147 crate::storage::Generic::default(),
148 )
149 .await
150 }
151
152 #[tracing::instrument(skip(self, snapshotter, storage))]
153 pub async fn try_build_with<S: SystemSnapshotter, P: Storage>(
154 mut self,
155 snapshotter: S,
156 storage: P,
157 ) -> Result<(Recorder, Worker), TransportsError> {
158 let transport = self.transport().await?;
159
160 Ok(self.build_with(transport, snapshotter, storage).await)
161 }
162
163 #[tracing::instrument(skip(self, snapshotter, storage))]
164 pub async fn build_or_default_with<S: SystemSnapshotter, P: Storage>(
165 mut self,
166 snapshotter: S,
167 storage: P,
168 ) -> (Recorder, Worker) {
169 let transport = self.transport_or_default().await;
170
171 self.build_with(transport, snapshotter, storage).await
172 }
173
174 #[tracing::instrument(skip(self, transport, snapshotter, storage))]
175 async fn build_with<S: SystemSnapshotter, P: Storage>(
176 &mut self,
177 transport: crate::transport::Transports,
178 snapshotter: S,
179 storage: P,
180 ) -> (Recorder, Worker) {
181 Worker::new(
182 self.anonymous_distinct_id.take(),
183 self.distinct_id.take(),
184 self.device_id.take(),
185 self.facts.take(),
186 self.groups.take(),
187 snapshotter,
188 storage,
189 transport,
190 )
191 .await
192 }
193
194 async fn transport_or_default(&mut self) -> crate::transport::Transports {
195 match self.transport().await {
196 Ok(t) => {
197 return t;
198 }
199 Err(e) => {
200 tracing::warn!(%e, "Failed to construct the transport as configured, falling back to the default");
201 }
202 }
203
204 match crate::transport::Transports::try_new(
205 None,
206 self.timeout
207 .take()
208 .unwrap_or_else(|| Duration::from_secs(3)),
209 None,
210 None,
211 )
212 .await
213 {
214 Ok(t) => {
215 return t;
216 }
217 Err(e) => {
218 tracing::warn!(%e, "Failed to construct the default transport, falling back to none");
219 }
220 }
221
222 crate::transport::Transports::none()
223 }
224
225 async fn transport(&mut self) -> Result<crate::transport::Transports, TransportsError> {
226 if self.enable_reporting {
227 crate::transport::Transports::try_new(
228 self.endpoint.take(),
229 self.timeout.unwrap_or_else(|| Duration::from_secs(3)),
230 self.certificate.take(),
231 self.proxy.take(),
232 )
233 .await
234 } else {
235 Ok(crate::transport::Transports::none())
236 }
237 }
238}