Skip to content

Issue #24 ChannelSpec #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion sentry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ num-bigint = { version = "0.2", features = ["serde"] }
chrono = { version = "0.4", features = ["serde"] }
time = "0.1.42"
[dev-dependencies]
fake = { version = "1.3", features = ["chrono"] }
fake = { version = "^1.3", features = ["chrono"] }
rand = "^0.6"
6 changes: 6 additions & 0 deletions sentry/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ use std::pin::Pin;

use futures::Future;

pub use self::ad_unit::AdUnit;
pub use self::asset::Asset;
pub use self::bignum::BigNum;
pub use self::channel::{Channel, ChannelId, ChannelListParams, ChannelRepository, ChannelSpec};
pub use self::event_submission::EventSubmission;
pub use self::targeting_tag::TargetingTag;
pub use self::validator::ValidatorDesc;

pub mod bignum;
pub mod channel;
pub mod validator;
pub mod asset;
pub mod targeting_tag;
pub mod ad_unit;
pub mod event_submission;

#[cfg(test)]
/// re-exports all the fixtures in one module
Expand Down
4 changes: 4 additions & 0 deletions sentry/src/domain/ad_unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AdUnit {}
47 changes: 40 additions & 7 deletions sentry/src/domain/channel.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::convert::TryFrom;

use chrono::{DateTime, Utc};
use chrono::serde::ts_milliseconds;
use serde::{Deserialize, Serialize};
use serde_hex::{SerHex, StrictPfx};

