use crate::{ config::{Config, ALPACA_CLOCK_API_URL}, types::alpaca, utils::duration_until, }; use backoff::{future::retry, ExponentialBackoff}; use log::info; use std::sync::Arc; use time::OffsetDateTime; use tokio::{sync::mpsc, time::sleep}; pub enum Status { Open, Closed, } pub struct Message { pub status: Status, pub next_switch: OffsetDateTime, } impl From for Message { fn from(clock: alpaca::api::incoming::clock::Clock) -> Self { if clock.is_open { Self { status: Status::Open, next_switch: clock.next_close, } } else { Self { status: Status::Closed, next_switch: clock.next_open, } } } } pub async fn run(app_config: Arc, clock_sender: mpsc::Sender) { loop { let clock = retry(ExponentialBackoff::default(), || async { app_config.alpaca_rate_limit.until_ready().await; app_config .alpaca_client .get(ALPACA_CLOCK_API_URL) .send() .await? .error_for_status() .map_err(backoff::Error::Permanent)? .json::() .await .map_err(backoff::Error::Permanent) }) .await .unwrap(); let sleep_until = duration_until(if clock.is_open { info!("Market is open, will close at {}.", clock.next_close); clock.next_close } else { info!("Market is closed, will reopen at {}.", clock.next_open); clock.next_open }); sleep(sleep_until).await; clock_sender.send(clock.into()).await.unwrap(); } }