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 ;
2
6
use std:: collections:: HashMap ;
3
7
4
8
pub use eval:: * ;
5
9
6
10
mod eval;
7
11
8
12
#[ derive( Debug , Clone ) ]
9
- #[ cfg_attr( test, derive( Default ) ) ]
10
13
pub struct Input {
11
14
/// AdView scope, accessible only on the AdView
12
15
pub ad_view : Option < AdView > ,
@@ -18,11 +21,13 @@ pub struct Input {
18
21
19
22
impl Input {
20
23
fn try_get ( & self , key : & str ) -> Result < Value , Error > {
24
+ let spec = & self . global . channel . spec ;
25
+
21
26
match key {
22
- "adView.secondsSinceShow " => self
27
+ "adView.secondsSinceCampaignImpression " => self
23
28
. ad_view
24
29
. 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 ( ) ) )
26
31
. ok_or ( Error :: UnknownVariable ) ,
27
32
"adView.hasCustomPreferences" => self
28
33
. ad_view
@@ -31,30 +36,7 @@ impl Input {
31
36
. ok_or ( Error :: UnknownVariable ) ,
32
37
"adSlotId" => Ok ( Value :: String ( self . global . ad_slot_id . clone ( ) ) ) ,
33
38
"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 ( ) ) ) ,
58
40
"secondsSinceEpoch" => Ok ( Value :: Number ( self . global . seconds_since_epoch . into ( ) ) ) ,
59
41
"userAgentOS" => self
60
42
. global
@@ -68,6 +50,68 @@ impl Input {
68
50
. clone ( )
69
51
. map ( Value :: String )
70
52
. 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
+ }
71
115
"adSlot.categories" => self
72
116
. ad_slot
73
117
. as_ref ( )
@@ -99,41 +143,54 @@ impl Input {
99
143
}
100
144
}
101
145
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
+
102
168
#[ derive( Debug , Clone ) ]
103
- #[ cfg_attr( test, derive( Default ) ) ]
104
169
pub struct AdView {
105
- pub seconds_since_show : u64 ,
170
+ pub seconds_since_campaign_impression : u64 ,
106
171
pub has_custom_preferences : bool ,
172
+ pub navigator_language : String ,
107
173
}
108
174
109
175
#[ derive( Debug , Clone ) ]
110
- #[ cfg_attr( test, derive( Default ) ) ]
111
176
pub struct Global {
112
177
/// Global scope, accessible everywhere
113
178
pub ad_slot_id : String ,
114
179
pub ad_slot_type : String ,
115
- pub publisher_id : String ,
180
+ pub publisher_id : ValidatorId ,
116
181
pub country : Option < String > ,
117
182
pub event_type : String ,
118
183
pub seconds_since_epoch : u64 ,
119
184
pub user_agent_os : Option < String > ,
120
185
pub user_agent_browser_family : Option < String > ,
121
186
/// 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 > ,
133
191
}
134
192
135
193
#[ derive( Debug , Clone ) ]
136
- #[ cfg_attr( test, derive( Default ) ) ]
137
194
pub struct AdSlot {
138
195
pub categories : Vec < String > ,
139
196
pub hostname : String ,
@@ -178,20 +235,57 @@ impl From<&Channel> for Output {
178
235
#[ cfg( test) ]
179
236
mod test {
180
237
use super :: * ;
238
+ use crate :: {
239
+ supermarket:: Status ,
240
+ util:: tests:: prep_db:: { DUMMY_CHANNEL , IDS } ,
241
+ } ;
242
+ use chrono:: Utc ;
181
243
182
244
#[ test]
183
245
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
+ } ;
191
285
192
286
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" ) ;
195
289
196
290
let expected_number = serde_json:: Number :: from ( 10 ) ;
197
291
@@ -213,14 +307,20 @@ mod test {
213
307
. try_get ( "campaignBudget" )
214
308
. expect ( "Should get the global.campaign_budget field" ) ;
215
309
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
+ ) ;
217
314
218
315
assert_eq ! (
219
316
Err ( Error :: UnknownVariable ) ,
220
317
input. try_get( "adSlot.alexaRank" )
221
318
) ;
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
+ } ;
224
324
input. ad_slot = Some ( ad_slot) ;
225
325
assert ! ( input. try_get( "adSlot.alexaRank" ) . is_ok( ) ) ;
226
326
}
0 commit comments