brainwires_proxy/convert/
detect.rs1use crate::convert::FormatDetector;
4use crate::types::FormatId;
5
6pub struct JsonFieldDetector {
8 format_id: FormatId,
10 fields: Vec<String>,
12}
13
14impl JsonFieldDetector {
15 pub fn new(format_id: FormatId, fields: Vec<String>) -> Self {
16 Self { format_id, fields }
17 }
18}
19
20impl FormatDetector for JsonFieldDetector {
21 fn detect(&self, body: &[u8], content_type: Option<&str>) -> Option<FormatId> {
22 if let Some(ct) = content_type
24 && !ct.contains("json")
25 && !ct.contains("text")
26 {
27 return None;
28 }
29
30 let value: serde_json::Value = serde_json::from_slice(body).ok()?;
32 let obj = value.as_object()?;
33
34 for field in &self.fields {
35 if obj.contains_key(field) {
36 return Some(self.format_id.clone());
37 }
38 }
39
40 None
41 }
42
43 fn name(&self) -> &str {
44 "json_field_detector"
45 }
46}
47
48#[derive(Default)]
50pub struct GenericJsonDetector;
51
52impl FormatDetector for GenericJsonDetector {
53 fn detect(&self, body: &[u8], content_type: Option<&str>) -> Option<FormatId> {
54 if let Some(ct) = content_type
55 && ct.contains("json")
56 {
57 return Some(FormatId::new("json"));
58 }
59
60 if serde_json::from_slice::<serde_json::Value>(body).is_ok() {
62 Some(FormatId::new("json"))
63 } else {
64 None
65 }
66 }
67
68 fn name(&self) -> &str {
69 "generic_json"
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn json_field_detector_matches() {
79 let detector = JsonFieldDetector::new(
80 FormatId::new("openai"),
81 vec!["model".into(), "messages".into()],
82 );
83
84 let body = br#"{"model": "gpt-4", "messages": []}"#;
85 let result = detector.detect(body, Some("application/json"));
86 assert_eq!(result, Some(FormatId::new("openai")));
87 }
88
89 #[test]
90 fn json_field_detector_no_match() {
91 let detector = JsonFieldDetector::new(FormatId::new("openai"), vec!["model".into()]);
92
93 let body = br#"{"data": "something else"}"#;
94 let result = detector.detect(body, Some("application/json"));
95 assert!(result.is_none());
96 }
97
98 #[test]
99 fn json_field_detector_rejects_non_json_content_type() {
100 let detector = JsonFieldDetector::new(FormatId::new("openai"), vec!["model".into()]);
101
102 let body = br#"{"model": "gpt-4"}"#;
103 let result = detector.detect(body, Some("application/xml"));
104 assert!(result.is_none());
105 }
106
107 #[test]
108 fn json_field_detector_invalid_json() {
109 let detector = JsonFieldDetector::new(FormatId::new("test"), vec!["key".into()]);
110
111 let body = b"not json at all";
112 let result = detector.detect(body, Some("application/json"));
113 assert!(result.is_none());
114 }
115
116 #[test]
117 fn generic_json_detector_by_content_type() {
118 let detector = GenericJsonDetector;
119 let body = b"not valid json";
120 let result = detector.detect(body, Some("application/json"));
121 assert_eq!(result, Some(FormatId::new("json")));
122 }
123
124 #[test]
125 fn generic_json_detector_by_parsing() {
126 let detector = GenericJsonDetector;
127 let body = br#"{"key": "value"}"#;
128 let result = detector.detect(body, None);
129 assert_eq!(result, Some(FormatId::new("json")));
130 }
131
132 #[test]
133 fn generic_json_detector_no_match() {
134 let detector = GenericJsonDetector;
135 let body = b"plain text";
136 let result = detector.detect(body, Some("text/plain"));
137 assert!(result.is_none());
138 }
139}