[mixnode] replace rocket with axum (#4071)

* axum-equivalent mixnode http api routes

* replaced all rocket routes with axum equivalents

* removed '_axum' suffix from the routes
This commit is contained in:
Jędrzej Stuczyński
2023-10-30 12:55:42 +00:00
committed by GitHub
parent a209b87a41
commit da9d743f39
20 changed files with 159 additions and 92 deletions
+10 -5
View File
@@ -1,9 +1,14 @@
use crate::node::node_description::NodeDescription;
use rocket::serde::json::Json;
use rocket::State;
use axum::extract::Query;
use nym_node::http::api::{FormattedResponse, OutputParams};
/// Returns a description of the node and why someone might want to delegate stake to it.
#[get("/description")]
pub(crate) fn description(description: &State<NodeDescription>) -> Json<NodeDescription> {
Json(description.inner().clone())
pub(crate) async fn description(
description: NodeDescription,
Query(output): Query<OutputParams>,
) -> MixnodeDescriptionResponse {
let output = output.output.unwrap_or_default();
output.to_response(description)
}
pub type MixnodeDescriptionResponse = FormattedResponse<NodeDescription>;
+9 -7
View File
@@ -1,10 +1,11 @@
use axum::extract::Query;
use cupid::TopologyType;
use rocket::serde::{json::Json, Serialize};
use nym_node::http::api::{FormattedResponse, OutputParams};
use serde::Serialize;
use sysinfo::{System, SystemExt};
#[derive(Serialize, Debug)]
#[serde(crate = "rocket::serde")]
pub(crate) struct Hardware {
pub struct Hardware {
ram: String,
num_cores: usize,
crypto_hardware: Option<CryptoHardware>,
@@ -12,7 +13,6 @@ pub(crate) struct Hardware {
#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize, Debug)]
#[serde(crate = "rocket::serde")]
pub(crate) struct CryptoHardware {
aesni: bool,
avx2: bool,
@@ -24,11 +24,13 @@ pub(crate) struct CryptoHardware {
}
/// Provides hardware information which Nym can use to optimize mixnet speed over time (memory, crypto hardware, CPU, cores, etc).
#[get("/hardware")]
pub(crate) fn hardware() -> Json<Option<Hardware>> {
Json(hardware_info())
pub(crate) async fn hardware(Query(output): Query<OutputParams>) -> MixnodeHardwareResponse {
let output = output.output.unwrap_or_default();
output.to_response(hardware_info())
}
pub type MixnodeHardwareResponse = FormattedResponse<Option<Hardware>>;
/// Gives back a summary report of whatever system hardware info we can get for this platform.
fn hardware_info() -> Option<Hardware> {
let crypto_hardware = hardware_info_from_cupid();
+8 -4
View File
@@ -1,11 +1,15 @@
pub(crate) mod description;
pub(crate) mod hardware;
pub(crate) mod state;
pub(crate) mod stats;
pub(crate) mod verloc;
use rocket::Request;
use axum::http::{StatusCode, Uri};
use axum::response::IntoResponse;
#[catch(404)]
pub(crate) fn not_found(req: &Request<'_>) -> String {
format!("I couldn't find '{}'. Try something else?", req.uri())
pub(crate) async fn not_found(uri: Uri) -> impl IntoResponse {
(
StatusCode::NOT_FOUND,
format!("I couldn't find '{uri}'. Try something else?"),
)
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::node::http::verloc::VerlocState;
use crate::node::node_statistics::SharedNodeStats;
use axum::extract::FromRef;
// this is a temporary thing for the transition period
#[derive(Clone)]
pub(crate) struct MixnodeAppState {
pub(crate) verloc: VerlocState,
pub(crate) stats: SharedNodeStats,
}
impl FromRef<MixnodeAppState> for VerlocState {
fn from_ref(app_state: &MixnodeAppState) -> Self {
app_state.verloc.clone()
}
}
impl FromRef<MixnodeAppState> for SharedNodeStats {
fn from_ref(app_state: &MixnodeAppState) -> Self {
app_state.stats.clone()
}
}
+25 -16
View File
@@ -1,29 +1,38 @@
use crate::node::node_statistics::{NodeStats, NodeStatsSimple, SharedNodeStats};
use rocket::serde::json::Json;
use rocket::State;
use serde::Serialize;
use axum::extract::{Query, State};
use nym_node::http::api::{FormattedResponse, Output};
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
#[serde(untagged)]
pub(crate) enum NodeStatsResponse {
pub enum NodeStatsResponse {
Full(NodeStats),
Simple(NodeStatsSimple),
}
/// Returns a running stats of the node.
#[get("/stats?<debug>")]
pub(crate) async fn stats(
stats: &State<SharedNodeStats>,
debug: Option<bool>,
) -> Json<NodeStatsResponse> {
Query(params): Query<StatsQueryParams>,
State(stats): State<SharedNodeStats>,
) -> MixnodeStatsResponse {
let output = params.output.unwrap_or_default();
let snapshot_data = stats.clone_data().await;
// there's no point in returning the entire hashmap of sending destinations in regular mode
if let Some(debug) = debug {
if debug {
return Json(NodeStatsResponse::Full(snapshot_data));
}
}
Json(NodeStatsResponse::Simple(snapshot_data.simplify()))
let response = if params.debug {
NodeStatsResponse::Full(snapshot_data)
} else {
NodeStatsResponse::Simple(snapshot_data.simplify())
};
output.to_response(response)
}
pub type MixnodeStatsResponse = FormattedResponse<NodeStatsResponse>;
#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
// #[derive(Default, Debug, Serialize, Deserialize, Copy, Clone, IntoParams, ToSchema)]
#[serde(default)]
pub(crate) struct StatsQueryParams {
debug: bool,
pub output: Option<Output>,
}
+11 -6
View File
@@ -1,7 +1,8 @@
use axum::extract::{Query, State};
use nym_mixnode_common::verloc::{AtomicVerlocResult, VerlocResult};
use rocket::serde::json::Json;
use rocket::State;
use nym_node::http::api::{FormattedResponse, OutputParams};
#[derive(Clone)]
pub(crate) struct VerlocState {
shared: AtomicVerlocResult,
}
@@ -16,8 +17,12 @@ impl VerlocState {
/// Provides verifiable location (verloc) measurements for this mixnode - a list of the
/// round-trip times, in milliseconds, for all other mixnodes that this node knows about.
#[get("/verloc")]
pub(crate) async fn verloc(state: &State<VerlocState>) -> Json<VerlocResult> {
// since it's impossible to get a mutable reference to the state, we can't cache any results outside the lock : (
Json(state.shared.clone_data().await)
pub(crate) async fn verloc(
State(verloc): State<VerlocState>,
Query(output): Query<OutputParams>,
) -> MixnodeVerlocResponse {
let output = output.output.unwrap_or_default();
output.to_response(verloc.shared.clone_data().await)
}
pub type MixnodeVerlocResponse = FormattedResponse<VerlocResult>;
@@ -7,6 +7,8 @@ use crate::node::listener::connection_handler::packet_processing::{
use crate::node::packet_delayforwarder::PacketDelayForwardSender;
use crate::node::TaskClient;
use futures::StreamExt;
use log::debug;
use log::{error, info, warn};
use nym_mixnode_common::measure;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::framing::codec::NymCodec;
@@ -16,8 +18,9 @@ use std::net::SocketAddr;
use tokio::net::TcpStream;
use tokio::time::Instant;
use tokio_util::codec::Framed;
#[cfg(feature = "cpucycles")]
use tracing::{error, info, instrument};
use tracing::instrument;
pub(crate) mod packet_processing;
+1 -2
View File
@@ -2,12 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node::listener::connection_handler::ConnectionHandler;
use log::{error, info, warn};
use std::net::SocketAddr;
use std::process;
use tokio::net::TcpListener;
use tokio::task::JoinHandle;
#[cfg(feature = "cpucycles")]
use tracing::error;
use super::TaskClient;
+34 -27
View File
@@ -2,23 +2,26 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use crate::node::http::{
description::description,
hardware::hardware,
not_found,
stats::stats,
verloc::{verloc as verloc_route, VerlocState},
};
use crate::node::http::description::description;
use crate::node::http::hardware::hardware;
use crate::node::http::not_found;
use crate::node::http::state::MixnodeAppState;
use crate::node::http::stats::stats;
use crate::node::http::verloc::{verloc, VerlocState};
use crate::node::listener::connection_handler::packet_processing::PacketProcessor;
use crate::node::listener::connection_handler::ConnectionHandler;
use crate::node::listener::Listener;
use crate::node::node_description::NodeDescription;
use crate::node::node_statistics::SharedNodeStats;
use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender};
use axum::routing::get;
use axum::Router;
use log::{error, info, warn};
use nym_bin_common::output_format::OutputFormat;
use nym_bin_common::version_checker::parse_version;
use nym_crypto::asymmetric::{encryption, identity};
use nym_mixnode_common::verloc::{self, AtomicVerlocResult, VerlocMeasurer};
use nym_node::http::middleware::logging;
use nym_task::{TaskClient, TaskManager};
use rand::seq::SliceRandom;
use rand::thread_rng;
@@ -26,9 +29,6 @@ use std::net::SocketAddr;
use std::process;
use std::sync::Arc;
#[cfg(feature = "cpucycles")]
use tracing::{error, info, warn};
mod http;
mod listener;
pub(crate) mod node_description;
@@ -99,29 +99,36 @@ impl MixNode {
atomic_verloc_result: AtomicVerlocResult,
node_stats_pointer: SharedNodeStats,
) {
info!(
"Starting HTTP API on http://{}:{}",
self.config.mixnode.listening_address, self.config.mixnode.http_api_port
let bind_address = SocketAddr::new(
self.config.mixnode.listening_address,
self.config.mixnode.http_api_port,
);
let mut config = rocket::config::Config::release_default();
info!("Starting HTTP API on http://{bind_address}",);
// bind to the same address as we are using for mixnodes
config.address = self.config.mixnode.listening_address;
config.port = self.config.mixnode.http_api_port;
let state = MixnodeAppState {
verloc: VerlocState::new(atomic_verloc_result),
stats: node_stats_pointer,
};
let verloc_state = VerlocState::new(atomic_verloc_result);
let descriptor = self.descriptor.clone();
let router = Router::new()
.route("/verloc", get(verloc))
.route(
"/description",
get({
let descriptor = self.descriptor.clone();
move |query| description(descriptor, query)
}),
)
.route("/stats", get(stats))
.route("/hardware", get(hardware))
.fallback(not_found)
.layer(axum::middleware::from_fn(logging::logger))
.with_state(state);
tokio::spawn(async move {
rocket::build()
.configure(config)
.mount("/", routes![verloc_route, description, stats, hardware])
.register("/", catchers![not_found])
.manage(verloc_state)
.manage(descriptor)
.manage(node_stats_pointer)
.launch()
axum::Server::bind(&bind_address)
.serve(router.into_make_service_with_connect_info::<SocketAddr>())
.await
});
}
+4 -4
View File
@@ -1,6 +1,8 @@
use super::TaskClient;
use futures::channel::mpsc;
use futures::lock::Mutex;
use futures::StreamExt;
use log::{debug, info, trace};
use serde::Serialize;
use std::collections::HashMap;
use std::ops::DerefMut;
@@ -9,8 +11,6 @@ use std::sync::Arc;
use std::time::{Duration, SystemTime};
use tokio::sync::{RwLock, RwLockReadGuard};
use super::TaskClient;
// convenience aliases
type PacketsMap = HashMap<String, u64>;
type PacketDataReceiver = mpsc::UnboundedReceiver<PacketEvent>;
@@ -80,7 +80,7 @@ impl SharedNodeStats {
}
#[derive(Serialize, Clone)]
pub(crate) struct NodeStats {
pub struct NodeStats {
#[serde(serialize_with = "humantime_serde::serialize")]
update_time: SystemTime,
@@ -126,7 +126,7 @@ impl NodeStats {
}
#[derive(Serialize, Clone)]
pub(crate) struct NodeStatsSimple {
pub struct NodeStatsSimple {
#[serde(serialize_with = "humantime_serde::serialize")]
update_time: SystemTime,