Skip to content

Commit eeb35f8

Browse files
authored
Issue #24 ChannelSpec (#37)
* domain - add dummy structs: - AdUnit - EventSubmission - TargetingTag * util - serde - ts_milliseconds_option - impl ser/deser for `Option<DateTime<Utc>>` * domain - ChannelSpec - adding all the fields in almost ready state: - domain - ValidatorDesc - rename `id` to `addr` - domain - ChannelSpec - add all the optional fields & optional DateTime for `active_from` - domain - channel - fixtures - update `get_channel_spec` fixture with **dummy** data for now * util - test - take_one - Cargo.toml - add `rand` to `dev-dependencies` * - domain - channel - fixtures - get_channel_spec - add most of the fake data generated from `Faker` * - domain - channel - fixtures - get_channel_spec - small improvements
1 parent c29e00b commit eeb35f8

File tree

12 files changed

+127
-14
lines changed

12 files changed

+127
-14
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sentry/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ num-bigint = { version = "0.2", features = ["serde"] }
3737
chrono = { version = "0.4", features = ["serde"] }
3838
time = "0.1.42"
3939
[dev-dependencies]
40-
fake = { version = "1.3", features = ["chrono"] }
40+
fake = { version = "^1.3", features = ["chrono"] }
41+
rand = "^0.6"

sentry/src/domain.rs

+6
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@ use std::pin::Pin;
44

55
use futures::Future;
66

7+
pub use self::ad_unit::AdUnit;
78
pub use self::asset::Asset;
89
pub use self::bignum::BigNum;
910
pub use self::channel::{Channel, ChannelId, ChannelListParams, ChannelRepository, ChannelSpec};
11+
pub use self::event_submission::EventSubmission;
12+
pub use self::targeting_tag::TargetingTag;
1013
pub use self::validator::ValidatorDesc;
1114

1215
pub mod bignum;
1316
pub mod channel;
1417
pub mod validator;
1518
pub mod asset;
19+
pub mod targeting_tag;
20+
pub mod ad_unit;
21+
pub mod event_submission;
1622

1723
#[cfg(test)]
1824
/// re-exports all the fixtures in one module

sentry/src/domain/ad_unit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Serialize, Deserialize, Debug, Clone)]
4+
pub struct AdUnit {}

sentry/src/domain/channel.rs

+40-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use std::convert::TryFrom;
22

33
use chrono::{DateTime, Utc};
4+
use chrono::serde::ts_milliseconds;
45
use serde::{Deserialize, Serialize};
56
use serde_hex::{SerHex, StrictPfx};
67

7-
use crate::domain::{Asset, DomainError, RepositoryFuture, ValidatorDesc};
8+
use crate::domain::{AdUnit, Asset, DomainError, EventSubmission, RepositoryFuture, TargetingTag, ValidatorDesc};
89
use crate::domain::bignum::BigNum;
10+
use crate::util::serde::ts_milliseconds_option;
911

