1use crate::cookie::Cookie;
2use serde::Deserialize;
3use std::time::{Duration, SystemTime};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum SolutionSource {
8 Fresh,
10 Cached { age: Duration },
12}
13
14impl SolutionSource {
15 pub fn is_cached(&self) -> bool {
16 matches!(self, SolutionSource::Cached { .. })
17 }
18}
19
20#[derive(Debug, Clone)]
23pub struct Solution {
24 pub url: String,
25 pub status: u16,
26 pub cookies: Vec<Cookie>,
27 pub user_agent: String,
28 pub response: Option<String>,
30 pub solved_at: SystemTime,
31 pub source: SolutionSource,
32}
33
34impl Solution {
35 pub fn cookie_header(&self) -> String {
37 self.cookies
38 .iter()
39 .map(|c| format!("{}={}", c.name, c.value))
40 .collect::<Vec<_>>()
41 .join("; ")
42 }
43
44 pub fn html(&self) -> &str {
46 self.response.as_deref().unwrap_or("")
47 }
48
49 pub(crate) fn from_wire(s: WireSolution) -> Self {
50 Self {
51 url: s.url,
52 status: s.status,
53 cookies: s.cookies,
54 user_agent: s.user_agent,
55 response: Some(s.response),
56 solved_at: SystemTime::now(),
57 source: SolutionSource::Fresh,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Deserialize)]
64pub(crate) struct WireSolution {
65 pub url: String,
66 pub status: u16,
67 pub cookies: Vec<Cookie>,
68 #[serde(rename = "userAgent")]
69 pub user_agent: String,
70 pub response: String,
71}
72
73#[derive(Debug, Deserialize)]
75pub(crate) struct ApiResponse {
76 pub status: String,
77 #[serde(default)]
78 pub message: String,
79 pub solution: Option<WireSolution>,
80 #[serde(default)]
82 pub session: Option<String>,
83}