bddap_aoc/
api.rs

1use chrono::{DateTime, TimeZone, Utc};
2
3pub enum Error {
4    ChallengeNotReady {
5        time_till_ready: std::time::Duration,
6    },
7    Other(anyhow::Error),
8}
9
10impl<E> From<E> for Error
11where
12    E: Into<anyhow::Error>,
13{
14    fn from(e: E) -> Self {
15        Error::Other(e.into())
16    }
17}
18
19/// challenges are released at midnight EST (UTC-5)
20/// get the time this challenge will be released
21fn release_time(year: usize, day: usize) -> DateTime<Utc> {
22    let est = chrono::FixedOffset::west_opt(5 * 60 * 60).unwrap();
23
24    let hour = 0;
25    let minute = 0;
26    let second = 0;
27    est.with_ymd_and_hms(year as i32, 12, day as u32, hour, minute, second)
28        .unwrap()
29        .into()
30}
31
32pub fn to_approx_std_duration(d: chrono::Duration) -> std::time::Duration {
33    std::time::Duration::from_secs(d.num_seconds().try_into().unwrap_or(0))
34}
35
36pub fn get_input(session_token: &str, year: usize, day: usize) -> Result<String, Error> {
37    let release_time = release_time(year, day);
38    let now = Utc::now();
39    if now < release_time {
40        let time_till_ready = to_approx_std_duration(release_time - now);
41        return Err(Error::ChallengeNotReady { time_till_ready });
42    }
43
44    let input = reqwest::blocking::Client::new()
45        .get(format!(
46            "https://adventofcode.com/{}/day/{}/input",
47            year, day
48        ))
49        .header("Cookie", format!("session={}", session_token))
50        .header(
51            // https://www.reddit.com/r/adventofcode/comments/z9dhtd/please_include_your_contact_info_in_the_useragent/
52            "User-Agent",
53            "github.com/bddap/bddap-aoc by andrew@dirksen.com",
54        )
55        .send()?
56        .error_for_status()?
57        .text()?;
58    Ok(input)
59}