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