Feature/add node description api (#605)

* Starting to build out node descriptions

* Renamed the mod to node_description instead of descriptor

* Returning results loaded from file

* Taking user input for node describe command

* Readline without new dependencies

* Adding input format hint

* Making sure the node can still start even when the descriptor file isn't there yet

* Adding some additional runtime checks

* Removing -dev from minimum node version

* Removing initial :: on serde

* Fixing comment on the /description endpoint

* Swapped json for toml

* Being a bit more specific with my startup message.

* Cleaning up path building

* Nicer runtime checks

* Put path building inside the file methods
This commit is contained in:
Dave Hrycyszyn
2021-05-19 09:25:11 -04:00
committed by GitHub
parent ea62d01e65
commit 190d3c4972
10 changed files with 149 additions and 10 deletions
+9
View File
@@ -0,0 +1,9 @@
use crate::node::node_description::NodeDescription;
use rocket::State;
use rocket_contrib::json::Json;
/// 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())
}
+3 -2
View File
@@ -1,7 +1,8 @@
use rocket::Request;
pub(crate) mod description;
pub(crate) mod verloc;
use rocket::Request;
#[catch(404)]
pub(crate) fn not_found(req: &Request) -> String {
format!("I couldn't find '{}'. Try something else?", req.uri())
+12 -4
View File
@@ -3,12 +3,14 @@
use crate::config::Config;
use crate::node::http::{
description::description,
not_found,
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::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender};
use crypto::asymmetric::{encryption, identity};
use log::{error, info, warn};
@@ -21,11 +23,13 @@ use version_checker::parse_version;
pub(crate) mod http;
mod listener;
mod metrics;
pub(crate) mod node_description;
pub(crate) mod packet_delayforwarder;
// the MixNode will live for whole duration of this program
pub struct MixNode {
config: Config,
descriptor: NodeDescription,
identity_keypair: Arc<identity::KeyPair>,
sphinx_keypair: Arc<encryption::KeyPair>,
}
@@ -33,31 +37,35 @@ pub struct MixNode {
impl MixNode {
pub fn new(
config: Config,
descriptor: NodeDescription,
identity_keypair: identity::KeyPair,
sphinx_keypair: encryption::KeyPair,
) -> Self {
MixNode {
config,
descriptor,
identity_keypair: Arc::new(identity_keypair),
sphinx_keypair: Arc::new(sphinx_keypair),
}
}
fn start_http_api(&self, atomic_verloc_result: AtomicVerlocResult) {
info!("Starting HTTP API on port 8000...");
info!("Starting HTTP API on http://localhost:8000");
let mut config = rocket::config::Config::release_default();
// bind to the same address as we are using for mixnodes
config.address = self.config.get_listening_address().ip();
let state = VerlocState::new(atomic_verloc_result);
let verloc_state = VerlocState::new(atomic_verloc_result);
let descriptor = self.descriptor.clone();
tokio::spawn(async move {
rocket::build()
.configure(config)
.mount("/", routes![verloc])
.mount("/", routes![verloc, description])
.register("/", catchers![not_found])
.manage(state)
.manage(verloc_state)
.manage(descriptor)
.launch()
.await
});
+46
View File
@@ -0,0 +1,46 @@
use serde::Deserialize;
use serde::Serialize;
use std::path::PathBuf;
use std::{fs, io};
pub(crate) const DESCRIPTION_FILE: &str = "description.toml";
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct NodeDescription {
pub(crate) name: String,
pub(crate) description: String,
pub(crate) link: String,
}
impl Default for NodeDescription {
fn default() -> Self {
NodeDescription {
name: "This node has not yet set a name".to_string(),
description: "This node has not yet set a description".to_string(),
link: "https://nymtech.net".to_string(),
}
}
}
impl NodeDescription {
pub(crate) fn load_from_file(config_path: PathBuf) -> io::Result<NodeDescription> {
let description_file_path: PathBuf = [config_path.to_str().unwrap(), DESCRIPTION_FILE]
.iter()
.collect();
let toml = fs::read_to_string(description_file_path)?;
toml::from_str(&toml).map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
}
pub(crate) fn save_to_file(
description: &NodeDescription,
config_path: PathBuf,
) -> io::Result<()> {
let description_file_path: PathBuf = [config_path.to_str().unwrap(), DESCRIPTION_FILE]
.iter()
.collect();
let description_toml =
toml::to_string(description).expect("could not encode description to toml");
fs::write(description_file_path, description_toml)?;
Ok(())
}
}