1use crate::shared::{specify_request, AnswerStatus, Date, OutputFormat, Part, RequestType};
9use crate::{
10 cache::Cacher,
11 configuration::Configuration,
12 errors::{CommandErrorKind, Error, ErrorKind},
13 html_parsing, url,
14};
15use reqwest::blocking;
16
17pub fn get_input_for_date<T: Cacher<String>>(
19 cacher: T,
20 client: blocking::Client,
21 date: Date,
22) -> Result<String, Error> {
23 let request_spec = specify_request(&date, RequestType::GetInput);
24
25 if let Some(cached_result) = cacher.lookup(&request_spec) {
26 return Ok(cached_result);
27 }
28
29 let response = request_from_url(client, url::build_input_url(&date))?;
30
31 if response.status() == reqwest::StatusCode::NOT_FOUND {
32 return Err(Error::new(ErrorKind::Command {
33 kind: CommandErrorKind::MissingDate(date),
34 }));
35 }
36 let result = response.text()?;
37
38 cacher.overwrite(&request_spec, &result);
39
40 Ok(result)
41}
42
43fn request_from_url(client: blocking::Client, url: String) -> Result<blocking::Response, Error> {
44 let request = client.get(url);
45 let response = request.send()?;
46 Ok(response)
47}
48
49pub fn submit_solution_for_date<T: Cacher<String>>(
51 cacher: T,
52 client: blocking::Client,
53 date: Date,
54 solution: &String,
55) -> Result<AnswerStatus, Error> {
56 let request_spec = specify_request(&date, RequestType::PostAnswer);
57 if let Some(cached_result) = cacher.lookup(&request_spec) {
58 let mut cached_previous_answer_attempts = cached_result.lines();
59 if cached_previous_answer_attempts.any(|attempt| attempt == solution) {
60 return Ok(AnswerStatus::Repeated);
61 }
62 }
63
64 let form_params =
65 std::collections::hash_map::HashMap::from([("answer", solution.as_str()), ("level", "1")]);
66 let request = client.post(url::build_answer_url(&date)).form(&form_params);
67 let response = request.send()?;
68 if response.status() == reqwest::StatusCode::NOT_FOUND {
69 return Err(Error::new(ErrorKind::Command {
70 kind: CommandErrorKind::MissingDate(date),
71 }));
72 }
73 let response_text = response.text()?;
74 let result = html_parsing::parse_answer_state_from_response_text(&response_text)?;
75 if let AnswerStatus::Correctness(_) = result {
76 cacher.append(&request_spec, solution);
77 }
78 Ok(result)
79}
80
81pub fn get_status_for_date<T: Cacher<String>>(
83 cacher: T,
84 client: blocking::Client,
85 date: Date,
86) -> Result<String, Error> {
87 let request_spec = specify_request(&date, RequestType::GetStars);
88 if let Some(cached_result) = cacher.lookup(&request_spec) {
89 return Ok(cached_result);
90 }
91
92 let response = request_from_url(client, url::build_year_url(&date))?;
93
94 let star_count: u8 = html_parsing::parse_star_count_from_response(response.text()?, date.day)?;
95 let result = star_count.to_string();
96 cacher.overwrite(&request_spec, &result);
97 Ok(result)
98}
99
100pub fn get_description_for_date<T: Cacher<String>>(
102 cacher: T,
103 client: blocking::Client,
104 date: Date,
105 part: Part,
106 output_format: OutputFormat,
107) -> Result<String, Error> {
108 let request_spec = specify_request(&date, RequestType::GetDescription(Part::Both));
109 if let Some(cached_result) = cacher.lookup(&request_spec) {
110 return Ok(cached_result);
111 }
112
113 let response = request_from_url(client, url::build_day_url(&date))?;
114 if response.status() == reqwest::StatusCode::NOT_FOUND {
115 return Err(Error::new(ErrorKind::Command {
116 kind: CommandErrorKind::MissingDate(date),
117 }));
118 }
119 let response_body = response.text()?;
120
121 let day_descriptions = html_parsing::parse_day_description_from_html(&response_body)?;
122 let selected_day_descriptions =
123 html_parsing::select_descriptions_via_part(&day_descriptions, part)?;
124 let converted_descriptions = match output_format {
125 OutputFormat::Html => html_parsing::convert_to_html_descriptions(selected_day_descriptions),
126 OutputFormat::Markdown => {
127 html_parsing::convert_to_markdown_descriptions(selected_day_descriptions)
128 }
129 }?;
130 let result = converted_descriptions.join("\n");
131 cacher.overwrite(&request_spec, &result);
132 Ok(result)
133}
134
135pub fn output_config(config: &Configuration) -> Result<String, Error> {
137 Ok(format!("{:?}", config))
138}