This commit is contained in:
2026-05-05 05:03:11 +02:00
parent 3e994995d7
commit f2c227e08f
132 changed files with 5767 additions and 4461 deletions

View File

@@ -29,23 +29,25 @@ impl KbJsonRpcWsRequest {
method: std::string::String,
params: std::vec::Vec<serde_json::Value>,
) -> Self {
Self {
return Self {
jsonrpc: "2.0".to_string(),
id: serde_json::Value::from(id),
method,
params,
}
};
}
/// Converts the request into a JSON value.
pub fn to_value(&self) -> Result<serde_json::Value, crate::KbError> {
let value_result = serde_json::to_value(self);
match value_result {
Ok(value) => Ok(value),
Err(error) => Err(crate::KbError::Json(format!(
"cannot serialize websocket json-rpc request '{}': {error}",
self.method
))),
Ok(value) => return Ok(value),
Err(error) => {
return Err(crate::KbError::Json(format!(
"cannot serialize websocket json-rpc request '{}': {error}",
self.method
)));
},
}
}
@@ -53,11 +55,13 @@ impl KbJsonRpcWsRequest {
pub fn to_json_string(&self) -> Result<std::string::String, crate::KbError> {
let text_result = serde_json::to_string(self);
match text_result {
Ok(text) => Ok(text),
Err(error) => Err(crate::KbError::Json(format!(
"cannot serialize websocket json-rpc request '{}': {error}",
self.method
))),
Ok(text) => return Ok(text),
Err(error) => {
return Err(crate::KbError::Json(format!(
"cannot serialize websocket json-rpc request '{}': {error}",
self.method
)));
},
}
}
}
@@ -130,9 +134,9 @@ impl KbJsonRpcWsIncomingMessage {
/// Returns a short human-readable kind label.
pub fn kind_name(&self) -> &'static str {
match self {
Self::SuccessResponse(_) => "success_response",
Self::ErrorResponse(_) => "error_response",
Self::Notification(_) => "notification",
Self::SuccessResponse(_) => return "success_response",
Self::ErrorResponse(_) => return "error_response",
Self::Notification(_) => return "notification",
}
}
}
@@ -143,7 +147,7 @@ impl KbJsonRpcWsIncomingMessage {
/// trimming left-side whitespace.
pub fn kb_is_probable_json_rpc_object_text(text: &str) -> bool {
let trimmed = text.trim_start();
trimmed.starts_with('{')
return trimmed.starts_with('{');
}
/// Parses a raw text message into a JSON-RPC incoming message.
@@ -160,10 +164,9 @@ pub fn parse_kb_json_rpc_ws_incoming_text(
return Err(crate::KbError::Json(format!(
"cannot parse websocket json-rpc text: {error}"
)));
}
},
};
parse_kb_json_rpc_ws_incoming_value(&value)
return parse_kb_json_rpc_ws_incoming_value(&value);
}
/// Parses a JSON value into a JSON-RPC incoming message.
@@ -179,7 +182,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(
"json-rpc websocket payload must be a JSON object".to_string(),
));
}
},
};
let jsonrpc_value_option = object.get("jsonrpc");
let jsonrpc_value = match jsonrpc_value_option {
@@ -188,7 +191,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(
"json-rpc websocket payload is missing 'jsonrpc'".to_string(),
));
}
},
};
let jsonrpc_string_option = jsonrpc_value.as_str();
let jsonrpc_string = match jsonrpc_string_option {
@@ -197,7 +200,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(
"json-rpc websocket field 'jsonrpc' must be a string".to_string(),
));
}
},
};
if jsonrpc_string != "2.0" {
return Err(crate::KbError::Json(format!(
@@ -218,7 +221,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(format!(
"cannot parse websocket json-rpc notification: {error}"
)));
}
},
};
return Ok(KbJsonRpcWsIncomingMessage::Notification(notification));
}
@@ -230,7 +233,7 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(format!(
"cannot parse websocket json-rpc success response: {error}"
)));
}
},
};
return Ok(KbJsonRpcWsIncomingMessage::SuccessResponse(response));
}
@@ -242,13 +245,11 @@ pub fn parse_kb_json_rpc_ws_incoming_value(
return Err(crate::KbError::Json(format!(
"cannot parse websocket json-rpc error response: {error}"
)));
}
},
};
return Ok(KbJsonRpcWsIncomingMessage::ErrorResponse(response));
}
Err(crate::KbError::Json(
"unsupported websocket json-rpc message shape".to_string(),
))
return Err(crate::KbError::Json("unsupported websocket json-rpc message shape".to_string()));
}
#[cfg(test)]
@@ -260,18 +261,10 @@ mod tests {
"slotSubscribe".to_string(),
std::vec::Vec::new(),
);
let value = request
.to_value()
.expect("request value serialization must succeed");
assert_eq!(
value["jsonrpc"],
serde_json::Value::String("2.0".to_string())
);
let value = request.to_value().expect("request value serialization must succeed");
assert_eq!(value["jsonrpc"], serde_json::Value::String("2.0".to_string()));
assert_eq!(value["id"], serde_json::Value::from(7u64));
assert_eq!(
value["method"],
serde_json::Value::String("slotSubscribe".to_string())
);
assert_eq!(value["method"], serde_json::Value::String("slotSubscribe".to_string()));
assert_eq!(value["params"], serde_json::Value::Array(vec![]));
}
@@ -284,10 +277,10 @@ mod tests {
assert_eq!(response.jsonrpc, "2.0");
assert_eq!(response.result, serde_json::Value::from(42u64));
assert_eq!(response.id, serde_json::Value::from(3u64));
}
},
other => {
panic!("unexpected parsed message: {other:?}");
}
},
}
}
@@ -303,10 +296,10 @@ mod tests {
assert_eq!(response.error.message, "Method not found");
assert_eq!(response.error.data, None);
assert_eq!(response.id, serde_json::Value::from(9u64));
}
},
other => {
panic!("unexpected parsed message: {other:?}");
}
},
}
}
@@ -319,22 +312,17 @@ mod tests {
assert_eq!(notification.jsonrpc, "2.0");
assert_eq!(notification.method, "slotNotification");
assert_eq!(notification.params.subscription, 17);
assert_eq!(
notification.params.result["slot"],
serde_json::Value::from(3u64)
);
}
assert_eq!(notification.params.result["slot"], serde_json::Value::from(3u64));
},
other => {
panic!("unexpected parsed message: {other:?}");
}
},
}
}
#[test]
fn probable_json_rpc_object_text_detects_object() {
assert!(crate::kb_is_probable_json_rpc_object_text(
" {\"jsonrpc\":\"2.0\"}"
));
assert!(crate::kb_is_probable_json_rpc_object_text(" {\"jsonrpc\":\"2.0\"}"));
assert!(!crate::kb_is_probable_json_rpc_object_text("hello"));
}
}