Skip to content

Commit a9944b1

Browse files
committed
refactor(ads-client): change dynamic traits to generic traits for min rust version compatibility
1 parent 8d4f21b commit a9944b1

File tree

9 files changed

+146
-117
lines changed

9 files changed

+146
-117
lines changed

components/ads-client/src/client.rs

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ use crate::client::ad_response::{
1111
pop_request_hash_from_url, AdImage, AdResponse, AdResponseValue, AdSpoc, AdTile,
1212
};
1313
use crate::client::config::AdsClientConfig;
14-
use crate::client::telemetry::{AdsTelemetry, ClientOperationEvent};
14+
use crate::client::telemetry::ClientOperationEvent;
1515
use crate::error::{RecordClickError, RecordImpressionError, ReportAdError, RequestAdsError};
16-
use crate::http_cache::{HttpCache, RequestCachePolicy};
16+
use crate::http_cache::{CacheOutcome, HttpCache, HttpCacheBuilderError, RequestCachePolicy};
1717
use crate::mars::MARSClient;
18+
use crate::telemetry::Telemetry;
1819
use ad_request::{AdPlacementRequest, AdRequest};
1920
use context_id::{ContextIDComponent, DefaultContextIdCallback};
2021
use url::Url;
@@ -30,14 +31,34 @@ pub mod telemetry;
3031
const DEFAULT_TTL_SECONDS: u64 = 300;
3132
const DEFAULT_MAX_CACHE_SIZE_MIB: u64 = 10;
3233

