1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
#![doc = include_str!("../README.md")]
use core::fmt;
use std::fmt::{Debug, Display};
/// The error type for this crate.
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("No session cookie found")]
NoSessionCookieFound,
#[error("Rookie crate error: {0}")]
RookieError(anyhow::Error),
}
/// The result type for this crate.
pub type Result<T> = core::result::Result<T, Error>;
/// Value of the session cookie for Advent of Code.
///
/// For example, this value can be used to get access to the puzzle input.
///
/// # Examples
///
/// ## Debug-print the session cookie value to stdout:
///
/// ```
/// use aoc_session::aoc_session;
///
/// let session_id: String = match aoc_session() {
/// Ok(session) => format!("{session:?}"),
/// Err(e) => panic!("Error: {e}"),
/// };
///
/// assert!(session_id.starts_with("session="));
/// println!("{}", session_id);
/// ```
///
/// ## Convert the session cookie value to a [`String`]:
///
/// ```
/// use aoc_session::aoc_session;
///
/// let session_id: String = match aoc_session() {
/// Ok(session) => session.to_string(),
/// Err(e) => panic!("Error: {e}"),
/// };
///
/// assert!(session_id.len() > 0);
/// assert!(!session_id.starts_with("session="));
/// println!("My session ID: {}", session_id);
/// ```
///
pub struct AocSession(String);
impl AocSession {
#[cfg(test)]
pub fn new(session: impl ToString) -> Self {
let session = session.to_string();
for symbol in session.chars() {
if !('a'..='z').contains(&symbol) && !('0'..='9').contains(&symbol) {
panic!("Session cookie value must be a lowercase string that represents a base-16 number");
}
}
Self(session)
}
}
impl Debug for AocSession {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "session={}", self.0)
}
}
impl Display for AocSession {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
/// Get the session cookie for Advent of Code. Beware that this function works for all browsers
/// supported by [`rookie`] but is slow.
///
/// # Examples
///
/// ## Debug-print the session cookie value to stdout:
///
/// ```
/// use aoc_session::aoc_session;
///
/// let session_id: String = match aoc_session() {
/// Ok(session) => format!("{session:?}"),
/// Err(e) => panic!("Error: {e}"),
/// };
///
/// assert!(session_id.starts_with("session="));
/// println!("{}", session_id);
/// ```
///
/// ## Convert the session cookie value to a [`String`]:
///
/// ```
/// use aoc_session::aoc_session;
///
/// let session_id: String = match aoc_session() {
/// Ok(session) => session.to_string(),
/// Err(e) => panic!("Error: {e}"),
/// };
///
/// assert!(session_id.len() > 0);
/// println!("My session ID: {}", session_id);
/// ```
///
pub fn aoc_session() -> Result<AocSession> {
let domains = Some(vec!["adventofcode.com"]); // set to None to get all
let cookies: Vec<_> = rookie::load(domains).map_err(Error::RookieError)?;
let session = cookies
.into_iter()
.find(|c| c.name == "session")
.ok_or(Error::NoSessionCookieFound)?;
Ok(AocSession(session.value))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn print_session_cookie() {
let session = match aoc_session() {
Ok(session) => session,
Err(e) => panic!(
"Error: {e}.\nIf you haven't logged in to Advent of Code yet, please do so now."
),
};
// session=25a16c7465645f5f286128b604b18e3d5a906611b3eac6740672d5e471a7ab0d3af049fb7363eadb2e07edfe51b600927ddd29b2311ea418ce366e8b9cf98dcc
println!("{:?}", session);
}
#[test]
fn check_debug_format() {
let session = AocSession::new("25a16c7465645f5f286128b604b18e3d5a906611b3eac6740672d5e471a7ab0d3af049fb7363eadb2e07edfe51b600927ddd29b2311ea418ce366e8b9cf98dcc");
assert_eq!(
format!("{:?}", session),
"session=25a16c7465645f5f286128b604b18e3d5a906611b3eac6740672d5e471a7ab0d3af049fb7363eadb2e07edfe51b600927ddd29b2311ea418ce366e8b9cf98dcc"
);
}
#[test]
fn check_to_string() {
let session = AocSession::new("25a16c7465645f5f286128b604b18e3d5a906611b3eac6740672d5e471a7ab0d3af049fb7363eadb2e07edfe51b600927ddd29b2311ea418ce366e8b9cf98dcc");
assert_eq!(
session.to_string(),
"25a16c7465645f5f286128b604b18e3d5a906611b3eac6740672d5e471a7ab0d3af049fb7363eadb2e07edfe51b600927ddd29b2311ea418ce366e8b9cf98dcc"
);
}
}