1use serde::{Deserialize, Deserializer, Serialize};
4
5use crate::check::CheckId;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct InlinkSample {
10 pub target: u32,
12 pub source: u32,
14 pub anchor: String,
15 pub nofollow: bool,
16}
17
18#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
19pub struct StatusCounts {
20 pub ok: u32,
21 pub redirect: u32,
22 pub client_error: u32,
23 pub server_error: u32,
24 pub failed: u32,
26 pub blocked: u32,
27}
28
29#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
30pub struct CrawlSummary {
31 pub pages: u32,
32 pub indexable: u32,
33 pub status: StatusCounts,
34 pub depth: Vec<u32>,
36 pub no_depth: u32,
38 pub avg_response_ms: u32,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42pub struct CrawlReport {
43 pub health_score: u8,
44 pub checks_passed: u16,
45 pub checks_total: u16,
46 #[serde(deserialize_with = "known_counts")]
50 pub counts: Vec<(CheckId, u32)>,
51 pub inlink_samples: Vec<InlinkSample>,
52 pub summary: CrawlSummary,
53}
54
55fn known_counts<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<(CheckId, u32)>, D::Error> {
57 let raw = Vec::<(String, u32)>::deserialize(d)?;
58 Ok(raw
59 .into_iter()
60 .filter_map(|(slug, n)| Some((CheckId::from_slug(&slug)?, n)))
61 .collect())
62}