use crate::domain::{Asset, DomainError, RepositoryFuture, ValidatorDesc};
use crate::domain::{AdUnit, Asset, DomainError, EventSubmission, RepositoryFuture, TargetingTag, ValidatorDesc};
use crate::domain::bignum::BigNum;
use crate::util::serde::ts_milliseconds_option;

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
#[serde(transparent)]
Expand Down Expand Up @@ -55,6 +57,7 @@ pub struct Channel {
pub creator: String,
pub deposit_asset: Asset,
pub deposit_amount: BigNum,
#[serde(with = "ts_milliseconds")]
pub valid_until: DateTime<Utc>,
pub spec: ChannelSpec,
}
Expand All @@ -63,7 +66,40 @@ pub struct Channel {
#[serde(rename_all = "camelCase")]
pub struct ChannelSpec {
// TODO: Add the rest of the fields Issue #24
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
// TODO: Make a custom ser/deser 2 validators(leader, follower) array
pub validators: Vec<ValidatorDesc>,
/// Maximum payment per impression
pub max_per_impression: BigNum,
/// Minimum payment offered per impression
pub min_per_impression: BigNum,
/// An array of TargetingTag (optional)
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub targeting: Vec<TargetingTag>,
/// Minimum targeting score (optional)
#[serde(default, skip_serializing_if = "Option::is_none")]
pub min_targeting_score: Option<u64>,
/// EventSubmission object, applies to event submission (POST /channel/:id/events)
pub event_submission: EventSubmission,
/// A millisecond timestamp of when the campaign was created
#[serde(with = "ts_milliseconds")]
pub created: DateTime<Utc>,
/// A millisecond timestamp representing the time you want this campaign to become active (optional)
/// Used by the AdViewManager
#[serde(default, skip_serializing_if = "Option::is_none", with = "ts_milliseconds_option")]
pub active_from: Option<DateTime<Utc>>,
/// A random number to ensure the campaignSpec hash is unique
pub nonce: BigNum,
/// A millisecond timestamp of when the campaign should enter a withdraw period
/// (no longer accept any events other than CHANNEL_CLOSE)
/// A sane value should be lower than channel.validUntil * 1000 and higher than created
/// It's recommended to set this at least one month prior to channel.validUntil * 1000
#[serde(with = "ts_milliseconds")]
pub withdraw_period_start: DateTime<Utc>,
/// An array of AdUnit (optional)
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub ad_units: Vec<AdUnit>,
}

pub struct ChannelListParams {
Expand Down Expand Up @@ -91,12 +127,9 @@ impl ChannelListParams {
}

let validator = validator
.and_then(|s| {
if s.is_empty() {
return None;
}

Some(s)
.and_then(|s| match s.is_empty() {
true => None,
false => Some(s),
});

Ok(Self {
Expand Down
27 changes: 26 additions & 1 deletion sentry/src/domain/channel_fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,31 @@ pub fn get_channel_spec(prefix: &str, validators_option: ValidatorsOption) -> Ch
ValidatorsOption::Some(validators) => validators,
ValidatorsOption::None => vec![],
};
use crate::domain::EventSubmission;
use test_util::take_one;

ChannelSpec { validators }
let title_string = Some(<Faker as Lorem>::sentence(3, 4));

let title = take_one(&[&title_string, &None]).to_owned();
let max_per_impression = BigNum::try_from(<Faker as Number>::between(250_u32, 500_u32)).expect("BigNum error when creating from random number");
let min_per_impression = BigNum::try_from(<Faker as Number>::between(1_u32, 250_u32)).expect("BigNum error when creating from random number");
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");
let min_targeting_score = take_one(&[&None, &Some(<Faker as Number>::between(1, 500))]).to_owned();

ChannelSpec {
validators,
title,
max_per_impression,
min_per_impression,
// @TODO: `TargetingTag`s fixtures issue #26
targeting: Vec::new(),
min_targeting_score,
// @TODO: `EventSubmission` fixture issue #27
event_submission: EventSubmission {},
created: Utc::now(),
active_from: Some(Utc::now()),
nonce,
withdraw_period_start: Utc::now(),
ad_units: Vec::new(),
}
}
4 changes: 4 additions & 0 deletions sentry/src/domain/event_submission.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EventSubmission {}
4 changes: 4 additions & 0 deletions sentry/src/domain/targeting_tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TargetingTag {}
5 changes: 3 additions & 2 deletions sentry/src/domain/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::domain::BigNum;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ValidatorDesc {
pub id: String,
// @TODO: UserId issue #36
pub addr: String,
pub url: String,
pub fee: BigNum,
}
Expand All @@ -25,7 +26,7 @@ pub(crate) mod fixtures {
let url = format!("http://{}-validator-url.com/validator", validator_id);

ValidatorDesc {
id: validator_id.to_string(),
addr: validator_id.to_string(),
url,
fee,
}
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/infrastructure/persistence/channel/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl ChannelRepository for MemoryChannelRepository {
Some(validator_id) => {
// check if there is any validator in the current
// `channel.spec.validators` that has the same `id`
channel.spec.validators.iter().any(|validator| &validator.id == validator_id)
channel.spec.validators.iter().any(|validator| &validator.addr == validator_id)
}
// if None -> the current channel has passed, since we don't need to filter by anything
None => true,
Expand Down
27 changes: 26 additions & 1 deletion sentry/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,27 @@
#[cfg(test)]
pub mod tests;
pub mod tests;

pub mod serde {
pub mod ts_milliseconds_option {
use chrono::{DateTime, Utc};
use chrono::serde::ts_milliseconds::deserialize as from_ts_milliseconds;
use chrono::serde::ts_milliseconds::serialize as to_ts_milliseconds;
use serde::{Deserializer, Serializer};

pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match *opt {
Some(ref dt) => to_ts_milliseconds(dt, serializer),
None => serializer.serialize_none(),
}
}

pub fn deserialize<'de, D>(de: D) -> Result<Option<DateTime<Utc>>, D::Error>
where
D: Deserializer<'de>,
{
from_ts_milliseconds(de).map(Some)
}
}
}
11 changes: 10 additions & 1 deletion sentry/src/util/tests.rs
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
pub mod time;
use rand::seq::SliceRandom;
use rand::thread_rng;

pub mod time;

#[inline]
pub fn take_one<'a, T: ?Sized>(list: &[&'a T]) -> &'a T {
let mut rng = thread_rng();
list.choose(&mut rng).expect("take_one got empty list")
}