1012
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
1113
#[serde(transparent)]
@@ -55,6 +57,7 @@ pub struct Channel {
5557
pub creator: String,
5658
pub deposit_asset: Asset,
5759
pub deposit_amount: BigNum,
60+
#[serde(with = "ts_milliseconds")]
5861
pub valid_until: DateTime<Utc>,
5962
pub spec: ChannelSpec,
6063
}
@@ -63,7 +66,40 @@ pub struct Channel {
6366
#[serde(rename_all = "camelCase")]
6467
pub struct ChannelSpec {
6568
// TODO: Add the rest of the fields Issue #24
69+
#[serde(default, skip_serializing_if = "Option::is_none")]
70+
pub title: Option<String>,
71+
// TODO: Make a custom ser/deser 2 validators(leader, follower) array
6672
pub validators: Vec<ValidatorDesc>,
73+
/// Maximum payment per impression
74+
pub max_per_impression: BigNum,
75+
/// Minimum payment offered per impression
76+
pub min_per_impression: BigNum,
77+
/// An array of TargetingTag (optional)
78+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
79+
pub targeting: Vec<TargetingTag>,
80+
/// Minimum targeting score (optional)
81+
#[serde(default, skip_serializing_if = "Option::is_none")]
82+
pub min_targeting_score: Option<u64>,
83+
/// EventSubmission object, applies to event submission (POST /channel/:id/events)
84+
pub event_submission: EventSubmission,
85+
/// A millisecond timestamp of when the campaign was created
86+
#[serde(with = "ts_milliseconds")]
87+
pub created: DateTime<Utc>,
88+
/// A millisecond timestamp representing the time you want this campaign to become active (optional)
89+
/// Used by the AdViewManager
90+
#[serde(default, skip_serializing_if = "Option::is_none", with = "ts_milliseconds_option")]
91+
pub active_from: Option<DateTime<Utc>>,
92+
/// A random number to ensure the campaignSpec hash is unique
93+
pub nonce: BigNum,
94+
/// A millisecond timestamp of when the campaign should enter a withdraw period
95+
/// (no longer accept any events other than CHANNEL_CLOSE)
96+
/// A sane value should be lower than channel.validUntil * 1000 and higher than created
97+
/// It's recommended to set this at least one month prior to channel.validUntil * 1000
98+
#[serde(with = "ts_milliseconds")]
99+
pub withdraw_period_start: DateTime<Utc>,
100+
/// An array of AdUnit (optional)
101+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
102+
pub ad_units: Vec<AdUnit>,
67103
}
68104

69105
pub struct ChannelListParams {
@@ -91,12 +127,9 @@ impl ChannelListParams {
91127
}
92128

93129
let validator = validator
94-
.and_then(|s| {
95-
if s.is_empty() {
96-
return None;
97-
}
98-
99-
Some(s)
130+
.and_then(|s| match s.is_empty() {
131+
true => None,
132+
false => Some(s),
100133
});
101134

102135
Ok(Self {

sentry/src/domain/channel_fixtures.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ pub fn get_channel_spec(prefix: &str, validators_option: ValidatorsOption) -> Ch
7171
ValidatorsOption::Some(validators) => validators,
7272
ValidatorsOption::None => vec![],
7373
};
74+
use crate::domain::EventSubmission;
75+
use test_util::take_one;
7476

75-
ChannelSpec { validators }
77+
let title_string = Some(<Faker as Lorem>::sentence(3, 4));
78+
79+
let title = take_one(&[&title_string, &None]).to_owned();
80+
let max_per_impression = BigNum::try_from(<Faker as Number>::between(250_u32, 500_u32)).expect("BigNum error when creating from random number");
81+
let min_per_impression = BigNum::try_from(<Faker as Number>::between(1_u32, 250_u32)).expect("BigNum error when creating from random number");
82+
let nonce = BigNum::try_from(<Faker as Number>::between(100_000_000_u32, 999_999_999_u32)).expect("BigNum error when creating from random number");
83+
let min_targeting_score = take_one(&[&None, &Some(<Faker as Number>::between(1, 500))]).to_owned();
84+
85+
ChannelSpec {
86+
validators,
87+
title,
88+
max_per_impression,
89+
min_per_impression,
90+
// @TODO: `TargetingTag`s fixtures issue #26
91+
targeting: Vec::new(),
92+
min_targeting_score,
93+
// @TODO: `EventSubmission` fixture issue #27
94+
event_submission: EventSubmission {},
95+
created: Utc::now(),
96+
active_from: Some(Utc::now()),
97+
nonce,
98+
withdraw_period_start: Utc::now(),
99+
ad_units: Vec::new(),
100+
}
76101
}

sentry/src/domain/event_submission.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Serialize, Deserialize, Debug, Clone)]
4+
pub struct EventSubmission {}

sentry/src/domain/targeting_tag.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Serialize, Deserialize, Debug, Clone)]
4+
pub struct TargetingTag {}

sentry/src/domain/validator.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use crate::domain::BigNum;
55
#[derive(Serialize, Deserialize, Debug, Clone)]
66
#[serde(rename_all = "camelCase")]
77
pub struct ValidatorDesc {
8-
pub id: String,
8+
// @TODO: UserId issue #36
9+
pub addr: String,
910
pub url: String,
1011
pub fee: BigNum,
1112
}
@@ -25,7 +26,7 @@ pub(crate) mod fixtures {
2526
let url = format!("http://{}-validator-url.com/validator", validator_id);
2627

2728
ValidatorDesc {
28-
id: validator_id.to_string(),
29+
addr: validator_id.to_string(),
2930
url,
3031
fee,
3132
}

sentry/src/infrastructure/persistence/channel/memory.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl ChannelRepository for MemoryChannelRepository {
3838
Some(validator_id) => {
3939
// check if there is any validator in the current
4040
// `channel.spec.validators` that has the same `id`
41-
channel.spec.validators.iter().any(|validator| &validator.id == validator_id)
41+
channel.spec.validators.iter().any(|validator| &validator.addr == validator_id)
4242
}
4343
// if None -> the current channel has passed, since we don't need to filter by anything
4444
None => true,

sentry/src/util.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,27 @@
11
#[cfg(test)]
2-
pub mod tests;
2+
pub mod tests;
3+
4+
pub mod serde {
5+
pub mod ts_milliseconds_option {
6+
use chrono::{DateTime, Utc};
7+
use chrono::serde::ts_milliseconds::deserialize as from_ts_milliseconds;
8+
use chrono::serde::ts_milliseconds::serialize as to_ts_milliseconds;
9+
use serde::{Deserializer, Serializer};
10+
11+
pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
12+
where S: Serializer
13+
{
14+
match *opt {
15+
Some(ref dt) => to_ts_milliseconds(dt, serializer),
16+
None => serializer.serialize_none(),
17+
}
18+
}
19+
20+
pub fn deserialize<'de, D>(de: D) -> Result<Option<DateTime<Utc>>, D::Error>
21+
where
22+
D: Deserializer<'de>,
23+
{
24+
from_ts_milliseconds(de).map(Some)
25+
}
26+
}
27+
}

sentry/src/util/tests.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
pub mod time;
1+
use rand::seq::SliceRandom;
2+
use rand::thread_rng;
3+
4+
pub mod time;
5+
6+
#[inline]
7+
pub fn take_one<'a, T: ?Sized>(list: &[&'a T]) -> &'a T {
8+
let mut rng = thread_rng();
9+
list.choose(&mut rng).expect("take_one got empty list")
10+
}

0 commit comments

Comments
 (0)