use serde_json::{json, Value};
use crate::error::ErrorCode;
use crate::method::Method;
pub const OPENRPC_VERSION: &str = "1.2.6";
pub fn openrpc_document(version: &str) -> Value {
json!({
"openrpc": OPENRPC_VERSION,
"info": {
"title": "DIG Node RPC",
"version": version,
"description":
"The canonical DIG-node JSON-RPC surface: content reads, peer \
discovery + range serving, and loopback control. Tiers and \
error codes are defined by the dig-rpc-types crate.",
},
"methods": Method::ALL.iter().map(|m| method_object(*m)).collect::<Vec<_>>(),
"components": {
"x-dig-errors": ErrorCode::ALL.iter().map(|c| json!({
"machineCode": c.machine_code(),
"code": c.code(),
"message": c.default_message(),
"origin": c.default_origin(),
})).collect::<Vec<_>>(),
},
"x-dig-peer-allowlist": Method::peer_reachable_names(),
})
}
fn method_object(m: Method) -> Value {
json!({
"name": m.name(),
"summary": m.summary(),
"params": [],
"result": {
"name": "result",
"schema": { "type": "object" },
},
"x-dig-tier": m.tier().as_str(),
"x-dig-peer-reachable": m.is_peer_reachable(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn document_header() {
let doc = openrpc_document("9.9.9");
assert_eq!(doc["openrpc"], "1.2.6");
assert_eq!(doc["info"]["version"], "9.9.9");
}
#[test]
fn all_methods_present_with_extensions() {
let doc = openrpc_document("1.0.0");
let methods = doc["methods"].as_array().unwrap();
assert_eq!(methods.len(), Method::ALL.len());
for m in Method::ALL {
let obj = methods
.iter()
.find(|o| o["name"] == m.name())
.unwrap_or_else(|| panic!("missing method {}", m.name()));
assert_eq!(obj["x-dig-tier"], m.tier().as_str());
assert_eq!(obj["x-dig-peer-reachable"], m.is_peer_reachable());
}
}
#[test]
fn error_catalogue_complete() {
let doc = openrpc_document("1.0.0");
let errors = doc["components"]["x-dig-errors"].as_array().unwrap();
assert_eq!(errors.len(), ErrorCode::ALL.len());
assert!(errors
.iter()
.any(|e| e["code"] == -32020 && e["machineCode"] == "ONION_CIRCUIT_UNAVAILABLE"));
assert!(errors
.iter()
.any(|e| e["code"] == -32030 && e["machineCode"] == "UNAUTHORIZED"));
}
#[test]
fn peer_allowlist_extension() {
let doc = openrpc_document("1.0.0");
let allow = doc["x-dig-peer-allowlist"].as_array().unwrap();
assert_eq!(allow.len(), Method::peer_reachable_names().len());
assert!(allow.iter().any(|n| n == "dig.getContent"));
assert!(!allow.iter().any(|n| n == "cache.clear"));
}
}