Skip to content

Commit eaf98fa

Browse files
author
BiomeOS Developer
committed
biomeos: centralized extract_rpc_error() — wetSpring V123 / healthSpring V30 pattern
Extracted structured (code, message) RPC error parsing into a single extract_rpc_error() function. Handles standard JSON-RPC error objects and bare string errors. parse_rpc_response() and response_has_error() now delegate to it, eliminating duplicated extraction logic. +4 tests (standard, bare string, absent error, method-not-found code). 916+ tests total. Made-with: Cursor
1 parent 7c10301 commit eaf98fa

1 file changed

Lines changed: 56 additions & 12 deletions

File tree

crates/groundspring/src/biomeos/protocol.rs

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,32 @@ pub(super) fn build_request(method: &str, params: &Value) -> String {
1818
.to_string()
1919
}
2020

21+
/// Extract structured error from a JSON-RPC 2.0 response.
22+
///
23+
/// Returns `Some((code, message))` if the response contains an `error` field,
24+
/// `None` if no error is present. Handles both standard JSON-RPC error objects
25+
/// (`{"code": -32600, "message": "..."}`) and bare string errors.
26+
///
27+
/// Pattern source: wetSpring V123 / healthSpring V30 centralized RPC error extraction.
28+
pub(super) fn extract_rpc_error(v: &Value) -> Option<(i64, String)> {
29+
let error = v.get("error")?;
30+
let code = error.get("code").and_then(Value::as_i64).unwrap_or(-32000);
31+
let message = error
32+
.get("message")
33+
.and_then(Value::as_str)
34+
.map(String::from)
35+
.or_else(|| error.as_str().map(String::from))
36+
.unwrap_or_else(|| "unknown RPC error".to_string());
37+
Some((code, message))
38+
}
39+
2140
/// Parse a JSON-RPC 2.0 response, extracting the result or error.
2241
pub(super) fn parse_rpc_response(response: &str) -> Result<String> {
2342
let v: Value = serde_json::from_str(response)
2443
.map_err(|e| BiomeOsError::Protocol(format!("invalid JSON-RPC response: {e}")))?;
2544

26-
if let Some(error) = v.get("error") {
27-
let msg = error
28-
.get("message")
29-
.and_then(Value::as_str)
30-
.unwrap_or("unknown RPC error");
31-
return Err(BiomeOsError::Protocol(msg.to_string()));
45+
if let Some((_code, message)) = extract_rpc_error(&v) {
46+
return Err(BiomeOsError::Protocol(message));
3247
}
3348

3449
match v.get("result") {
@@ -45,12 +60,8 @@ pub(super) fn response_has_error(response: &str) -> Result<()> {
4560
let v: Value = serde_json::from_str(response)
4661
.map_err(|e| BiomeOsError::Protocol(format!("invalid JSON-RPC response: {e}")))?;
4762

48-
if let Some(error) = v.get("error") {
49-
let msg = error
50-
.get("message")
51-
.and_then(Value::as_str)
52-
.unwrap_or("unknown RPC error");
53-
return Err(BiomeOsError::Protocol(msg.to_string()));
63+
if let Some((_code, message)) = extract_rpc_error(&v) {
64+
return Err(BiomeOsError::Protocol(message));
5465
}
5566

5667
Ok(())
@@ -120,4 +131,37 @@ mod tests {
120131
let resp = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"bad"},"id":1}"#;
121132
assert!(response_has_error(resp).is_err());
122133
}
134+
135+
#[test]
136+
fn extract_rpc_error_standard() {
137+
let v: Value =
138+
serde_json::from_str(r#"{"error":{"code":-32601,"message":"method not found"}}"#)
139+
.unwrap();
140+
let (code, msg) = extract_rpc_error(&v).unwrap();
141+
assert_eq!(code, -32601);
142+
assert_eq!(msg, "method not found");
143+
}
144+
145+
#[test]
146+
fn extract_rpc_error_bare_string() {
147+
let v: Value = serde_json::from_str(r#"{"error":"something went wrong"}"#).unwrap();
148+
let (code, msg) = extract_rpc_error(&v).unwrap();
149+
assert_eq!(code, -32000);
150+
assert_eq!(msg, "something went wrong");
151+
}
152+
153+
#[test]
154+
fn extract_rpc_error_none_when_no_error() {
155+
let v: Value = serde_json::from_str(r#"{"result":"ok"}"#).unwrap();
156+
assert!(extract_rpc_error(&v).is_none());
157+
}
158+
159+
#[test]
160+
fn extract_rpc_error_is_method_not_found() {
161+
let v: Value =
162+
serde_json::from_str(r#"{"error":{"code":-32601,"message":"method not found"}}"#)
163+
.unwrap();
164+
let (code, _) = extract_rpc_error(&v).unwrap();
165+
assert_eq!(code, -32601);
166+
}
123167
}

0 commit comments

Comments
 (0)