Skip to content

Commit fee170f

Browse files
authored
feat: support multiple time ranges in schedule (#127)
* chore: fix deprecated warnings * feat: support multiple time ranges in schedule * chore: bump version
1 parent 660b216 commit fee170f

File tree

5 files changed

+76
-45
lines changed

5 files changed

+76
-45
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-agent"
3-
version = "2.7.0"
3+
version = "2.8.0"
44
edition = "2021"
55

66
[[bin]]

src/agent/legacy_schedule.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Market hours metadata parsing and evaluation logic
2+
#![allow(deprecated)]
23

34
use {
45
anyhow::{

src/agent/market_schedule.rs

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Holiday hours metadata parsing and evaluation logic
22
3+
#[allow(deprecated)]
34
use {
45
super::legacy_schedule::{
56
LegacySchedule,
@@ -19,6 +20,7 @@ use {
1920
chrono_tz::Tz,
2021
std::{
2122
fmt::Display,
23+
ops::RangeInclusive,
2224
str::FromStr,
2325
},
2426
winnow::{
@@ -129,6 +131,7 @@ impl FromStr for MarketSchedule {
129131
}
130132
}
131133

134+
#[allow(deprecated)]
132135
impl From<LegacySchedule> for MarketSchedule {
133136
fn from(legacy: LegacySchedule) -> Self {
134137
Self {
@@ -190,19 +193,19 @@ impl Display for HolidayDaySchedule {
190193
}
191194
}
192195

193-
#[derive(Clone, Debug, Eq, PartialEq, Copy)]
196+
#[derive(Clone, Debug, Eq, PartialEq)]
194197
pub enum ScheduleDayKind {
195198
Open,
196199
Closed,
197-
TimeRange(NaiveTime, NaiveTime),
200+
TimeRanges(Vec<RangeInclusive<NaiveTime>>),
198201
}
199202

200203
impl ScheduleDayKind {
201204
pub fn can_publish_at(&self, when_local: NaiveTime) -> bool {
202205
match self {
203206
Self::Open => true,
204207
Self::Closed => false,
205-
Self::TimeRange(start, end) => start <= &when_local && &when_local <= end,
208+
Self::TimeRanges(ranges) => ranges.iter().any(|range| range.contains(&when_local)),
206209
}
207210
}
208211
}
@@ -218,8 +221,20 @@ impl Display for ScheduleDayKind {
218221
match self {
219222
Self::Open => write!(f, "O"),
220223
Self::Closed => write!(f, "C"),
221-
Self::TimeRange(start, end) => {
222-
write!(f, "{}-{}", start.format("%H%M"), end.format("%H%M"))
224+
Self::TimeRanges(ranges) => {
225+
let mut ranges = ranges.iter().peekable();
226+
while let Some(range) = ranges.next() {
227+
write!(
228+
f,
229+
"{}-{}",
230+
range.start().format("%H%M"),
231+
range.end().format("%H%M")
232+
)?;
233+
if ranges.peek().is_some() {
234+
write!(f, "&")?;
235+
}
236+
}
237+
Ok(())
223238
}
224239
}
225240
}
@@ -234,21 +249,21 @@ fn time_parser<'s>(input: &mut &'s str) -> PResult<NaiveTime> {
234249
.parse_next(input)
235250
}
236251

237-
fn time_range_parser<'s>(input: &mut &'s str) -> PResult<ScheduleDayKind> {
252+
fn time_range_parser<'s>(input: &mut &'s str) -> PResult<RangeInclusive<NaiveTime>> {
238253
seq!(
239254
time_parser,
240255
_: "-",
241256
time_parser,
242257
)
243-
.map(|s| ScheduleDayKind::TimeRange(s.0, s.1))
258+
.map(|s| s.0..=s.1)
244259
.parse_next(input)
245260
}
246261

247262
fn schedule_day_kind_parser<'s>(input: &mut &'s str) -> PResult<ScheduleDayKind> {
248263
alt((
249264
"C".map(|_| ScheduleDayKind::Closed),
250265
"O".map(|_| ScheduleDayKind::Open),
251-
time_range_parser,
266+
separated(1.., time_range_parser, "&").map(ScheduleDayKind::TimeRanges),
252267
))
253268
.parse_next(input)
254269
}
@@ -267,7 +282,7 @@ impl From<MHKind> for ScheduleDayKind {
267282
match mhkind {
268283
MHKind::Open => ScheduleDayKind::Open,
269284
MHKind::Closed => ScheduleDayKind::Closed,
270-
MHKind::TimeRange(start, end) => ScheduleDayKind::TimeRange(start, end),
285+
MHKind::TimeRange(start, end) => ScheduleDayKind::TimeRanges(vec![start..=end]),
271286
}
272287
}
273288
}
@@ -290,6 +305,7 @@ mod tests {
290305
let open = "O";
291306
let closed = "C";
292307
let valid = "1234-1347";
308+
let valid_double = "1234-1347&1400-1500";
293309
let valid2400 = "1234-2400";
294310
let invalid = "1234-5668";
295311
let invalid_format = "1234-56";
@@ -304,17 +320,25 @@ mod tests {
304320
);
305321
assert_eq!(
306322
valid.parse::<ScheduleDayKind>().unwrap(),
307-
ScheduleDayKind::TimeRange(
308-
NaiveTime::from_hms_opt(12, 34, 0).unwrap(),
309-
NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
310-
)
323+
ScheduleDayKind::TimeRanges(vec![
324+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()
325+
..=NaiveTime::from_hms_opt(13, 47, 0).unwrap()
326+
])
327+
);
328+
assert_eq!(
329+
valid_double.parse::<ScheduleDayKind>().unwrap(),
330+
ScheduleDayKind::TimeRanges(vec![
331+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()
332+
..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
333+
NaiveTime::from_hms_opt(14, 0, 0).unwrap()
334+
..=NaiveTime::from_hms_opt(15, 0, 0).unwrap(),
335+
])
311336
);
312337
assert_eq!(
313338
valid2400.parse::<ScheduleDayKind>().unwrap(),
314-
ScheduleDayKind::TimeRange(
315-
NaiveTime::from_hms_opt(12, 34, 0).unwrap(),
316-
MAX_TIME_INSTANT,
317-
)
339+
ScheduleDayKind::TimeRanges(vec![
340+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()..=MAX_TIME_INSTANT
341+
])
318342
);
319343
assert!(invalid.parse::<ScheduleDayKind>().is_err());
320344
assert!(invalid_format.parse::<ScheduleDayKind>().is_err());
@@ -347,10 +371,10 @@ mod tests {
347371
let expected = HolidayDaySchedule {
348372
month: 04,
349373
day: 12,
350-
kind: ScheduleDayKind::TimeRange(
351-
NaiveTime::from_hms_opt(12, 34, 0).unwrap(),
352-
NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
353-
),
374+
kind: ScheduleDayKind::TimeRanges(vec![
375+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()
376+
..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
377+
]),
354378
};
355379
let parsed = input.parse::<HolidayDaySchedule>()?;
356380
assert_eq!(parsed, expected);
@@ -371,14 +395,13 @@ mod tests {
371395
timezone: Tz::America__New_York,
372396
weekly_schedule: vec![
373397
ScheduleDayKind::Open,
374-
ScheduleDayKind::TimeRange(
375-
NaiveTime::from_hms_opt(12, 34, 0).unwrap(),
376-
NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
377-
),
378-
ScheduleDayKind::TimeRange(
379-
NaiveTime::from_hms_opt(09, 30, 0).unwrap(),
380-
MAX_TIME_INSTANT,
381-
),
398+
ScheduleDayKind::TimeRanges(vec![
399+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()
400+
..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
401+
]),
402+
ScheduleDayKind::TimeRanges(vec![
403+
NaiveTime::from_hms_opt(09, 30, 0).unwrap()..=MAX_TIME_INSTANT,
404+
]),
382405
ScheduleDayKind::Closed,
383406
ScheduleDayKind::Closed,
384407
ScheduleDayKind::Closed,
@@ -398,18 +421,17 @@ mod tests {
398421
HolidayDaySchedule {
399422
month: 04,
400423
day: 14,
401-
kind: ScheduleDayKind::TimeRange(
402-
NaiveTime::from_hms_opt(12, 34, 0).unwrap(),
403-
NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
404-
),
424+
kind: ScheduleDayKind::TimeRanges(vec![
425+
NaiveTime::from_hms_opt(12, 34, 0).unwrap()
426+
..=NaiveTime::from_hms_opt(13, 47, 0).unwrap(),
427+
]),
405428
},
406429
HolidayDaySchedule {
407430
month: 12,
408431
day: 30,
409-
kind: ScheduleDayKind::TimeRange(
410-
NaiveTime::from_hms_opt(09, 30, 0).unwrap(),
411-
MAX_TIME_INSTANT,
412-
),
432+
kind: ScheduleDayKind::TimeRanges(vec![
433+
NaiveTime::from_hms_opt(09, 30, 0).unwrap()..=MAX_TIME_INSTANT,
434+
]),
413435
},
414436
],
415437
};
@@ -476,18 +498,24 @@ mod tests {
476498
}
477499

478500
prop_compose! {
479-
fn schedule_day_kind()(
480-
r in any::<u8>(),
501+
fn time_range()(
481502
t1 in any::<u32>(),
482503
t2 in any::<u32>(),
504+
) -> RangeInclusive<NaiveTime> {
505+
NaiveTime::from_hms_opt(t1 % 24, t1 / 24 % 60, 0).unwrap()..=
506+
NaiveTime::from_hms_opt(t2 % 24, t2 / 24 % 60, 0).unwrap()
507+
}
508+
}
509+
510+
prop_compose! {
511+
fn schedule_day_kind()(
512+
r in any::<u8>(),
513+
ranges in proptest::collection::vec(time_range(), 1..3),
483514
) -> ScheduleDayKind {
484515
match r % 3 {
485516
0 => ScheduleDayKind::Open,
486517
1 => ScheduleDayKind::Closed,
487-
_ => ScheduleDayKind::TimeRange(
488-
NaiveTime::from_hms_opt(t1 % 24, t1 / 24 % 60, 0).unwrap(),
489-
NaiveTime::from_hms_opt(t2 % 24, t2 / 24 % 60, 0).unwrap(),
490-
),
518+
_ => ScheduleDayKind::TimeRanges(ranges),
491519
}
492520
}
493521
}

src/agent/solana/oracle.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// This module is responsible for loading the current state of the
22
// on-chain Oracle program accounts from Solana.
3+
#[allow(deprecated)]
34
use {
45
self::subscriber::Subscriber,
56
super::{
@@ -648,6 +649,7 @@ impl Poller {
648649
let product = load_product_account(prod_acc.data.as_slice())
649650
.context(format!("Could not parse product account {}", product_key))?;
650651

652+
#[allow(deprecated)]
651653
let legacy_schedule: LegacySchedule = if let Some((_wsched_key, wsched_val)) =
652654
product.iter().find(|(k, _v)| *k == "weekly_schedule")
653655
{

0 commit comments

Comments
 (0)