1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! # dig-rpc
//!
//! An axum-based JSON-RPC **server framework** for a DIG node. It serves the
//! canonical [`dig-rpc-protocol`](dig_rpc_protocol) interface over the three DIG
//! transport surfaces and owns everything transport-shaped so a node doesn't
//! have to:
//!
//! - **mTLS** peer surface, **HTTPS** public-read surface, **loopback** control
//! surface — one [`RpcServer`] per surface, over the same handler;
//! - the JSON-RPC 2.0 envelope + the uniform error envelope;
//! - the surface/tier **allowlist boundary** ([`dispatch`](mod@dispatch)) — a
//! control method is unreachable off loopback, a non-allowlisted method is
//! unreachable over the peer surface;
//! - `rpc.discover` served from the generated OpenRPC document;
//! - per-(peer, tier) **rate limiting**;
//! - **graceful shutdown** driven by any future.
//!
//! The node supplies the *semantics* through one small trait,
//! [`RpcHandler`] — so this crate depends ONLY on [`dig_rpc_protocol`], never on a
//! node or service crate. (The previous design's `dig-service` dependency is
//! gone: the shutdown signal is a plain future and dispatch is a trait, not an
//! external `RpcApi`.)
//!
//! ## Architecture
//!
//! ```text
//! POST / (one surface: Loopback | PublicRead | Peer)
//! │
//! ▼ axum handler
//! ┌────────────────────────────────────────────────┐
//! │ rate limit — per (peer, tier) token bucket │
//! │ dispatch — resolve method (dig-rpc-protocol) │
//! │ — surface/tier allowlist boundary │
//! │ — rpc.discover from OpenRPC generator │
//! │ — RpcHandler::handle (node semantics) │
//! │ envelope — JsonRpcResponse { result | error } │
//! └────────────────────────────────────────────────┘
//! ```
//!
//! ## Minimal handler
//!
//! ```
//! use dig_rpc::{RpcHandler};
//! use dig_rpc_protocol::{Method, RpcError, ErrorCode};
//! use serde_json::{json, Value};
//!
//! struct MyNode;
//!
//! #[async_trait::async_trait]
//! impl RpcHandler for MyNode {
//! async fn handle(&self, method: Method, _params: Value) -> Result<Value, RpcError> {
//! match method {
//! Method::Health => Ok(json!({ "status": "ok" })),
//! other => Err(RpcError::of(
//! ErrorCode::MethodNotFound,
//! format!("{} not served", other.name()),
//! )),
//! }
//! }
//! }
//! ```
pub use ;
pub use RpcServerError;
pub use RpcHandler;
pub use ;
pub use ;
pub use ;
// Re-export the wire contract for ergonomic downstream use.
pub use ;