mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-11-17 00:07:53 +00:00
traits
This commit is contained in:
parent
ea8f2e681c
commit
73c11a4cdf
15 changed files with 335 additions and 855 deletions
113
Cargo.lock
generated
113
Cargo.lock
generated
|
@ -106,6 +106,61 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"itoa",
|
||||||
|
"matchit",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper 1.0.1",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-core"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustversion",
|
||||||
|
"sync_wrapper 0.1.2",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.73"
|
version = "0.3.73"
|
||||||
|
@ -758,8 +813,12 @@ dependencies = [
|
||||||
name = "cuprate-rpc-interface"
|
name = "cuprate-rpc-interface"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"axum",
|
||||||
"cuprate-epee-encoding",
|
"cuprate-epee-encoding",
|
||||||
|
"cuprate-json-rpc",
|
||||||
|
"cuprate-rpc-types",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tower",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1309,6 +1368,12 @@ version = "1.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545"
|
checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -1321,6 +1386,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
@ -1630,6 +1696,12 @@ version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchit"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
|
@ -1658,6 +1730,12 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
@ -2371,6 +2449,28 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_path_to_error"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_urlencoded"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.8"
|
version = "0.10.8"
|
||||||
|
@ -2506,6 +2606,18 @@ dependencies = [
|
||||||
"syn 2.0.66",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synchronoise"
|
name = "synchronoise"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -2733,6 +2845,7 @@ version = "0.1.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
|
|
|
@ -13,7 +13,11 @@ default = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
|
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
|
||||||
|
cuprate-json-rpc = { path = "../json-rpc" }
|
||||||
|
cuprate-rpc-types = { path = "../types" }
|
||||||
|
|
||||||
|
axum = { version = "0.7.5" }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
tower = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,89 +1,11 @@
|
||||||
Monero RPC types.
|
|
||||||
|
|
||||||
# What
|
|
||||||
This crate ports the types used in Monero's RPC interface, including:
|
|
||||||
- JSON types
|
|
||||||
- Binary (epee) types
|
|
||||||
- Mixed types
|
|
||||||
- Other commonly used RPC types
|
|
||||||
|
|
||||||
# Modules
|
|
||||||
This crate's types are split in the following manner:
|
|
||||||
|
|
||||||
| Module | Purpose |
|
|
||||||
|--------|---------|
|
|
||||||
| The root module | Miscellaneous items, e.g. constants.
|
|
||||||
| [`json`] | Contains JSON request/response (some mixed with binary) that all share the common `/json_rpc` endpoint. |
|
|
||||||
| [`bin`] | Contains request/response types that are expected to be fully in binary (`cuprate_epee_encoding`) in `monerod` and `cuprated`'s RPC interface. These are called at a custom endpoint instead of `/json_rpc`, e.g. `/get_blocks.bin`. |
|
|
||||||
| [`other`] | Contains request/response types that are JSON, but aren't called at `/json_rpc` (e.g. [`crate::other::GetHeightRequest`]). |
|
|
||||||
| [`misc`] | Contains miscellaneous types, e.g. [`crate::misc::Status`]. Many of types here are found and used in request/response types, for example, [`crate::misc::BlockHeader`] is used in [`crate::json::GetLastBlockHeaderResponse`]. |
|
|
||||||
| [`base`] | Contains base types flattened into many request/response types.
|
|
||||||
|
|
||||||
Each type in `{json,bin,other}` come in pairs and have identical names, but are suffixed with either `Request` or `Response`. e.g. [`GetBlockCountRequest`](crate::json::GetBlockCountRequest) & [`GetBlockCountResponse`](crate::json::GetBlockCountResponse).
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
The documentation for types within `{json,bin,other}` are omitted, as they can be found in [Monero's RPC documentation](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html).
|
|
||||||
|
|
||||||
However, each type will document:
|
|
||||||
- **Definition**: the exact type definition location in `monerod`
|
|
||||||
- **Documentation**: the Monero RPC documentation link
|
|
||||||
- **Request/response**: the other side of this type, either the request or response
|
|
||||||
|
|
||||||
# Naming
|
|
||||||
The naming for types within `{json,bin,other}` follow the following scheme:
|
|
||||||
1. Convert the endpoint or method name into `UpperCamelCase`
|
|
||||||
1. Remove any suffix extension
|
|
||||||
1. Add `Request/Response` suffix
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
| Endpoint/method | Crate location and name |
|
|
||||||
|-----------------|-------------------------|
|
|
||||||
| [`get_block_count`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block_count) | [`json::GetBlockCountRequest`] & [`json::GetBlockCountResponse`]
|
|
||||||
| [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blockbin) | [`bin::GetBlocksRequest`] & [`bin::GetBlocksResponse`]
|
|
||||||
| [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height) | [`other::GetHeightRequest`] & [`other::GetHeightResponse`]
|
|
||||||
|
|
||||||
# Mixed types
|
|
||||||
Note that some types mix JSON & binary together, i.e., the message overall is JSON,
|
|
||||||
however some fields contain binary values inside JSON strings, for example:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"string": "",
|
|
||||||
"float": 30.0,
|
|
||||||
"integer": 30,
|
|
||||||
"binary": "<serialized binary>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`binary` here is (de)serialized as a normal [`String`]. In order to be clear on which fields contain binary data, the struct fields that have them will use [`crate::misc::BinaryString`] instead of [`String`].
|
|
||||||
|
|
||||||
These mixed types are:
|
|
||||||
- [`crate::json::GetTransactionPoolBacklogResponse`]
|
|
||||||
- [`crate::json::GetOutputDistributionResponse`]
|
|
||||||
|
|
||||||
TODO: we need to figure out a type that (de)serializes correctly, `String` errors with `serde_json`
|
|
||||||
|
|
||||||
# Fixed byte containers
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
<!--
|
# What
|
||||||
|
|
||||||
Some fields within requests/responses are containers, but fixed in size.
|
|
||||||
|
|
||||||
For example, [`crate::json::GetBlockTemplateResponse::prev_hash`] is always a 32-byte hash.
|
|
||||||
|
|
||||||
In these cases, stack allocated types like `cuprate_fixed_bytes::StrArray`
|
|
||||||
will be used instead of a more typical [`String`] for optimization reasons.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Feature flags
|
# Feature flags
|
||||||
List of feature flags for `cuprate-rpc-types`.
|
List of feature flags for `cuprate-rpc-interface`.
|
||||||
|
|
||||||
All are enabled by default.
|
All are enabled by default.
|
||||||
|
|
||||||
| Feature flag | Does what |
|
| Feature flag | Does what |
|
||||||
|--------------|-----------|
|
|--------------|-----------|
|
||||||
| `serde` | Implements `serde` on all types
|
|
||||||
| `epee` | Implements `cuprate_epee_encoding` on all types
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Status
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
|
/// TODO
|
||||||
|
pub enum Error {}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,18 +1,69 @@
|
||||||
//! Free functions.
|
//! Free functions.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Serde
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
// These are functions used for conditionally (de)serialization.
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
/// Returns `true` if the input `u` is equal to `0`.
|
use axum::{routing::method_routing::get, Router};
|
||||||
#[inline]
|
use tower::Service;
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)] // serde needs `&`
|
|
||||||
pub(crate) const fn is_zero(u: &u64) -> bool {
|
|
||||||
*u == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` the input `u` is equal to `1`.
|
use crate::{
|
||||||
#[inline]
|
error::Error, request::Request, response::Response, route::json_rpc, rpc_handler::RpcHandler,
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)] // serde needs `&`
|
RpcState,
|
||||||
pub(crate) const fn is_one(u: &u64) -> bool {
|
};
|
||||||
*u == 1
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Router
|
||||||
|
/// TODO
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub fn create_router<H: RpcHandler>() -> Router<H::RpcState> {
|
||||||
|
// List of `monerod` routes:
|
||||||
|
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.h#L97-L189>
|
||||||
|
Router::new()
|
||||||
|
// JSON-RPC route.
|
||||||
|
.route("/json_rpc", get(json_rpc))
|
||||||
|
// Other JSON routes.
|
||||||
|
.route("/get_height", todo!())
|
||||||
|
.route("/getheight", todo!())
|
||||||
|
.route("/get_transactions", todo!())
|
||||||
|
.route("/gettransactions", todo!())
|
||||||
|
.route("/get_alt_blocks_hashes", todo!())
|
||||||
|
.route("/is_key_image_spent", todo!())
|
||||||
|
.route("/send_raw_transaction", todo!())
|
||||||
|
.route("/sendrawtransaction", todo!())
|
||||||
|
.route("/start_mining", todo!())
|
||||||
|
.route("/stop_mining", todo!())
|
||||||
|
.route("/mining_status", todo!())
|
||||||
|
.route("/save_bc", todo!())
|
||||||
|
.route("/get_peer_list", todo!())
|
||||||
|
.route("/get_public_nodes", todo!())
|
||||||
|
.route("/set_log_hash_rate", todo!())
|
||||||
|
.route("/set_log_level", todo!())
|
||||||
|
.route("/set_log_categories", todo!())
|
||||||
|
.route("/get_transaction_pool", todo!())
|
||||||
|
.route("/get_transaction_pool_hashes", todo!())
|
||||||
|
.route("/get_transaction_pool_stats", todo!())
|
||||||
|
.route("/set_bootstrap_daemon", todo!())
|
||||||
|
.route("/stop_daemon", todo!())
|
||||||
|
.route("/get_info", todo!())
|
||||||
|
.route("/getinfo", todo!())
|
||||||
|
.route("/get_net_stats", todo!())
|
||||||
|
.route("/get_limit", todo!())
|
||||||
|
.route("/set_limit", todo!())
|
||||||
|
.route("/out_peers", todo!())
|
||||||
|
.route("/in_peers", todo!())
|
||||||
|
.route("/get_outs", todo!())
|
||||||
|
.route("/update", todo!())
|
||||||
|
.route("/pop_blocks", todo!())
|
||||||
|
// Binary routes.
|
||||||
|
.route("/get_blocks.bin", todo!())
|
||||||
|
.route("/getblocks.bin", todo!())
|
||||||
|
.route("/get_blocks_by_height.bin", todo!())
|
||||||
|
.route("/getblocks_by_height.bin", todo!())
|
||||||
|
.route("/get_hashes.bin", todo!())
|
||||||
|
.route("/gethashes.bin", todo!())
|
||||||
|
.route("/get_o_indexes.bin", todo!())
|
||||||
|
.route("/get_outs.bin", todo!())
|
||||||
|
.route("/get_transaction_pool_hashes.bin", todo!())
|
||||||
|
.route("/get_output_distribution.bin", todo!())
|
||||||
|
// Unknown route.
|
||||||
|
.route("/*", todo!())
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,14 +102,24 @@
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
// TODO: remove me after finishing impl
|
// TODO: remove me after finishing impl
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code, unreachable_code)]
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Mod
|
//---------------------------------------------------------------------------------------------------- Mod
|
||||||
mod constants;
|
mod constants;
|
||||||
mod error;
|
mod error;
|
||||||
mod free;
|
mod free;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod method;
|
||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
mod route;
|
mod route;
|
||||||
mod state;
|
mod rpc_handler;
|
||||||
|
mod rpc_state;
|
||||||
|
|
||||||
|
pub use error::Error;
|
||||||
|
pub use free::create_router;
|
||||||
|
pub use method::Method;
|
||||||
|
pub use request::Request;
|
||||||
|
pub use response::Response;
|
||||||
|
pub use rpc_handler::{ConcreteRpcHandler, RpcHandler};
|
||||||
|
pub use rpc_state::{ConcreteRpcState, RpcState};
|
||||||
|
|
|
@ -1,379 +1,3 @@
|
||||||
//! Macros.
|
//! Macros.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request_and_response
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
/// A template for generating the RPC request and response `struct`s.
|
|
||||||
///
|
|
||||||
/// These `struct`s automatically implement:
|
|
||||||
/// - `Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash`
|
|
||||||
/// - `serde::{Serialize, Deserialize}`
|
|
||||||
/// - `cuprate_epee_encoding::EpeeObject`
|
|
||||||
///
|
|
||||||
/// It's best to see the output of this macro via the documentation
|
|
||||||
/// of the generated structs via `cargo doc`s to see which parts
|
|
||||||
/// generate which docs.
|
|
||||||
///
|
|
||||||
/// See the [`crate::json`] module for example usage.
|
|
||||||
///
|
|
||||||
/// # Macro internals
|
|
||||||
/// This macro uses:
|
|
||||||
/// - [`__define_request`]
|
|
||||||
/// - [`__define_response`]
|
|
||||||
/// - [`__define_request_and_response_doc`]
|
|
||||||
///
|
|
||||||
/// # `__define_request`
|
|
||||||
/// This macro has 2 branches. If the caller provides
|
|
||||||
/// `Request {}`, i.e. no fields, it will generate:
|
|
||||||
/// ```
|
|
||||||
/// pub type Request = ();
|
|
||||||
/// ```
|
|
||||||
/// If they _did_ specify fields, it will generate:
|
|
||||||
/// ```
|
|
||||||
/// pub struct Request {/* fields */}
|
|
||||||
/// ```
|
|
||||||
/// This is because having a bunch of types that are all empty structs
|
|
||||||
/// means they are not compatible and it makes it cumbersome for end-users.
|
|
||||||
/// Really, they semantically are empty types, so `()` is used.
|
|
||||||
///
|
|
||||||
/// # `__define_response`
|
|
||||||
/// This macro has 2 branches. If the caller provides `Response`
|
|
||||||
/// it will generate a normal struct with no additional fields.
|
|
||||||
///
|
|
||||||
/// If the caller provides a base type from [`crate::base`], it will
|
|
||||||
/// flatten that into the request type automatically.
|
|
||||||
///
|
|
||||||
/// E.g. `Response {/*...*/}` and `ResponseBase {/*...*/}`
|
|
||||||
/// would trigger the different branches.
|
|
||||||
macro_rules! define_request_and_response {
|
|
||||||
(
|
|
||||||
// The markdown tag for Monero daemon RPC documentation. Not necessarily the endpoint.
|
|
||||||
$monero_daemon_rpc_doc_link:ident,
|
|
||||||
|
|
||||||
// The commit hash and `$file.$extension` in which this type is defined in
|
|
||||||
// the Monero codebase in the `rpc/` directory, followed by the specific lines.
|
|
||||||
$monero_code_commit:ident =>
|
|
||||||
$monero_code_filename:ident.
|
|
||||||
$monero_code_filename_extension:ident =>
|
|
||||||
$monero_code_line_start:literal..=
|
|
||||||
$monero_code_line_end:literal,
|
|
||||||
|
|
||||||
// The base `struct` name.
|
|
||||||
// Attributes added here will apply to _both_
|
|
||||||
// request and response types.
|
|
||||||
$( #[$type_attr:meta] )*
|
|
||||||
$type_name:ident,
|
|
||||||
|
|
||||||
// The request type (and any doc comments, derives, etc).
|
|
||||||
$( #[$request_type_attr:meta] )*
|
|
||||||
Request {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$request_field_attr:meta] )* // Field attribute.
|
|
||||||
$request_field:ident: $request_field_type:ty // field_name: field type
|
|
||||||
$(as $request_field_type_as:ty)? // (optional) alternative type (de)serialization
|
|
||||||
$(= $request_field_type_default:expr, $request_field_type_default_string:literal)?, // (optional) default value
|
|
||||||
)*
|
|
||||||
},
|
|
||||||
|
|
||||||
// The response type (and any doc comments, derives, etc).
|
|
||||||
$( #[$response_type_attr:meta] )*
|
|
||||||
$response_base_type:ty {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$response_field_attr:meta] )*
|
|
||||||
$response_field:ident: $response_field_type:ty
|
|
||||||
$(as $response_field_type_as:ty)?
|
|
||||||
$(= $response_field_type_default:expr, $response_field_type_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => { paste::paste! {
|
|
||||||
$crate::macros::__define_request! {
|
|
||||||
#[doc = $crate::macros::__define_request_and_response_doc!(
|
|
||||||
"response" => [<$type_name Response>],
|
|
||||||
$monero_daemon_rpc_doc_link,
|
|
||||||
$monero_code_commit,
|
|
||||||
$monero_code_filename,
|
|
||||||
$monero_code_filename_extension,
|
|
||||||
$monero_code_line_start,
|
|
||||||
$monero_code_line_end,
|
|
||||||
)]
|
|
||||||
///
|
|
||||||
$( #[$type_attr] )*
|
|
||||||
///
|
|
||||||
$( #[$request_type_attr] )*
|
|
||||||
[<$type_name Request>] {
|
|
||||||
$(
|
|
||||||
$( #[$request_field_attr] )*
|
|
||||||
$request_field: $request_field_type
|
|
||||||
$(as $request_field_type_as)?
|
|
||||||
$(= $request_field_type_default, $request_field_type_default_string)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$crate::macros::__define_response! {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[doc = $crate::macros::__define_request_and_response_doc!(
|
|
||||||
"request" => [<$type_name Request>],
|
|
||||||
$monero_daemon_rpc_doc_link,
|
|
||||||
$monero_code_commit,
|
|
||||||
$monero_code_filename,
|
|
||||||
$monero_code_filename_extension,
|
|
||||||
$monero_code_line_start,
|
|
||||||
$monero_code_line_end,
|
|
||||||
)]
|
|
||||||
///
|
|
||||||
$( #[$type_attr] )*
|
|
||||||
///
|
|
||||||
$( #[$response_type_attr] )*
|
|
||||||
$response_base_type => [<$type_name Response>] {
|
|
||||||
$(
|
|
||||||
$( #[$response_field_attr] )*
|
|
||||||
$response_field: $response_field_type
|
|
||||||
$(as $response_field_type_as)?
|
|
||||||
$(= $response_field_type_default, $response_field_type_default_string)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
pub(crate) use define_request_and_response;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request
|
|
||||||
/// Define a request type.
|
|
||||||
///
|
|
||||||
/// This is only used in [`define_request_and_response`], see it for docs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_request {
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This branch will generate a type alias to `()` if only given `{}` as input.
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
$t:ident {}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
///
|
|
||||||
/// This request has no inputs.
|
|
||||||
pub type $t = ();
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This branch of the macro expects fields within the `{}`,
|
|
||||||
// and will generate a `struct`
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
$t:ident {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )* // field attributes
|
|
||||||
// field_name: FieldType
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
// The $field_default is an optional extra token that represents
|
|
||||||
// a default value to pass to [`cuprate_epee_encoding::epee_object`],
|
|
||||||
// see it for usage.
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
#[allow(dead_code, missing_docs)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_request;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_response
|
|
||||||
/// Define a response type.
|
|
||||||
///
|
|
||||||
/// This is only used in [`define_request_and_response`], see it for docs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_response {
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This version of the macro expects the literal ident
|
|
||||||
// `Response` => $response_type_name.
|
|
||||||
//
|
|
||||||
// It will create a `struct` that _doesn't_ use a base from [`crate::base`],
|
|
||||||
// for example, [`crate::json::BannedResponse`] doesn't use a base, so it
|
|
||||||
// uses this branch.
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
Response => $t:ident {
|
|
||||||
// And any fields.
|
|
||||||
// See [`__define_request`] for docs, this does the same thing.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )*
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This version of the macro expects a `Request` base type from [`crate::bases`].
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response base type => actual name of the struct
|
|
||||||
$base:ty => $t:ident {
|
|
||||||
// And any fields.
|
|
||||||
// See [`__define_request`] for docs, this does the same thing.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )*
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
|
||||||
pub base: $base,
|
|
||||||
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
!flatten: base: $base,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_response;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request_and_response_doc
|
|
||||||
/// Generate documentation for the types generated
|
|
||||||
/// by the [`__define_request_and_response`] macro.
|
|
||||||
///
|
|
||||||
/// See it for more info on inputs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_request_and_response_doc {
|
|
||||||
(
|
|
||||||
// This labels the last `[request]` or `[response]`
|
|
||||||
// hyperlink in documentation. Input is either:
|
|
||||||
// - "request"
|
|
||||||
// - "response"
|
|
||||||
//
|
|
||||||
// Remember this is linking to the _other_ type,
|
|
||||||
// so if defining a `Request` type, input should
|
|
||||||
// be "response".
|
|
||||||
$request_or_response:literal => $request_or_response_type:ident,
|
|
||||||
|
|
||||||
$monero_daemon_rpc_doc_link:ident,
|
|
||||||
$monero_code_commit:ident,
|
|
||||||
$monero_code_filename:ident,
|
|
||||||
$monero_code_filename_extension:ident,
|
|
||||||
$monero_code_line_start:literal,
|
|
||||||
$monero_code_line_end:literal,
|
|
||||||
) => {
|
|
||||||
concat!(
|
|
||||||
"",
|
|
||||||
"[Definition](",
|
|
||||||
"https://github.com/monero-project/monero/blob/",
|
|
||||||
stringify!($monero_code_commit),
|
|
||||||
"/src/rpc/",
|
|
||||||
stringify!($monero_code_filename),
|
|
||||||
".",
|
|
||||||
stringify!($monero_code_filename_extension),
|
|
||||||
"#L",
|
|
||||||
stringify!($monero_code_line_start),
|
|
||||||
"-L",
|
|
||||||
stringify!($monero_code_line_end),
|
|
||||||
"), [documentation](",
|
|
||||||
"https://www.getmonero.org/resources/developer-guides/daemon-rpc.html",
|
|
||||||
"#",
|
|
||||||
stringify!($monero_daemon_rpc_doc_link),
|
|
||||||
"), [",
|
|
||||||
$request_or_response,
|
|
||||||
"](",
|
|
||||||
stringify!($request_or_response_type),
|
|
||||||
")."
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_request_and_response_doc;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Macro
|
|
||||||
/// Output a string link to `monerod` source code.
|
|
||||||
macro_rules! monero_definition_link {
|
|
||||||
(
|
|
||||||
$commit:ident, // Git commit hash
|
|
||||||
$file_path:literal, // File path within `monerod`'s `src/`, e.g. `rpc/core_rpc_server_commands_defs.h`
|
|
||||||
$start:literal$(..=$end:literal)? // File lines, e.g. `0..=123` or `0`
|
|
||||||
) => {
|
|
||||||
concat!(
|
|
||||||
"[Definition](https://github.com/monero-project/monero/blob/",
|
|
||||||
stringify!($commit),
|
|
||||||
"/src/",
|
|
||||||
$file_path,
|
|
||||||
"#L",
|
|
||||||
stringify!($start),
|
|
||||||
$(
|
|
||||||
"-L",
|
|
||||||
stringify!($end),
|
|
||||||
)?
|
|
||||||
")."
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use monero_definition_link;
|
|
||||||
|
|
31
rpc/interface/src/method.rs
Normal file
31
rpc/interface/src/method.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_rpc_types::json::GetBlockRequest;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
|
/// TODO
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(tag = "method", content = "params")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum Method {
|
||||||
|
/// TODO
|
||||||
|
GetBlock(GetBlockRequest),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Method {
|
||||||
|
/// TODO
|
||||||
|
pub const fn is_restricted(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::GetBlock(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
// use super::*;
|
||||||
|
}
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Status
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
|
/// TODO
|
||||||
|
pub enum Request {}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Status
|
//---------------------------------------------------------------------------------------------------- Status
|
||||||
|
/// TODO
|
||||||
|
pub enum Response {}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -3,8 +3,25 @@
|
||||||
//! All types are originally defined in [`rpc/core_rpc_server_commands_defs.h`](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h).
|
//! All types are originally defined in [`rpc/core_rpc_server_commands_defs.h`](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h).
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use std::{future::Future, sync::Arc};
|
||||||
|
|
||||||
|
use axum::Json;
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::Error, method::Method, request::Request, response::Response, rpc_handler::RpcHandler,
|
||||||
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Struct definitions
|
//---------------------------------------------------------------------------------------------------- Struct definitions
|
||||||
|
/// TODO
|
||||||
|
// pub(crate) async fn json_rpc<H: RpcHandler>(
|
||||||
|
pub(crate) async fn json_rpc(
|
||||||
|
// handler: Arc<H>,
|
||||||
|
Json(request): Json<cuprate_json_rpc::Request<Method>>,
|
||||||
|
) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
// // This generates 2 structs:
|
// // This generates 2 structs:
|
||||||
// //
|
// //
|
||||||
// // - `GetBlockTemplateRequest`
|
// // - `GetBlockTemplateRequest`
|
|
@ -1,5 +1,7 @@
|
||||||
//! TODO
|
//! TODO
|
||||||
|
|
||||||
mod bin;
|
mod bin;
|
||||||
mod json;
|
mod json_rpc;
|
||||||
mod other;
|
mod other;
|
||||||
|
|
||||||
|
pub(crate) use json_rpc::json_rpc;
|
||||||
|
|
49
rpc/interface/src/rpc_handler.rs
Normal file
49
rpc/interface/src/rpc_handler.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
|
use std::{future::Future, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::Error, request::Request, response::Response, rpc_state::ConcreteRpcState, RpcState,
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
|
/// TODO
|
||||||
|
pub trait RpcHandler: Send + Sync + 'static {
|
||||||
|
/// TODO
|
||||||
|
type RpcState: RpcState;
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
type Handler: Send + Sync + 'static + Service<Request>;
|
||||||
|
// where
|
||||||
|
// <Self::Handler as Service<Request>>::Response: Into<Response>,
|
||||||
|
// <Self::Handler as Service<Request>>::Error: Into<Error>,
|
||||||
|
// <Self::Handler as Service<Request>>::Future: Future<Output = Result<Response, Error>>;
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
fn state(&self) -> Self::RpcState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct ConcreteRpcHandler<Handler> {
|
||||||
|
state: ConcreteRpcState,
|
||||||
|
_handler: PhantomData<Handler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H> RpcHandler for ConcreteRpcHandler<H>
|
||||||
|
where
|
||||||
|
H: Send + Sync + 'static + Service<Request>,
|
||||||
|
<H as Service<Request>>::Response: Into<Response>,
|
||||||
|
<H as Service<Request>>::Error: Into<Error>,
|
||||||
|
<H as Service<Request>>::Future: Future<Output = Result<Response, Error>>,
|
||||||
|
{
|
||||||
|
type RpcState = ConcreteRpcState;
|
||||||
|
type Handler = H;
|
||||||
|
|
||||||
|
fn state(&self) -> Self::RpcState {
|
||||||
|
self.state
|
||||||
|
}
|
||||||
|
}
|
30
rpc/interface/src/rpc_state.rs
Normal file
30
rpc/interface/src/rpc_state.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
|
use std::{future::Future, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
|
use crate::{error::Error, request::Request, response::Response};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- TODO
|
||||||
|
/// TODO
|
||||||
|
pub trait RpcState
|
||||||
|
where
|
||||||
|
Self: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
/// TODO
|
||||||
|
fn restricted(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct ConcreteRpcState {
|
||||||
|
restricted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RpcState for ConcreteRpcState {
|
||||||
|
fn restricted(&self) -> bool {
|
||||||
|
self.restricted
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,379 +0,0 @@
|
||||||
//! Macros.
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request_and_response
|
|
||||||
/// A template for generating the RPC request and response `struct`s.
|
|
||||||
///
|
|
||||||
/// These `struct`s automatically implement:
|
|
||||||
/// - `Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash`
|
|
||||||
/// - `serde::{Serialize, Deserialize}`
|
|
||||||
/// - `cuprate_epee_encoding::EpeeObject`
|
|
||||||
///
|
|
||||||
/// It's best to see the output of this macro via the documentation
|
|
||||||
/// of the generated structs via `cargo doc`s to see which parts
|
|
||||||
/// generate which docs.
|
|
||||||
///
|
|
||||||
/// See the [`crate::json`] module for example usage.
|
|
||||||
///
|
|
||||||
/// # Macro internals
|
|
||||||
/// This macro uses:
|
|
||||||
/// - [`__define_request`]
|
|
||||||
/// - [`__define_response`]
|
|
||||||
/// - [`__define_request_and_response_doc`]
|
|
||||||
///
|
|
||||||
/// # `__define_request`
|
|
||||||
/// This macro has 2 branches. If the caller provides
|
|
||||||
/// `Request {}`, i.e. no fields, it will generate:
|
|
||||||
/// ```
|
|
||||||
/// pub type Request = ();
|
|
||||||
/// ```
|
|
||||||
/// If they _did_ specify fields, it will generate:
|
|
||||||
/// ```
|
|
||||||
/// pub struct Request {/* fields */}
|
|
||||||
/// ```
|
|
||||||
/// This is because having a bunch of types that are all empty structs
|
|
||||||
/// means they are not compatible and it makes it cumbersome for end-users.
|
|
||||||
/// Really, they semantically are empty types, so `()` is used.
|
|
||||||
///
|
|
||||||
/// # `__define_response`
|
|
||||||
/// This macro has 2 branches. If the caller provides `Response`
|
|
||||||
/// it will generate a normal struct with no additional fields.
|
|
||||||
///
|
|
||||||
/// If the caller provides a base type from [`crate::base`], it will
|
|
||||||
/// flatten that into the request type automatically.
|
|
||||||
///
|
|
||||||
/// E.g. `Response {/*...*/}` and `ResponseBase {/*...*/}`
|
|
||||||
/// would trigger the different branches.
|
|
||||||
macro_rules! define_request_and_response {
|
|
||||||
(
|
|
||||||
// The markdown tag for Monero daemon RPC documentation. Not necessarily the endpoint.
|
|
||||||
$monero_daemon_rpc_doc_link:ident,
|
|
||||||
|
|
||||||
// The commit hash and `$file.$extension` in which this type is defined in
|
|
||||||
// the Monero codebase in the `rpc/` directory, followed by the specific lines.
|
|
||||||
$monero_code_commit:ident =>
|
|
||||||
$monero_code_filename:ident.
|
|
||||||
$monero_code_filename_extension:ident =>
|
|
||||||
$monero_code_line_start:literal..=
|
|
||||||
$monero_code_line_end:literal,
|
|
||||||
|
|
||||||
// The base `struct` name.
|
|
||||||
// Attributes added here will apply to _both_
|
|
||||||
// request and response types.
|
|
||||||
$( #[$type_attr:meta] )*
|
|
||||||
$type_name:ident,
|
|
||||||
|
|
||||||
// The request type (and any doc comments, derives, etc).
|
|
||||||
$( #[$request_type_attr:meta] )*
|
|
||||||
Request {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$request_field_attr:meta] )* // Field attribute.
|
|
||||||
$request_field:ident: $request_field_type:ty // field_name: field type
|
|
||||||
$(as $request_field_type_as:ty)? // (optional) alternative type (de)serialization
|
|
||||||
$(= $request_field_type_default:expr, $request_field_type_default_string:literal)?, // (optional) default value
|
|
||||||
)*
|
|
||||||
},
|
|
||||||
|
|
||||||
// The response type (and any doc comments, derives, etc).
|
|
||||||
$( #[$response_type_attr:meta] )*
|
|
||||||
$response_base_type:ty {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$response_field_attr:meta] )*
|
|
||||||
$response_field:ident: $response_field_type:ty
|
|
||||||
$(as $response_field_type_as:ty)?
|
|
||||||
$(= $response_field_type_default:expr, $response_field_type_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => { paste::paste! {
|
|
||||||
$crate::macros::__define_request! {
|
|
||||||
#[doc = $crate::macros::__define_request_and_response_doc!(
|
|
||||||
"response" => [<$type_name Response>],
|
|
||||||
$monero_daemon_rpc_doc_link,
|
|
||||||
$monero_code_commit,
|
|
||||||
$monero_code_filename,
|
|
||||||
$monero_code_filename_extension,
|
|
||||||
$monero_code_line_start,
|
|
||||||
$monero_code_line_end,
|
|
||||||
)]
|
|
||||||
///
|
|
||||||
$( #[$type_attr] )*
|
|
||||||
///
|
|
||||||
$( #[$request_type_attr] )*
|
|
||||||
[<$type_name Request>] {
|
|
||||||
$(
|
|
||||||
$( #[$request_field_attr] )*
|
|
||||||
$request_field: $request_field_type
|
|
||||||
$(as $request_field_type_as)?
|
|
||||||
$(= $request_field_type_default, $request_field_type_default_string)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$crate::macros::__define_response! {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
#[doc = $crate::macros::__define_request_and_response_doc!(
|
|
||||||
"request" => [<$type_name Request>],
|
|
||||||
$monero_daemon_rpc_doc_link,
|
|
||||||
$monero_code_commit,
|
|
||||||
$monero_code_filename,
|
|
||||||
$monero_code_filename_extension,
|
|
||||||
$monero_code_line_start,
|
|
||||||
$monero_code_line_end,
|
|
||||||
)]
|
|
||||||
///
|
|
||||||
$( #[$type_attr] )*
|
|
||||||
///
|
|
||||||
$( #[$response_type_attr] )*
|
|
||||||
$response_base_type => [<$type_name Response>] {
|
|
||||||
$(
|
|
||||||
$( #[$response_field_attr] )*
|
|
||||||
$response_field: $response_field_type
|
|
||||||
$(as $response_field_type_as)?
|
|
||||||
$(= $response_field_type_default, $response_field_type_default_string)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
pub(crate) use define_request_and_response;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request
|
|
||||||
/// Define a request type.
|
|
||||||
///
|
|
||||||
/// This is only used in [`define_request_and_response`], see it for docs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_request {
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This branch will generate a type alias to `()` if only given `{}` as input.
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
$t:ident {}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
///
|
|
||||||
/// This request has no inputs.
|
|
||||||
pub type $t = ();
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This branch of the macro expects fields within the `{}`,
|
|
||||||
// and will generate a `struct`
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
$t:ident {
|
|
||||||
// And any fields.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )* // field attributes
|
|
||||||
// field_name: FieldType
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
// The $field_default is an optional extra token that represents
|
|
||||||
// a default value to pass to [`cuprate_epee_encoding::epee_object`],
|
|
||||||
// see it for usage.
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
#[allow(dead_code, missing_docs)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_request;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_response
|
|
||||||
/// Define a response type.
|
|
||||||
///
|
|
||||||
/// This is only used in [`define_request_and_response`], see it for docs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_response {
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This version of the macro expects the literal ident
|
|
||||||
// `Response` => $response_type_name.
|
|
||||||
//
|
|
||||||
// It will create a `struct` that _doesn't_ use a base from [`crate::base`],
|
|
||||||
// for example, [`crate::json::BannedResponse`] doesn't use a base, so it
|
|
||||||
// uses this branch.
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response type.
|
|
||||||
Response => $t:ident {
|
|
||||||
// And any fields.
|
|
||||||
// See [`__define_request`] for docs, this does the same thing.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )*
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// This version of the macro expects a `Request` base type from [`crate::bases`].
|
|
||||||
(
|
|
||||||
// Any doc comments, derives, etc.
|
|
||||||
$( #[$attr:meta] )*
|
|
||||||
// The response base type => actual name of the struct
|
|
||||||
$base:ty => $t:ident {
|
|
||||||
// And any fields.
|
|
||||||
// See [`__define_request`] for docs, this does the same thing.
|
|
||||||
$(
|
|
||||||
$( #[$field_attr:meta] )*
|
|
||||||
$field:ident: $field_type:ty
|
|
||||||
$(as $field_as:ty)?
|
|
||||||
$(= $field_default:expr, $field_default_string:literal)?,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
$( #[$attr] )*
|
|
||||||
pub struct $t {
|
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
|
||||||
pub base: $base,
|
|
||||||
|
|
||||||
$(
|
|
||||||
$( #[$field_attr] )*
|
|
||||||
$(#[cfg_attr(feature = "serde", serde(default = $field_default_string))])?
|
|
||||||
pub $field: $field_type,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "epee")]
|
|
||||||
::cuprate_epee_encoding::epee_object! {
|
|
||||||
$t,
|
|
||||||
$(
|
|
||||||
$field: $field_type
|
|
||||||
$(as $field_as)?
|
|
||||||
$(= $field_default)?,
|
|
||||||
)*
|
|
||||||
!flatten: base: $base,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_response;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- define_request_and_response_doc
|
|
||||||
/// Generate documentation for the types generated
|
|
||||||
/// by the [`__define_request_and_response`] macro.
|
|
||||||
///
|
|
||||||
/// See it for more info on inputs.
|
|
||||||
///
|
|
||||||
/// `__` is used to notate that this shouldn't be called directly.
|
|
||||||
macro_rules! __define_request_and_response_doc {
|
|
||||||
(
|
|
||||||
// This labels the last `[request]` or `[response]`
|
|
||||||
// hyperlink in documentation. Input is either:
|
|
||||||
// - "request"
|
|
||||||
// - "response"
|
|
||||||
//
|
|
||||||
// Remember this is linking to the _other_ type,
|
|
||||||
// so if defining a `Request` type, input should
|
|
||||||
// be "response".
|
|
||||||
$request_or_response:literal => $request_or_response_type:ident,
|
|
||||||
|
|
||||||
$monero_daemon_rpc_doc_link:ident,
|
|
||||||
$monero_code_commit:ident,
|
|
||||||
$monero_code_filename:ident,
|
|
||||||
$monero_code_filename_extension:ident,
|
|
||||||
$monero_code_line_start:literal,
|
|
||||||
$monero_code_line_end:literal,
|
|
||||||
) => {
|
|
||||||
concat!(
|
|
||||||
"",
|
|
||||||
"[Definition](",
|
|
||||||
"https://github.com/monero-project/monero/blob/",
|
|
||||||
stringify!($monero_code_commit),
|
|
||||||
"/src/rpc/",
|
|
||||||
stringify!($monero_code_filename),
|
|
||||||
".",
|
|
||||||
stringify!($monero_code_filename_extension),
|
|
||||||
"#L",
|
|
||||||
stringify!($monero_code_line_start),
|
|
||||||
"-L",
|
|
||||||
stringify!($monero_code_line_end),
|
|
||||||
"), [documentation](",
|
|
||||||
"https://www.getmonero.org/resources/developer-guides/daemon-rpc.html",
|
|
||||||
"#",
|
|
||||||
stringify!($monero_daemon_rpc_doc_link),
|
|
||||||
"), [",
|
|
||||||
$request_or_response,
|
|
||||||
"](",
|
|
||||||
stringify!($request_or_response_type),
|
|
||||||
")."
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use __define_request_and_response_doc;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Macro
|
|
||||||
/// Output a string link to `monerod` source code.
|
|
||||||
macro_rules! monero_definition_link {
|
|
||||||
(
|
|
||||||
$commit:ident, // Git commit hash
|
|
||||||
$file_path:literal, // File path within `monerod`'s `src/`, e.g. `rpc/core_rpc_server_commands_defs.h`
|
|
||||||
$start:literal$(..=$end:literal)? // File lines, e.g. `0..=123` or `0`
|
|
||||||
) => {
|
|
||||||
concat!(
|
|
||||||
"[Definition](https://github.com/monero-project/monero/blob/",
|
|
||||||
stringify!($commit),
|
|
||||||
"/src/",
|
|
||||||
$file_path,
|
|
||||||
"#L",
|
|
||||||
stringify!($start),
|
|
||||||
$(
|
|
||||||
"-L",
|
|
||||||
stringify!($end),
|
|
||||||
)?
|
|
||||||
")."
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use monero_definition_link;
|
|
Loading…
Reference in a new issue