1use rmcp::ErrorData;
4use serde_json::{Map, Value, json};
5
6fn obj(m: Map<String, Value>) -> Value {
7 Value::Object(m)
8}
9use void_crawl_core::VoidCrawlError;
10
11pub fn map_err(err: VoidCrawlError) -> ErrorData {
17 match err {
18 VoidCrawlError::ElementNotFound(s)
19 | VoidCrawlError::FrameNotFound(s)
20 | VoidCrawlError::AmbiguousFrame(s)
21 | VoidCrawlError::NavigationFailed(s)
22 | VoidCrawlError::JsEvalError(s) => ErrorData::invalid_params(s, None),
23 VoidCrawlError::Timeout(s) => ErrorData::internal_error(format!("timeout: {s}"), None),
24 VoidCrawlError::BrowserClosed => ErrorData::internal_error("browser closed", None),
25 VoidCrawlError::CaptchaDetected { ref kind } => {
26 let data = tagged("CaptchaDetected", json!({ "kind": kind }));
27 ErrorData::internal_error(err.to_string(), Some(obj(data)))
28 }
29 VoidCrawlError::AntibotChallenge { ref vendor } => {
30 let data = tagged("AntibotChallenge", json!({ "vendor": vendor }));
31 ErrorData::internal_error(err.to_string(), Some(obj(data)))
32 }
33 VoidCrawlError::ProfileBusy { ref name } => {
34 let data = tagged("ProfileBusy", json!({ "name": name }));
35 ErrorData::internal_error(err.to_string(), Some(obj(data)))
36 }
37 VoidCrawlError::ProfileLeaseExpired { ref name, timeout_secs } => {
38 let data = tagged(
39 "ProfileLeaseExpired",
40 json!({ "name": name, "timeout_secs": timeout_secs }),
41 );
42 ErrorData::internal_error(err.to_string(), Some(obj(data)))
43 }
44 VoidCrawlError::ProfileNotFound { ref name, ref searched } => {
45 let data = tagged("ProfileNotFound", json!({ "name": name, "searched": searched }));
46 ErrorData::invalid_params(err.to_string(), Some(obj(data)))
47 }
48 other => ErrorData::internal_error(other.to_string(), None),
49 }
50}
51
52fn tagged(exception: &str, extra: Value) -> Map<String, Value> {
53 let mut m = Map::new();
54 m.insert("exception".into(), Value::String(exception.into()));
55 if let Value::Object(obj) = extra {
56 for (k, v) in obj {
57 m.insert(k, v);
58 }
59 }
60 m
61}