diff --git a/Cargo.lock b/Cargo.lock index 4acfe92..a6aee01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3211,7 +3211,7 @@ dependencies = [ [[package]] name = "pyth-agent" -version = "2.7.0" +version = "2.8.0" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index f7fa1f9..d66c5bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyth-agent" -version = "2.7.0" +version = "2.8.0" edition = "2021" [[bin]] diff --git a/src/agent/legacy_schedule.rs b/src/agent/legacy_schedule.rs index 8360021..c2cd99f 100644 --- a/src/agent/legacy_schedule.rs +++ b/src/agent/legacy_schedule.rs @@ -1,4 +1,5 @@ //! Market hours metadata parsing and evaluation logic +#![allow(deprecated)] use { anyhow::{ diff --git a/src/agent/market_schedule.rs b/src/agent/market_schedule.rs index 718f393..ae6af30 100644 --- a/src/agent/market_schedule.rs +++ b/src/agent/market_schedule.rs @@ -1,5 +1,6 @@ //! Holiday hours metadata parsing and evaluation logic +#[allow(deprecated)] use { super::legacy_schedule::{ LegacySchedule, @@ -19,6 +20,7 @@ use { chrono_tz::Tz, std::{ fmt::Display, + ops::RangeInclusive, str::FromStr, }, winnow::{ @@ -129,6 +131,7 @@ impl FromStr for MarketSchedule { } } +#[allow(deprecated)] impl From for MarketSchedule { fn from(legacy: LegacySchedule) -> Self { Self { @@ -190,11 +193,11 @@ impl Display for HolidayDaySchedule { } } -#[derive(Clone, Debug, Eq, PartialEq, Copy)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum ScheduleDayKind { Open, Closed, - TimeRange(NaiveTime, NaiveTime), + TimeRanges(Vec>), } impl ScheduleDayKind { @@ -202,7 +205,7 @@ impl ScheduleDayKind { match self { Self::Open => true, Self::Closed => false, - Self::TimeRange(start, end) => start <= &when_local && &when_local <= end, + Self::TimeRanges(ranges) => ranges.iter().any(|range| range.contains(&when_local)), } } } @@ -218,8 +221,20 @@ impl Display for ScheduleDayKind { match self { Self::Open => write!(f, "O"), Self::Closed => write!(f, "C"), - Self::TimeRange(start, end) => { - write!(f, "{}-{}", start.format("%H%M"), end.format("%H%M")) + Self::TimeRanges(ranges) => { + let mut ranges = ranges.iter().peekable(); + while let Some(range) = ranges.next() { + write!( + f, + "{}-{}", + range.start().format("%H%M"), + range.end().format("%H%M") + )?; + if ranges.peek().is_some() { + write!(f, "&")?; + } + } + Ok(()) } } } @@ -234,13 +249,13 @@ fn time_parser<'s>(input: &mut &'s str) -> PResult { .parse_next(input) } -fn time_range_parser<'s>(input: &mut &'s str) -> PResult { +fn time_range_parser<'s>(input: &mut &'s str) -> PResult> { seq!( time_parser, _: "-", time_parser, ) - .map(|s| ScheduleDayKind::TimeRange(s.0, s.1)) + .map(|s| s.0..=s.1) .parse_next(input) } @@ -248,7 +263,7 @@ fn schedule_day_kind_parser<'s>(input: &mut &'s str) -> PResult alt(( "C".map(|_| ScheduleDayKind::Closed), "O".map(|_| ScheduleDayKind::Open), - time_range_parser, + separated(1.., time_range_parser, "&").map(ScheduleDayKind::TimeRanges), )) .parse_next(input) } @@ -267,7 +282,7 @@ impl From for ScheduleDayKind { match mhkind { MHKind::Open => ScheduleDayKind::Open, MHKind::Closed => ScheduleDayKind::Closed, - MHKind::TimeRange(start, end) => ScheduleDayKind::TimeRange(start, end), + MHKind::TimeRange(start, end) => ScheduleDayKind::TimeRanges(vec![start..=end]), } } } @@ -290,6 +305,7 @@ mod tests { let open = "O"; let closed = "C"; let valid = "1234-1347"; + let valid_double = "1234-1347&1400-1500"; let valid2400 = "1234-2400"; let invalid = "1234-5668"; let invalid_format = "1234-56"; @@ -304,17 +320,25 @@ mod tests { ); assert_eq!( valid.parse::().unwrap(), - ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(12, 34, 0).unwrap(), - NaiveTime::from_hms_opt(13, 47, 0).unwrap(), - ) + ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap() + ..=NaiveTime::from_hms_opt(13, 47, 0).unwrap() + ]) + ); + assert_eq!( + valid_double.parse::().unwrap(), + ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap() + ..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(), + NaiveTime::from_hms_opt(14, 0, 0).unwrap() + ..=NaiveTime::from_hms_opt(15, 0, 0).unwrap(), + ]) ); assert_eq!( valid2400.parse::().unwrap(), - ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(12, 34, 0).unwrap(), - MAX_TIME_INSTANT, - ) + ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap()..=MAX_TIME_INSTANT + ]) ); assert!(invalid.parse::().is_err()); assert!(invalid_format.parse::().is_err()); @@ -347,10 +371,10 @@ mod tests { let expected = HolidayDaySchedule { month: 04, day: 12, - kind: ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(12, 34, 0).unwrap(), - NaiveTime::from_hms_opt(13, 47, 0).unwrap(), - ), + kind: ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap() + ..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(), + ]), }; let parsed = input.parse::()?; assert_eq!(parsed, expected); @@ -371,14 +395,13 @@ mod tests { timezone: Tz::America__New_York, weekly_schedule: vec![ ScheduleDayKind::Open, - ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(12, 34, 0).unwrap(), - NaiveTime::from_hms_opt(13, 47, 0).unwrap(), - ), - ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(09, 30, 0).unwrap(), - MAX_TIME_INSTANT, - ), + ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap() + ..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(), + ]), + ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(09, 30, 0).unwrap()..=MAX_TIME_INSTANT, + ]), ScheduleDayKind::Closed, ScheduleDayKind::Closed, ScheduleDayKind::Closed, @@ -398,18 +421,17 @@ mod tests { HolidayDaySchedule { month: 04, day: 14, - kind: ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(12, 34, 0).unwrap(), - NaiveTime::from_hms_opt(13, 47, 0).unwrap(), - ), + kind: ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(12, 34, 0).unwrap() + ..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(), + ]), }, HolidayDaySchedule { month: 12, day: 30, - kind: ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(09, 30, 0).unwrap(), - MAX_TIME_INSTANT, - ), + kind: ScheduleDayKind::TimeRanges(vec![ + NaiveTime::from_hms_opt(09, 30, 0).unwrap()..=MAX_TIME_INSTANT, + ]), }, ], }; @@ -476,18 +498,24 @@ mod tests { } prop_compose! { - fn schedule_day_kind()( - r in any::(), + fn time_range()( t1 in any::(), t2 in any::(), + ) -> RangeInclusive { + NaiveTime::from_hms_opt(t1 % 24, t1 / 24 % 60, 0).unwrap()..= + NaiveTime::from_hms_opt(t2 % 24, t2 / 24 % 60, 0).unwrap() + } + } + + prop_compose! { + fn schedule_day_kind()( + r in any::(), + ranges in proptest::collection::vec(time_range(), 1..3), ) -> ScheduleDayKind { match r % 3 { 0 => ScheduleDayKind::Open, 1 => ScheduleDayKind::Closed, - _ => ScheduleDayKind::TimeRange( - NaiveTime::from_hms_opt(t1 % 24, t1 / 24 % 60, 0).unwrap(), - NaiveTime::from_hms_opt(t2 % 24, t2 / 24 % 60, 0).unwrap(), - ), + _ => ScheduleDayKind::TimeRanges(ranges), } } } diff --git a/src/agent/solana/oracle.rs b/src/agent/solana/oracle.rs index ff7c1f4..148f7d6 100644 --- a/src/agent/solana/oracle.rs +++ b/src/agent/solana/oracle.rs @@ -1,5 +1,6 @@ // This module is responsible for loading the current state of the // on-chain Oracle program accounts from Solana. +#[allow(deprecated)] use { self::subscriber::Subscriber, super::{ @@ -648,6 +649,7 @@ impl Poller { let product = load_product_account(prod_acc.data.as_slice()) .context(format!("Could not parse product account {}", product_key))?; + #[allow(deprecated)] let legacy_schedule: LegacySchedule = if let Some((_wsched_key, wsched_val)) = product.iter().find(|(k, _v)| *k == "weekly_schedule") {