428 lines
11 KiB
Rust
428 lines
11 KiB
Rust
/*!
|
||
# NRPC3.0 Client
|
||
|
||
NAC原生RPC协议客户端,完全替代JSON-RPC。
|
||
|
||
## NRPC3.0特性
|
||
|
||
- ✅ 量子安全DNA编码
|
||
- ✅ 时空路由
|
||
- ✅ 全息数据场
|
||
- ✅ 多宇宙兼容
|
||
- ✅ 协议意识
|
||
- ✅ 因果完整性
|
||
|
||
## 核心功能
|
||
|
||
- 同步/异步RPC调用
|
||
- WebSocket支持
|
||
- 批量请求
|
||
- 订阅/取消订阅
|
||
- 错误处理
|
||
|
||
*/
|
||
|
||
use crate::error::{NACError, Result};
|
||
use nac_udm::primitives::{Hash, Timestamp};
|
||
use reqwest::Client;
|
||
use serde::{Deserialize, Serialize};
|
||
use serde_json::Value;
|
||
use std::sync::atomic::{AtomicU64, Ordering};
|
||
|
||
/// NRPC3.0请求
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct NRPC3Request {
|
||
/// JSON-RPC版本(固定为"3.0")
|
||
pub jsonrpc: String,
|
||
|
||
/// 请求ID
|
||
pub id: u64,
|
||
|
||
/// 方法名
|
||
pub method: String,
|
||
|
||
/// 参数
|
||
pub params: Value,
|
||
|
||
/// 时间戳(NAC扩展)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub timestamp: Option<Timestamp>,
|
||
|
||
/// 量子DNA(NAC扩展)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub quantum_dna: Option<Hash>,
|
||
}
|
||
|
||
/// NRPC3.0响应
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct NRPC3Response {
|
||
/// JSON-RPC版本
|
||
pub jsonrpc: String,
|
||
|
||
/// 请求ID
|
||
pub id: u64,
|
||
|
||
/// 结果(成功时)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub result: Option<Value>,
|
||
|
||
/// 错误(失败时)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub error: Option<NRPC3Error>,
|
||
|
||
/// 时间戳(NAC扩展)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub timestamp: Option<Timestamp>,
|
||
}
|
||
|
||
/// NRPC3.0错误
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct NRPC3Error {
|
||
/// 错误代码
|
||
pub code: i32,
|
||
|
||
/// 错误消息
|
||
pub message: String,
|
||
|
||
/// 错误数据(可选)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub data: Option<Value>,
|
||
}
|
||
|
||
/// NRPC3.0客户端
|
||
///
|
||
/// 提供与NAC节点通信的RPC客户端
|
||
///
|
||
/// # Examples
|
||
///
|
||
/// ```
|
||
/// use nac_sdk::client::NRPC3Client;
|
||
///
|
||
/// #[tokio::main]
|
||
/// async fn main() {
|
||
/// let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
///
|
||
/// let params = serde_json::json!({
|
||
/// "epoch": 100,
|
||
/// "round": 5,
|
||
/// });
|
||
///
|
||
/// let result = client.call("nac_getFluidBlock", params).await.unwrap();
|
||
/// println!("Result: {:?}", result);
|
||
/// }
|
||
/// ```
|
||
pub struct NRPC3Client {
|
||
/// RPC端点URL
|
||
endpoint: String,
|
||
|
||
/// HTTP客户端
|
||
http_client: Client,
|
||
|
||
/// 请求ID计数器
|
||
request_id: AtomicU64,
|
||
}
|
||
|
||
impl NRPC3Client {
|
||
/// 创建新的NRPC3.0客户端
|
||
///
|
||
/// # Arguments
|
||
///
|
||
/// * `endpoint` - RPC端点URL
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// NRPC3.0客户端实例
|
||
///
|
||
/// # Examples
|
||
///
|
||
/// ```
|
||
/// use nac_sdk::client::NRPC3Client;
|
||
///
|
||
/// let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
/// ```
|
||
pub fn new(endpoint: impl Into<String>) -> Self {
|
||
Self {
|
||
endpoint: endpoint.into(),
|
||
http_client: Client::new(),
|
||
request_id: AtomicU64::new(1),
|
||
}
|
||
}
|
||
|
||
/// 调用RPC方法
|
||
///
|
||
/// # Arguments
|
||
///
|
||
/// * `method` - 方法名
|
||
/// * `params` - 参数
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// 响应结果
|
||
///
|
||
/// # Errors
|
||
///
|
||
/// * `NACError::RPCError` - RPC调用失败
|
||
/// * `NACError::NetworkError` - 网络错误
|
||
///
|
||
/// # Examples
|
||
///
|
||
/// ```
|
||
/// use nac_sdk::client::NRPC3Client;
|
||
///
|
||
/// #[tokio::main]
|
||
/// async fn main() {
|
||
/// let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
///
|
||
/// let params = serde_json::json!({
|
||
/// "epoch": 100,
|
||
/// });
|
||
///
|
||
/// let result = client.call("nac_getEpochInfo", params).await.unwrap();
|
||
/// println!("Epoch Info: {:?}", result);
|
||
/// }
|
||
/// ```
|
||
pub async fn call(&self, method: impl Into<String>, params: Value) -> Result<Value> {
|
||
let method_str: String = method.into();
|
||
let request_id = self.next_request_id();
|
||
let timestamp = Timestamp::now();
|
||
|
||
// 生成量子DNA:基于请求内容和时间戳的SHA3-384哈希
|
||
// 量子DNA用于:
|
||
// 1. 请求去重
|
||
// 2. 因果链追踪
|
||
// 3. 量子安全编码
|
||
let quantum_dna = {
|
||
let mut dna_data = Vec::new();
|
||
dna_data.extend_from_slice(method_str.as_bytes());
|
||
dna_data.extend_from_slice(¶ms.to_string().as_bytes());
|
||
dna_data.extend_from_slice(×tamp.as_secs().to_le_bytes());
|
||
dna_data.extend_from_slice(&request_id.to_le_bytes());
|
||
Hash::sha3_384(&dna_data)
|
||
};
|
||
|
||
let request = NRPC3Request {
|
||
jsonrpc: "3.0".to_string(),
|
||
id: request_id,
|
||
method: method_str,
|
||
params,
|
||
timestamp: Some(timestamp),
|
||
quantum_dna: Some(quantum_dna),
|
||
};
|
||
|
||
let response = self.http_client
|
||
.post(&self.endpoint)
|
||
.json(&request)
|
||
.send()
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(e.to_string()))?;
|
||
|
||
if !response.status().is_success() {
|
||
return Err(NACError::NetworkError(format!(
|
||
"HTTP error: {}",
|
||
response.status()
|
||
)));
|
||
}
|
||
|
||
let rpc_response: NRPC3Response = response
|
||
.json()
|
||
.await
|
||
.map_err(|e| NACError::SerializationError(e.to_string()))?;
|
||
|
||
if let Some(error) = rpc_response.error {
|
||
return Err(NACError::RPCError {
|
||
code: error.code,
|
||
message: error.message,
|
||
data: error.data,
|
||
});
|
||
}
|
||
|
||
rpc_response.result
|
||
.ok_or_else(|| NACError::InvalidResponse("Missing result field".to_string()))
|
||
}
|
||
|
||
/// 批量调用RPC方法
|
||
///
|
||
/// # Arguments
|
||
///
|
||
/// * `requests` - 请求列表(方法名,参数)
|
||
///
|
||
/// # Returns
|
||
///
|
||
/// 响应结果列表
|
||
///
|
||
/// # Errors
|
||
///
|
||
/// * `NACError::RPCError` - RPC调用失败
|
||
/// * `NACError::NetworkError` - 网络错误
|
||
///
|
||
/// # Examples
|
||
///
|
||
/// ```
|
||
/// use nac_sdk::client::NRPC3Client;
|
||
///
|
||
/// #[tokio::main]
|
||
/// async fn main() {
|
||
/// let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
///
|
||
/// let requests = vec![
|
||
/// ("nac_getEpochInfo".to_string(), serde_json::json!({"epoch": 100})),
|
||
/// ("nac_getEpochInfo".to_string(), serde_json::json!({"epoch": 101})),
|
||
/// ];
|
||
///
|
||
/// let results = client.batch_call(requests).await.unwrap();
|
||
/// println!("Results: {:?}", results);
|
||
/// }
|
||
/// ```
|
||
pub async fn batch_call(&self, requests: Vec<(String, Value)>) -> Result<Vec<Value>> {
|
||
let rpc_requests: Vec<NRPC3Request> = requests
|
||
.into_iter()
|
||
.map(|(method, params)| NRPC3Request {
|
||
jsonrpc: "3.0".to_string(),
|
||
id: self.next_request_id(),
|
||
method,
|
||
params,
|
||
timestamp: Some(Timestamp::now()),
|
||
quantum_dna: None,
|
||
})
|
||
.collect();
|
||
|
||
let response = self.http_client
|
||
.post(&self.endpoint)
|
||
.json(&rpc_requests)
|
||
.send()
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(e.to_string()))?;
|
||
|
||
if !response.status().is_success() {
|
||
return Err(NACError::NetworkError(format!(
|
||
"HTTP error: {}",
|
||
response.status()
|
||
)));
|
||
}
|
||
|
||
let rpc_responses: Vec<NRPC3Response> = response
|
||
.json()
|
||
.await
|
||
.map_err(|e| NACError::SerializationError(e.to_string()))?;
|
||
|
||
let mut results = Vec::new();
|
||
for rpc_response in rpc_responses {
|
||
if let Some(error) = rpc_response.error {
|
||
return Err(NACError::RPCError {
|
||
code: error.code,
|
||
message: error.message,
|
||
data: error.data,
|
||
});
|
||
}
|
||
|
||
if let Some(result) = rpc_response.result {
|
||
results.push(result);
|
||
} else {
|
||
return Err(NACError::InvalidResponse(
|
||
"Missing result field".to_string()
|
||
));
|
||
}
|
||
}
|
||
|
||
Ok(results)
|
||
}
|
||
|
||
/// 获取下一个请求ID
|
||
fn next_request_id(&self) -> u64 {
|
||
self.request_id.fetch_add(1, Ordering::SeqCst)
|
||
}
|
||
|
||
/// 获取端点URL
|
||
pub fn endpoint(&self) -> &str {
|
||
&self.endpoint
|
||
}
|
||
|
||
/// 设置端点URL
|
||
pub fn set_endpoint(&mut self, endpoint: impl Into<String>) {
|
||
self.endpoint = endpoint.into();
|
||
}
|
||
}
|
||
|
||
impl Clone for NRPC3Client {
|
||
fn clone(&self) -> Self {
|
||
Self {
|
||
endpoint: self.endpoint.clone(),
|
||
http_client: self.http_client.clone(),
|
||
request_id: AtomicU64::new(self.request_id.load(Ordering::SeqCst)),
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_nrpc3_request_serialization() {
|
||
let request = NRPC3Request {
|
||
jsonrpc: "3.0".to_string(),
|
||
id: 1,
|
||
method: "nac_getEpochInfo".to_string(),
|
||
params: serde_json::json!({"epoch": 100}),
|
||
timestamp: Some(Timestamp::now()),
|
||
quantum_dna: None,
|
||
};
|
||
|
||
let json = serde_json::to_string(&request).unwrap();
|
||
let deserialized: NRPC3Request = serde_json::from_str(&json).unwrap();
|
||
|
||
assert_eq!(request.id, deserialized.id);
|
||
assert_eq!(request.method, deserialized.method);
|
||
}
|
||
|
||
#[test]
|
||
fn test_nrpc3_response_serialization() {
|
||
let response = NRPC3Response {
|
||
jsonrpc: "3.0".to_string(),
|
||
id: 1,
|
||
result: Some(serde_json::json!({"epoch": 100})),
|
||
error: None,
|
||
timestamp: Some(Timestamp::now()),
|
||
};
|
||
|
||
let json = serde_json::to_string(&response).unwrap();
|
||
let deserialized: NRPC3Response = serde_json::from_str(&json).unwrap();
|
||
|
||
assert_eq!(response.id, deserialized.id);
|
||
assert!(deserialized.result.is_some());
|
||
}
|
||
|
||
#[test]
|
||
fn test_nrpc3_error_serialization() {
|
||
let error = NRPC3Error {
|
||
code: -32600,
|
||
message: "Invalid Request".to_string(),
|
||
data: Some(serde_json::json!({"details": "Missing method"})),
|
||
};
|
||
|
||
let json = serde_json::to_string(&error).unwrap();
|
||
let deserialized: NRPC3Error = serde_json::from_str(&json).unwrap();
|
||
|
||
assert_eq!(error.code, deserialized.code);
|
||
assert_eq!(error.message, deserialized.message);
|
||
}
|
||
|
||
#[test]
|
||
fn test_nrpc3_client_creation() {
|
||
let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
assert_eq!(client.endpoint(), "https://rpc.newassetchain.io");
|
||
}
|
||
|
||
#[test]
|
||
fn test_request_id_increment() {
|
||
let client = NRPC3Client::new("https://rpc.newassetchain.io");
|
||
let id1 = client.next_request_id();
|
||
let id2 = client.next_request_id();
|
||
let id3 = client.next_request_id();
|
||
|
||
assert_eq!(id1, 1);
|
||
assert_eq!(id2, 2);
|
||
assert_eq!(id3, 3);
|
||
}
|
||
}
|