Skip to content

Commit 8cc6f62

Browse files
committed
PricingBounds::get & Input::get
1 parent bb61f45 commit 8cc6f62

File tree

4 files changed

+222
-65
lines changed

4 files changed

+222
-65
lines changed

primitives/src/channel.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ impl PricingBounds {
116116

117117
vec
118118
}
119+
120+
pub fn get(&self, event_type: &str) -> Option<&Pricing> {
121+
match event_type {
122+
"IMPRESSION" => self.impression.as_ref(),
123+
"CLICK" => self.click.as_ref(),
124+
_ => None,
125+
}
126+
}
119127
}
120128

121129
#[derive(Serialize, Deserialize, Debug, Clone)]

primitives/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ pub mod event_submission;
1515
pub mod market;
1616
pub mod merkle_tree;
1717
pub mod sentry;
18+
pub mod supermarket;
1819
pub mod targeting;
1920
pub mod targeting_tag;
20-
pub mod supermarket;
2121

2222
pub mod util {
2323
pub mod tests {

primitives/src/targeting.rs

Lines changed: 156 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
use crate::{BigNum, Channel};
1+
use crate::{
2+
channel::Pricing, supermarket::Status, AdUnit, BalancesMap, BigNum, Channel, ToETHChecksum,
3+
ValidatorId,
4+
};
5+
use chrono::Utc;
26
use std::collections::HashMap;
37

48
pub use eval::*;
59

610
mod eval;
711

812
#[derive(Debug, Clone)]
9-
#[cfg_attr(test, derive(Default))]
1013
pub struct Input {
1114
/// AdView scope, accessible only on the AdView
1215
pub ad_view: Option<AdView>,
@@ -18,11 +21,13 @@ pub struct Input {
1821

1922
impl Input {
2023
fn try_get(&self, key: &str) -> Result<Value, Error> {
24+
let spec = &self.global.channel.spec;
25+
2126
match key {
22-
"adView.secondsSinceShow" => self
27+
"adView.secondsSinceCampaignImpression" => self
2328
.ad_view
2429
.as_ref()
25-
.map(|ad_view| Value::Number(ad_view.seconds_since_show.into()))
30+
.map(|ad_view| Value::Number(ad_view.seconds_since_campaign_impression.into()))
2631
.ok_or(Error::UnknownVariable),
2732
"adView.hasCustomPreferences" => self
2833
.ad_view
@@ -31,30 +36,7 @@ impl Input {
3136
.ok_or(Error::UnknownVariable),
3237
"adSlotId" => Ok(Value::String(self.global.ad_slot_id.clone())),
3338
"adSlotType" => Ok(Value::String(self.global.ad_slot_type.clone())),
34-
"adUnitId" => Ok(Value::String(self.global.ad_unit_id.clone())),
35-
"publisherId" => Ok(Value::String(self.global.publisher_id.clone())),
36-
"advertiserId" => Ok(Value::String(self.global.advertiser_id.clone())),
37-
"country" => self
38-
.global
39-
.country
40-
.clone()
41-
.map(Value::String)
42-
.ok_or(Error::UnknownVariable),
43-
"eventType" => Ok(Value::String(self.global.event_type.clone())),
44-
"campaignId" => Ok(Value::String(self.global.campaign_id.clone())),
45-
"campaignTotalSpent" => Ok(Value::String(self.global.campaign_total_spent.clone())),
46-
"campaignSecondsActive" => {
47-
Ok(Value::Number(self.global.campaign_seconds_active.into()))
48-
}
49-
"campaignSecondsDuration" => {
50-
Ok(Value::Number(self.global.campaign_seconds_duration.into()))
51-
}
52-
"campaignBudget" => Ok(Value::BigNum(self.global.campaign_budget.clone())),
53-
"eventMinPrice" => Ok(Value::BigNum(self.global.event_min_price.clone())),
54-
"eventMaxPrice" => Ok(Value::BigNum(self.global.event_max_price.clone())),
55-
"publisherEarnedFromCampaign" => Ok(Value::BigNum(
56-
self.global.publisher_earned_from_campaign.clone(),
57-
)),
39+
"publisherId" => Ok(Value::String(self.global.publisher_id.to_checksum())),
5840
"secondsSinceEpoch" => Ok(Value::Number(self.global.seconds_since_epoch.into())),
5941
"userAgentOS" => self
6042
.global
@@ -68,6 +50,68 @@ impl Input {
6850
.clone()
6951
.map(Value::String)
7052
.ok_or(Error::UnknownVariable),
53+
54+
"adUnitId" => {
55+
let ipfs = self
56+
.global
57+
.ad_unit
58+
.as_ref()
59+
.map(|ad_unit| ad_unit.ipfs.clone());
60+
Ok(Value::String(ipfs.unwrap_or_default()))
61+
}
62+
"advertiserId" => {
63+
let creator = self.global.channel.creator.to_hex_prefix_string();
64+
65+
Ok(Value::String(creator))
66+
}
67+
"campaignId" => Ok(Value::String(self.global.channel.id.to_string())),
68+
"campaignTotalSpent" => Ok(Value::BigNum(
69+
self.global
70+
.balances
71+
.as_ref()
72+
.map(|b| b.values().sum())
73+
.unwrap_or_default(),
74+
)),
75+
"campaignSecondsActive" => {
76+
let duration = Utc::now() - spec.active_from.unwrap_or(spec.created);
77+
78+
let seconds = duration
79+
.to_std()
80+
.map(|duration| duration.as_secs())
81+
.unwrap_or(0);
82+
83+
Ok(Value::Number(seconds.into()))
84+
}
85+
"campaignSecondsDuration" => {
86+
let duration =
87+
spec.withdraw_period_start - spec.active_from.unwrap_or(spec.created);
88+
let seconds = duration
89+
.to_std()
90+
.map(|std_duration| std_duration.as_secs())
91+
.unwrap_or(0);
92+
93+
Ok(Value::Number(seconds.into()))
94+
}
95+
"campaignBudget" => Ok(Value::BigNum(self.global.channel.deposit_amount.clone())),
96+
"eventMinPrice" => {
97+
let min = get_pricing_bounds(&self.global.channel, &self.global.event_type).min;
98+
Ok(Value::BigNum(min))
99+
}
100+
"eventMaxPrice" => {
101+
let max = get_pricing_bounds(&self.global.channel, &self.global.event_type).max;
102+
Ok(Value::BigNum(max))
103+
}
104+
"publisherEarnedFromCampaign" => {
105+
let earned = self
106+
.global
107+
.balances
108+
.as_ref()
109+
.and_then(|balances| balances.get(&self.global.publisher_id))
110+
.cloned()
111+
.unwrap_or_default();
112+
113+
Ok(Value::BigNum(earned))
114+
}
71115
"adSlot.categories" => self
72116
.ad_slot
73117
.as_ref()
@@ -99,41 +143,54 @@ impl Input {
99143
}
100144
}
101145

146+
fn get_pricing_bounds(channel: &Channel, event_type: &str) -> Pricing {
147+
channel
148+
.spec
149+
.pricing_bounds
150+
.as_ref()
151+
.and_then(|pricing_bounds| pricing_bounds.get(event_type))
152+
.cloned()
153+
.unwrap_or_else(|| {
154+
if event_type == "IMPRESSION" {
155+
Pricing {
156+
min: channel.spec.min_per_impression.clone().max(1.into()),
157+
max: channel.spec.max_per_impression.clone().max(1.into()),
158+
}
159+
} else {
160+
Pricing {
161+
min: 0.into(),
162+
max: 0.into(),
163+
}
164+
}
165+
})
166+
}
167+
102168
#[derive(Debug, Clone)]
103-
#[cfg_attr(test, derive(Default))]
104169
pub struct AdView {
105-
pub seconds_since_show: u64,
170+
pub seconds_since_campaign_impression: u64,
106171
pub has_custom_preferences: bool,
172+
pub navigator_language: String,
107173
}
108174

109175
#[derive(Debug, Clone)]
110-
#[cfg_attr(test, derive(Default))]
111176
pub struct Global {
112177
/// Global scope, accessible everywhere
113178
pub ad_slot_id: String,
114179
pub ad_slot_type: String,
115-
pub publisher_id: String,
180+
pub publisher_id: ValidatorId,
116181
pub country: Option<String>,
117182
pub event_type: String,
118183
pub seconds_since_epoch: u64,
119184
pub user_agent_os: Option<String>,
120185
pub user_agent_browser_family: Option<String>,
121186
/// Global scope, accessible everywhere, campaign-dependant
122-
pub ad_unit_id: String,
123-
// adUnitCategories
124-
pub advertiser_id: String,
125-
pub campaign_id: String,
126-
pub campaign_total_spent: String,
127-
pub campaign_seconds_active: u64,
128-
pub campaign_seconds_duration: u64,
129-
pub campaign_budget: BigNum,
130-
pub event_min_price: BigNum,
131-
pub event_max_price: BigNum,
132-
pub publisher_earned_from_campaign: BigNum,
187+
ad_unit: Option<AdUnit>,
188+
channel: Channel,
189+
status: Option<Status>,
190+
balances: Option<BalancesMap>,
133191
}
134192

135193
#[derive(Debug, Clone)]
136-
#[cfg_attr(test, derive(Default))]
137194
pub struct AdSlot {
138195
pub categories: Vec<String>,
139196
pub hostname: String,
@@ -178,20 +235,57 @@ impl From<&Channel> for Output {
178235
#[cfg(test)]
179236
mod test {
180237
use super::*;
238+
use crate::{
239+
supermarket::Status,
240+
util::tests::prep_db::{DUMMY_CHANNEL, IDS},
241+
};
242+
use chrono::Utc;
181243

182244
#[test]
183245
fn test_try_get_of_input() {
184-
let mut input = Input::default();
185-
input.global.ad_slot_id = "ad_slot_id Value".to_string();
186-
input.global.campaign_budget = BigNum::from(50);
187-
input.ad_view = Some(AdView {
188-
seconds_since_show: 10,
189-
has_custom_preferences: false,
190-
});
246+
let ad_unit = AdUnit {
247+
ipfs: "Hash".to_string(),
248+
ad_type: "legacy_300x250".to_string(),
249+
media_url: "media_url".to_string(),
250+
media_mime: "media_mime".to_string(),
251+
target_url: "target_url".to_string(),
252+
targeting: vec![],
253+
min_targeting_score: None,
254+
tags: vec![],
255+
owner: IDS["creator"],
256+
created: Utc::now(),
257+
title: None,
258+
description: None,
259+
archived: false,
260+
modified: None,
261+
};
262+
let input_balances = BalancesMap::default();
263+
let mut input = Input {
264+
ad_view: Some(AdView {
265+
seconds_since_campaign_impression: 10,
266+
has_custom_preferences: false,
267+
navigator_language: "bg".to_string(),
268+
}),
269+
global: Global {
270+
ad_slot_id: "ad_slot_id Value".to_string(),
271+
ad_slot_type: "ad_slot_type Value".to_string(),
272+
publisher_id: IDS["leader"],
273+
country: Some("bg".to_string()),
274+
event_type: "IMPRESSION".to_string(),
275+
seconds_since_epoch: 500,
276+
user_agent_os: Some("os".to_string()),
277+
user_agent_browser_family: Some("family".to_string()),
278+
ad_unit: Some(ad_unit),
279+
channel: DUMMY_CHANNEL.clone(),
280+
status: Some(Status::Initializing),
281+
balances: Some(input_balances),
282+
},
283+
ad_slot: None,
284+
};
191285

192286
let ad_view_seconds_since_show = input
193-
.try_get("adView.secondsSinceShow")
194-
.expect("Should get the ad_view.seconds_since_show field");
287+
.try_get("adView.secondsSinceCampaignImpression")
288+
.expect("Should get the ad_view.seconds_since_campaign_impression field");
195289

196290
let expected_number = serde_json::Number::from(10);
197291

@@ -213,14 +307,20 @@ mod test {
213307
.try_get("campaignBudget")
214308
.expect("Should get the global.campaign_budget field");
215309

216-
assert_eq!(Value::BigNum(BigNum::from(50)), global_campaign_budget);
310+
assert_eq!(
311+
Value::BigNum(DUMMY_CHANNEL.deposit_amount.clone()),
312+
global_campaign_budget
313+
);
217314

218315
assert_eq!(
219316
Err(Error::UnknownVariable),
220317
input.try_get("adSlot.alexaRank")
221318
);
222-
let mut ad_slot = AdSlot::default();
223-
ad_slot.alexa_rank = Some(20.0);
319+
let ad_slot = AdSlot {
320+
categories: vec![],
321+
hostname: "".to_string(),
322+
alexa_rank: Some(20.0),
323+
};
224324
input.ad_slot = Some(ad_slot);
225325
assert!(input.try_get("adSlot.alexaRank").is_ok());
226326
}

0 commit comments

Comments
 (0)