Skip to main content

xdiff_live/config/
xdiff.rs

1use crate::{diff_text, ExtraArgs, RequestProfile};
2use anyhow::{Context, Result};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6use super::{is_default, LoadConfig, ValidateConfig};
7
8#[derive(Debug, Deserialize, Serialize, Clone)]
9pub struct DiffConfig {
10    #[serde(flatten)]
11    // #[serde(flatten)] 属性宏的作用是将嵌套结构体的字段展平,
12    // 即将内部结构体的字段合并到外部结构体中,以便更方便地序列化和反序列化。
13    // 这个属性通常用于处理复杂的嵌套结构体,将它们展平为单层的数据结构,
14    // 从而简化代码和数据格式。
15    pub profiles: HashMap<String, DiffProfile>,
16}
17
18#[derive(Debug, Deserialize, Serialize, Clone)]
19pub struct DiffProfile {
20    pub req1: RequestProfile,
21    pub req2: RequestProfile,
22    #[serde(skip_serializing_if = "is_default", default)]
23    pub res: ResponseProfile,
24}
25
26#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default)]
27pub struct ResponseProfile {
28    #[serde(skip_serializing_if = "Vec::is_empty", default)]
29    pub skip_headers: Vec<String>,
30    #[serde(skip_serializing_if = "Vec::is_empty", default)]
31    pub skip_body: Vec<String>,
32}
33
34impl ResponseProfile {
35    pub fn new(skip_headers: Vec<String>, skip_body: Vec<String>) -> Self {
36        Self {
37            skip_headers,
38            skip_body,
39        }
40    }
41}
42
43impl LoadConfig for DiffConfig {}
44
45impl DiffConfig {
46    pub fn new(profiles: HashMap<String, DiffProfile>) -> Self {
47        Self { 
48            profiles
49        }
50    }
51
52    pub fn get_profile(&self, name: &str) -> Option<&DiffProfile> {
53        self.profiles.get(name)
54    }
55}
56
57impl DiffProfile {
58    pub fn new(req1: RequestProfile, req2: RequestProfile, res: ResponseProfile) -> Self {
59        Self { req1, req2, res }
60    }
61
62    pub async fn diff(&self, args: ExtraArgs) -> Result<String> {
63        let res1 = self.req1.send(&args).await?;
64        let res2 = self.req2.send(&args).await?;
65
66        let text1 = res1.get_text(&self.res).await?;
67        let text2 = res2.get_text(&self.res).await?;
68
69        diff_text(&text1, &text2)
70    }
71}
72
73impl ValidateConfig for DiffConfig {
74    fn validate(&self) -> Result<()> {
75        for (name, profile) in &self.profiles {
76            profile
77                .validate()
78                .context(format!("failed to validate profile: {}", name))?;
79        }
80        Ok(())
81    }
82}
83
84impl ValidateConfig for DiffProfile {
85    fn validate(&self) -> Result<()> {
86        self.req1.validate().context("req1 failed to validate")?;
87        self.req2.validate().context("req2 failed to validate")?;
88        Ok(())
89    }
90}