33-
pub struct AdsClient {
34-
client: MARSClient,
34+
pub struct AdsClient<T>
35+
where
36+
T: Telemetry<CacheOutcome>
37+
+ Telemetry<ClientOperationEvent>
38+
+ Telemetry<HttpCacheBuilderError>
39+
+ Telemetry<RecordClickError>
40+
+ Telemetry<RecordImpressionError>
41+
+ Telemetry<ReportAdError>
42+
+ Telemetry<RequestAdsError>
43+
+ Telemetry<serde_json::Error>,
44+
{
45+
client: MARSClient<T>,
3546
context_id_component: ContextIDComponent,
36-
telemetry: Arc<dyn AdsTelemetry>,
47+
telemetry: Arc<T>,
3748
}
3849

39-
impl AdsClient {
40-
pub fn new(client_config: AdsClientConfig) -> Self {
50+
impl<T> AdsClient<T>
51+
where
52+
T: Telemetry<CacheOutcome>
53+
+ Telemetry<serde_json::Error>
54+
+ Telemetry<ClientOperationEvent>
55+
+ Telemetry<HttpCacheBuilderError>
56+
+ Telemetry<RecordClickError>
57+
+ Telemetry<RecordImpressionError>
58+
+ Telemetry<ReportAdError>
59+
+ Telemetry<RequestAdsError>,
60+
{
61+
pub fn new(client_config: AdsClientConfig<T>) -> Self {
4162
let context_id = Uuid::new_v4().to_string();
4263
let context_id_component = ContextIDComponent::new(
4364
&context_id,
@@ -97,35 +118,19 @@ impl AdsClient {
97118
client
98119
}
99120

100-
#[cfg(test)]
101-
pub fn new_with_mars_client(client: MARSClient) -> Self {
102-
use crate::client::telemetry::PrintAdsTelemetry;
103-
104-
let context_id_component = ContextIDComponent::new(
105-
&uuid::Uuid::new_v4().to_string(),
106-
0,
107-
false,
108-
Box::new(DefaultContextIdCallback),
109-
);
110-
Self {
111-
context_id_component,
112-
client,
113-
telemetry: Arc::new(PrintAdsTelemetry),
114-
}
115-
}
116-
117-
fn request_ads<T>(
121+
fn request_ads<A>(
118122
&self,
119123
ad_placement_requests: Vec<AdPlacementRequest>,
120124
options: Option<RequestCachePolicy>,
121-
) -> Result<AdResponse<T>, RequestAdsError>
125+
) -> Result<AdResponse<A>, RequestAdsError>
122126
where
123-
T: AdResponseValue,
127+
A: AdResponseValue,
124128
{
125129
let context_id = self.get_context_id()?;
126130
let ad_request = AdRequest::build(context_id, ad_placement_requests)?;
127131
let cache_policy = options.unwrap_or_default();
128-
let (mut response, request_hash) = self.client.fetch_ads(&ad_request, &cache_policy)?;
132+
let (mut response, request_hash) =
133+
self.client.fetch_ads::<A>(&ad_request, &cache_policy)?;
129134
response.add_request_hash_to_callbacks(&request_hash);
130135
Ok(response)
131136
}
@@ -237,18 +242,30 @@ impl AdsClient {
237242
mod tests {
238243
use crate::{
239244
client::config::Environment,
240-
client::telemetry::PrintAdsTelemetry,
241245
test_utils::{
242246
get_example_happy_image_response, get_example_happy_spoc_response,
243-
get_example_happy_uatile_response, make_happy_placement_requests,
247+
get_example_happy_uatile_response, make_happy_placement_requests, PrintAdsTelemetry,
244248
},
245249
};
246250

247251
use super::*;
248252

253+
fn new_with_mars_client(client: MARSClient<PrintAdsTelemetry>) -> AdsClient<PrintAdsTelemetry> {
254+
let context_id_component = ContextIDComponent::new(
255+
&uuid::Uuid::new_v4().to_string(),
256+
0,
257+
false,
258+
Box::new(DefaultContextIdCallback),
259+
);
260+
AdsClient {
261+
context_id_component,
262+
client,
263+
telemetry: Arc::new(PrintAdsTelemetry),
264+
}
265+
}
266+
249267
#[test]
250268
fn test_get_context_id() {
251-
use crate::client::telemetry::PrintAdsTelemetry;
252269
use std::sync::Arc;
253270
let config = AdsClientConfig {
254271
environment: Environment::Test,
@@ -262,7 +279,6 @@ mod tests {
262279

263280
#[test]
264281
fn test_cycle_context_id() {
265-
use crate::client::telemetry::PrintAdsTelemetry;
266282
use std::sync::Arc;
267283
let config = AdsClientConfig {
268284
environment: Environment::Test,
@@ -288,8 +304,9 @@ mod tests {
288304
.with_body(serde_json::to_string(&expected_response.data).unwrap())
289305
.create();
290306

291-
let mars_client = MARSClient::new(Environment::Test, None, Arc::new(PrintAdsTelemetry));
292-
let ads_client = AdsClient::new_with_mars_client(mars_client);
307+
let telemetry = Arc::new(PrintAdsTelemetry);
308+
let mars_client = MARSClient::new(Environment::Test, None, telemetry.clone());
309+
let ads_client = new_with_mars_client(mars_client);
293310

294311
let ad_placement_requests = make_happy_placement_requests();
295312

@@ -309,8 +326,9 @@ mod tests {
309326
.with_body(serde_json::to_string(&expected_response.data).unwrap())
310327
.create();
311328

312-
let mars_client = MARSClient::new(Environment::Test, None, Arc::new(PrintAdsTelemetry));
313-
let ads_client = AdsClient::new_with_mars_client(mars_client);
329+
let telemetry = Arc::new(PrintAdsTelemetry);
330+
let mars_client = MARSClient::new(Environment::Test, None, telemetry.clone());
331+
let ads_client = new_with_mars_client(mars_client);
314332

315333
let ad_placement_requests = make_happy_placement_requests();
316334

@@ -330,8 +348,9 @@ mod tests {
330348
.with_body(serde_json::to_string(&expected_response.data).unwrap())
331349
.create();
332350

333-
let mars_client = MARSClient::new(Environment::Test, None, Arc::new(PrintAdsTelemetry));
334-
let ads_client = AdsClient::new_with_mars_client(mars_client);
351+
let telemetry = Arc::new(PrintAdsTelemetry);
352+
let mars_client = MARSClient::new(Environment::Test, None, telemetry.clone());
353+
let ads_client = new_with_mars_client(mars_client);
335354

336355
let ad_placement_requests = make_happy_placement_requests();
337356

@@ -346,9 +365,9 @@ mod tests {
346365
let cache = HttpCache::builder("test_record_click_invalidates_cache")
347366
.build()
348367
.unwrap();
349-
let mars_client =
350-
MARSClient::new(Environment::Test, Some(cache), Arc::new(PrintAdsTelemetry));
351-
let ads_client = AdsClient::new_with_mars_client(mars_client);
368+
let telemetry = Arc::new(PrintAdsTelemetry);
369+
let mars_client = MARSClient::new(Environment::Test, Some(cache), telemetry.clone());
370+
let ads_client = new_with_mars_client(mars_client);
352371

353372
let response = get_example_happy_image_response();
354373

components/ads-client/src/client/ad_response.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ use std::collections::HashMap;
1111
use url::Url;
1212

1313
#[derive(Debug, PartialEq, Serialize)]
14-
pub struct AdResponse<T: AdResponseValue> {
15-
pub data: HashMap<String, Vec<T>>,
14+
pub struct AdResponse<A: AdResponseValue> {
15+
pub data: HashMap<String, Vec<A>>,
1616
}
1717

18-
impl<T: AdResponseValue> AdResponse<T> {
19-
pub fn parse(
18+
impl<A: AdResponseValue> AdResponse<A> {
19+
pub fn parse<T: Telemetry<serde_json::Error> + ?Sized>(
2020
data: serde_json::Value,
21-
telemetry: &dyn Telemetry<serde_json::Error>,
22-
) -> Result<AdResponse<T>, serde_json::Error> {
23-
let raw: HashMap<String, serde_json::Value> = ::serde_json::from_value(data)?;
21+
telemetry: &T,
22+
) -> Result<AdResponse<A>, serde_json::Error> {
23+
let raw: HashMap<String, serde_json::Value> = serde_json::from_value(data)?;
2424
let mut result = HashMap::new();
2525

2626
for (key, value) in raw {
2727
if let serde_json::Value::Array(arr) = value {
28-
let mut ads: Vec<T> = vec![];
28+
let mut ads: Vec<A> = vec![];
2929
for item in arr {
30-
match serde_json::from_value::<T>(item.clone()) {
30+
match serde_json::from_value::<A>(item.clone()) {
3131
Ok(ad) => ads.push(ad),
3232
Err(e) => {
3333
telemetry.record(&e);
@@ -60,7 +60,7 @@ impl<T: AdResponseValue> AdResponse<T> {
6060
}
6161
}
6262

63-
pub fn take_first(self) -> HashMap<String, T> {
63+
pub fn take_first(self) -> HashMap<String, A> {
6464
self.data
6565
.into_iter()
6666
.filter_map(|(k, mut v)| {

components/ads-client/src/client/config.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use std::sync::Arc;
88
use once_cell::sync::Lazy;
99
use url::Url;
1010

11-
use super::telemetry::AdsTelemetry;
11+
use crate::client::telemetry::ClientOperationEvent;
12+
use crate::error::{RecordClickError, RecordImpressionError, ReportAdError, RequestAdsError};
13+
use crate::http_cache::{CacheOutcome, HttpCacheBuilderError};
14+
use crate::telemetry::Telemetry;
1215

1316
static MARS_API_ENDPOINT_PROD: Lazy<Url> =
1417
Lazy::new(|| Url::parse("https://ads.mozilla.org/v1/").expect("hardcoded URL must be valid"));
@@ -17,10 +20,20 @@ static MARS_API_ENDPOINT_PROD: Lazy<Url> =
1720
static MARS_API_ENDPOINT_STAGING: Lazy<Url> =
1821
Lazy::new(|| Url::parse("https://ads.allizom.org/v1/").expect("hardcoded URL must be valid"));
1922

20-
pub struct AdsClientConfig {
23+
pub struct AdsClientConfig<T>
24+
where
25+
T: Telemetry<CacheOutcome>
26+
+ Telemetry<ClientOperationEvent>
27+
+ Telemetry<HttpCacheBuilderError>
28+
+ Telemetry<RecordClickError>
29+
+ Telemetry<RecordImpressionError>
30+
+ Telemetry<ReportAdError>
31+
+ Telemetry<RequestAdsError>
32+
+ Telemetry<serde_json::Error>,
33+
{
2134
pub environment: Environment,
2235
pub cache_config: Option<AdsCacheConfig>,
23-
pub telemetry: Arc<dyn AdsTelemetry>,
36+
pub telemetry: Arc<T>,
2437
}
2538

2639
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]

components/ads-client/src/client/telemetry.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,6 @@ use std::fmt::Debug;
44
* License, v. 2.0. If a copy of the MPL was not distributed with this
55
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
66
*/
7-
use crate::error::{RecordClickError, RecordImpressionError, ReportAdError, RequestAdsError};
8-
use crate::http_cache::HttpCacheBuilderError;
9-
use crate::mars::MARSTelemetry;
10-
use crate::telemetry::Telemetry;
11-
12-
pub trait AdsTelemetry:
13-
MARSTelemetry
14-
+ Telemetry<ClientOperationEvent>
15-
+ Telemetry<HttpCacheBuilderError>
16-
+ Telemetry<RecordClickError>
17-
+ Telemetry<RecordImpressionError>
18-
+ Telemetry<ReportAdError>
19-
+ Telemetry<RequestAdsError>
20-
{
21-
}
227

238
#[derive(Clone, Debug, PartialEq, Eq)]
249
pub enum ClientOperationEvent {
@@ -28,13 +13,3 @@ pub enum ClientOperationEvent {
2813
ReportAd,
2914
RequestAds,
3015
}
31-
32-
pub struct PrintAdsTelemetry;
33-
34-
impl<A: Debug> Telemetry<A> for PrintAdsTelemetry {
35-
fn record(&self, event: &A) {
36-
println!("record: {:?}", event);
37-
}
38-
}
39-
40-
impl AdsTelemetry for PrintAdsTelemetry {}

components/ads-client/src/ffi.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
44
*/
55

6-
mod telemetry;
6+
pub mod telemetry;
77

88
use std::sync::Arc;
99

@@ -12,9 +12,8 @@ use crate::client::ad_response::{
1212
AdCallbacks, AdImage, AdSpoc, AdTile, SpocFrequencyCaps, SpocRanking,
1313
};
1414
use crate::client::config::{AdsCacheConfig, AdsClientConfig, Environment};
15-
use crate::client::telemetry::{AdsTelemetry, PrintAdsTelemetry};
1615
use crate::error::ComponentError;
17-
use crate::ffi::telemetry::MozAdsTelemetryWrapper;
16+
use crate::ffi::telemetry::{MozAdsTelemetryWrapper, NoopMozAdsTelemetry};
1817
use crate::http_cache::{CacheMode, RequestCachePolicy};
1918
use error_support::{ErrorHandling, GetErrorHandling};
2019
use url::Url;
@@ -96,12 +95,16 @@ pub struct MozAdsClientConfig {
9695
pub telemetry: Option<Arc<dyn MozAdsTelemetry>>,
9796
}
9897

99-
impl From<MozAdsClientConfig> for AdsClientConfig {
98+
impl From<MozAdsClientConfig> for AdsClientConfig<MozAdsTelemetryWrapper> {
10099
fn from(config: MozAdsClientConfig) -> Self {
101-
let telemetry: Arc<dyn AdsTelemetry> = config
100+
let telemetry = config
102101
.telemetry
103-
.map(|t| Arc::new(MozAdsTelemetryWrapper { inner: t }) as Arc<dyn AdsTelemetry>)
104-
.unwrap_or_else(|| Arc::new(PrintAdsTelemetry));
102+
.map(|t| Arc::new(MozAdsTelemetryWrapper { inner: t }))
103+
.unwrap_or_else(|| {
104+
Arc::new(MozAdsTelemetryWrapper {
105+
inner: Arc::new(NoopMozAdsTelemetry),
106+
})
107+
});
105108
Self {
106109
environment: config.environment.into(),
107110
cache_config: config.cache_config.map(Into::into),

components/ads-client/src/ffi/telemetry.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
use std::sync::Arc;
77

8-
use crate::client::telemetry::{AdsTelemetry, ClientOperationEvent};
8+
use crate::client::telemetry::ClientOperationEvent;
99
use crate::error::{RecordClickError, RecordImpressionError, ReportAdError, RequestAdsError};
1010
use crate::http_cache::{CacheOutcome, HttpCacheBuilderError};
1111
use crate::telemetry::Telemetry;
@@ -19,6 +19,16 @@ pub trait MozAdsTelemetry: Send + Sync {
1919
fn record_http_cache_outcome(&self, label: &str);
2020
}
2121

22+
pub struct NoopMozAdsTelemetry;
23+
24+
impl MozAdsTelemetry for NoopMozAdsTelemetry {
25+
fn record_build_cache_error(&self, _label: &str, _value: &str) {}
26+
fn record_client_error(&self, _label: &str, _value: &str) {}
27+
fn record_client_operation_total(&self, _label: &str) {}
28+
fn record_deserialization_error(&self, _label: &str, _value: &str) {}
29+
fn record_http_cache_outcome(&self, _label: &str) {}
30+
}
31+
2232
pub struct MozAdsTelemetryWrapper {
2333
pub inner: Arc<dyn MozAdsTelemetry>,
2434
}
@@ -103,5 +113,3 @@ impl Telemetry<ClientOperationEvent> for MozAdsTelemetryWrapper {
103113
self.inner.record_client_operation_total(label);
104114
}
105115
}
106-
107-
impl AdsTelemetry for MozAdsTelemetryWrapper {}

0 commit comments

Comments
 (0)