From 886ad9c1a60c0910a814929a4831b1209fdc89e6 Mon Sep 17 00:00:00 2001 From: fluo10 Date: Mon, 2 Jun 2025 12:02:04 +0900 Subject: [PATCH] Implement server and node ping command --- lazy-supplements/src/cli/config.rs | 30 ++++++++++++ lazy-supplements/src/cli/mod.rs | 4 ++ lazy-supplements/src/cli/node.rs | 36 +++++--------- lazy-supplements/src/cli/server.rs | 26 ++++++++++ lazy-supplements/src/config/mod.rs | 39 --------------- lazy-supplements/src/config/node.rs | 75 +++++++++++++++++++++-------- lazy-supplements/src/global/mod.rs | 13 ++++- lazy-supplements/src/main.rs | 4 +- 8 files changed, 140 insertions(+), 87 deletions(-) create mode 100644 lazy-supplements/src/cli/config.rs create mode 100644 lazy-supplements/src/cli/server.rs diff --git a/lazy-supplements/src/cli/config.rs b/lazy-supplements/src/cli/config.rs new file mode 100644 index 0000000..c165eb9 --- /dev/null +++ b/lazy-supplements/src/cli/config.rs @@ -0,0 +1,30 @@ +use std::path::PathBuf; + +use clap::Args; +use libp2p::identity; + +use crate::{config::{NodeConfig, RawNodeConfig}, error::Error, global::{DEFAULT_CONFIG_FILE_PATH, DEFAULT_RAW_NODE_CONFIG}}; + +#[derive(Args, Clone, Debug)] +pub struct ConfigArgs { + #[arg(long)] + pub config: Option, + #[command(flatten)] + pub node_config: RawNodeConfig, +} + +impl ConfigArgs { + pub fn get_config_path_or_default(&self) -> PathBuf { + if let Some(x) = self.config.as_ref() { + x.clone() + } else { + DEFAULT_CONFIG_FILE_PATH.to_path_buf() + } + } + pub async fn try_into_raw_node_config(self) -> Result { + Ok(RawNodeConfig::read_from(self.get_config_path_or_default()).await? + self.node_config) + } + pub async fn try_into_node_config(self) -> Result { + Ok((DEFAULT_RAW_NODE_CONFIG.clone() + self.try_into_raw_node_config().await?).try_into()?) + } +} \ No newline at end of file diff --git a/lazy-supplements/src/cli/mod.rs b/lazy-supplements/src/cli/mod.rs index e13fdab..130b3e6 100644 --- a/lazy-supplements/src/cli/mod.rs +++ b/lazy-supplements/src/cli/mod.rs @@ -1,7 +1,11 @@ use std::path::PathBuf; +mod config; mod init; mod node; +mod server; +pub use config::ConfigArgs; pub use init::InitArgs; pub use node::{ NodeArgs, NodeCommand, JoinNodeArgs }; +pub use server::ServerArgs; \ No newline at end of file diff --git a/lazy-supplements/src/cli/node.rs b/lazy-supplements/src/cli/node.rs index 5b526d3..3529b91 100644 --- a/lazy-supplements/src/cli/node.rs +++ b/lazy-supplements/src/cli/node.rs @@ -7,7 +7,9 @@ use libp2p::{ }; use tracing_subscriber::EnvFilter; -use crate::error::Error; +use crate::{cli::ServerArgs, error::Error}; + +use super::ConfigArgs; #[derive(Args, Debug)] pub struct NodeArgs { @@ -18,13 +20,13 @@ pub struct NodeArgs { #[derive(Args, Debug)] pub struct JoinNodeArgs { #[arg(long)] - pub endpoint: IpAddr, + pub peer_ip: IpAddr, #[arg(long)] - pub port: u16, - #[arg(long)] - pub peer_id: String, - #[arg(long)] - pub config: Option, + pub peer_port: u16, + //#[arg(long)] + //pub peer_id: String, + #[command(flatten)] + pub config: ConfigArgs, } #[derive(Debug, Subcommand)] @@ -36,28 +38,14 @@ pub enum NodeCommand { impl JoinNodeArgs { pub async fn ping(self) -> Result<(), Error> { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .try_init(); - let mut swarm = libp2p::SwarmBuilder::with_new_identity() - .with_tokio() - .with_tcp( - tcp::Config::default(), - noise::Config::new, - yamux::Config::default, - )? - .with_behaviour(|_| ping::Behaviour::default())? - .build(); - - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - + let mut swarm = self.config.try_into_node_config().await?.try_into_swarm().await?; let mut remote: Multiaddr = Multiaddr::empty(); - remote.push(match self.endpoint { + remote.push(match self.peer_ip { IpAddr::V4(x) => Protocol::Ip4(x), IpAddr::V6(x) => Protocol::Ip6(x), }); - remote.push(Protocol::Tcp(self.port)); + remote.push(Protocol::Tcp(self.peer_port)); let addr = remote.to_string(); swarm.dial(remote)?; println!("Dialed {addr}"); diff --git a/lazy-supplements/src/cli/server.rs b/lazy-supplements/src/cli/server.rs new file mode 100644 index 0000000..247fd7f --- /dev/null +++ b/lazy-supplements/src/cli/server.rs @@ -0,0 +1,26 @@ +use clap::Args; +use futures::StreamExt; +use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm}; +use tracing_subscriber::EnvFilter; + +use crate::error::Error; + +use super::ConfigArgs; + +#[derive(Args, Debug)] +pub struct ServerArgs { + #[command(flatten)] + config: ConfigArgs, +} +impl ServerArgs { + pub async fn start_server(self) -> Result<(), Error>{ + let mut swarm = self.config.try_into_node_config().await?.try_into_swarm().await?; + loop{ + match swarm.select_next_some().await { + SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"), + SwarmEvent::Behaviour(event) => println!("{event:?}"), + _ => {} + } + } + } +} \ No newline at end of file diff --git a/lazy-supplements/src/config/mod.rs b/lazy-supplements/src/config/mod.rs index a4b069f..a3e7f39 100644 --- a/lazy-supplements/src/config/mod.rs +++ b/lazy-supplements/src/config/mod.rs @@ -14,43 +14,4 @@ pub struct PartialConfig { node: Option, } -impl PartialConfig { - pub fn new() -> Self { - PartialConfig { - node: Some(NodeConfig::default()), - } - } - pub async fn read_or_create(path: T) -> Result - where - T: AsRef - { - if !path.as_ref().exists() { - Self::new().write_to(&path).await?; - } - Self::read_from(&path).await - } - pub async fn read_from(path:T) -> Result - where - T: AsRef - { - let mut file = File::open(path.as_ref()).await?; - let mut content = String::new(); - file.read_to_string(&mut content).await?; - let config: PartialConfig = toml::from_str(&content)?; - Ok(config) - } - pub async fn write_to(&self, path:T) -> Result<(), Error> - where - T: AsRef - { - if !path.as_ref().exists() { - let _ = File::create(&path).await?; - } - let mut file = File::open(&path).await?; - file.write_all(toml::to_string(self)?.as_bytes()).await?; - Ok(()) - } -} - - diff --git a/lazy-supplements/src/config/node.rs b/lazy-supplements/src/config/node.rs index 05afa95..f2887c4 100644 --- a/lazy-supplements/src/config/node.rs +++ b/lazy-supplements/src/config/node.rs @@ -1,13 +1,14 @@ -use std::{net::IpAddr, path::{Path, PathBuf}}; +use std::{net::IpAddr, ops, path::{Path, PathBuf}}; use base64::{prelude::BASE64_STANDARD, Engine}; use clap::Args; -use libp2p::identity::{self, DecodingError, Keypair}; +use libp2p::{identity::{self, DecodingError, Keypair}, noise, ping, tcp, yamux, Swarm}; use serde::{Deserialize, Serialize}; use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}}; +use tracing_subscriber::EnvFilter; -use crate::{error::Error, global::DEFAULT_DATABASE_FILE_PATH}; +use crate::{cli::ConfigArgs, error::Error, global::DEFAULT_DATABASE_FILE_PATH}; use super::{PartialConfig, DEFAULT_LISTEN_IPS, DEFAULT_PORT}; @@ -20,26 +21,33 @@ fn keypair_to_base64(keypair: &Keypair) -> Result { fn base64_to_keypair(base64: &str) -> Result { let vec = BASE64_STANDARD.decode(base64)?; Ok(Keypair::from_protobuf_encoding(&vec)?) - } #[derive(Debug, Deserialize, Serialize)] pub struct NodeConfig { #[serde(with = "keypair_parser")] - secret: Keypair, - database_path: PathBuf, - listen_ips: Vec, - port: u16, + pub secret: Keypair, + pub database_path: PathBuf, + pub listen_ips: Vec, + pub port: u16, } -impl Default for NodeConfig { - fn default() -> NodeConfig{ - NodeConfig { - secret: identity::Keypair::generate_ed25519(), - database_path: DEFAULT_DATABASE_FILE_PATH.to_path_buf(), - listen_ips: DEFAULT_LISTEN_IPS.to_vec(), - port: DEFAULT_PORT, - } +impl NodeConfig { + pub async fn try_into_swarm (self) -> Result, Error> { + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .try_init(); + let mut swarm = libp2p::SwarmBuilder::with_existing_identity(self.secret) + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? + .with_behaviour(|_| ping::Behaviour::default())? + .build(); + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + Ok(swarm) } } @@ -78,16 +86,16 @@ mod keypair_parser { } } -#[derive(Args, Debug, Deserialize, Serialize)] +#[derive(Args, Clone, Debug, Deserialize, Serialize)] pub struct RawNodeConfig { #[arg(skip)] - secret: Option, + pub secret: Option, #[arg(long)] - database_path: Option, + pub database_path: Option, #[arg(long)] - listen_ips: Option>, + pub listen_ips: Option>, #[arg(long)] - port: Option, + pub port: Option, } impl RawNodeConfig { @@ -138,8 +146,33 @@ impl RawNodeConfig { file.write_all(toml::to_string(self)?.as_bytes()).await?; Ok(()) } + + pub fn merge(&mut self, another: RawNodeConfig) { + if let Some(x) = another.secret { + self.secret = Some(x); + }; + if let Some(x) = another.database_path { + self.database_path = Some(x); + }; + if let Some(x) = another.listen_ips { + self.listen_ips = Some(x); + }; + if let Some(x) = another.port { + self.port = Some(x); + }; + } } +impl ops::Add for RawNodeConfig { + type Output = RawNodeConfig; + fn add(mut self, another: RawNodeConfig) -> RawNodeConfig { + self.merge(another); + self + } +} + + + #[cfg(test)] mod tests { use libp2p::identity; diff --git a/lazy-supplements/src/global/mod.rs b/lazy-supplements/src/global/mod.rs index e69867a..459310e 100644 --- a/lazy-supplements/src/global/mod.rs +++ b/lazy-supplements/src/global/mod.rs @@ -1,6 +1,6 @@ use std::{net::{IpAddr, Ipv4Addr}, path::PathBuf, sync::LazyLock}; -use crate::config::NodeConfig; +use crate::config::{NodeConfig, RawNodeConfig}; use sea_orm::DatabaseConnection; use tokio::sync::OnceCell; @@ -69,4 +69,13 @@ impl Global { pub async fn get_or_try_init_node_config(&self, config: NodeConfig) -> &NodeConfig { self.node_config.get_or_init(|| async {config}).await } -} \ No newline at end of file +} + +pub static DEFAULT_RAW_NODE_CONFIG: LazyLock = LazyLock::new(|| { + RawNodeConfig { + secret: None, + database_path: Some(DEFAULT_DATABASE_FILE_PATH.to_path_buf()), + listen_ips: Some(DEFAULT_LISTEN_IPS.to_vec()), + port: Some(DEFAULT_PORT), + } +}); \ No newline at end of file diff --git a/lazy-supplements/src/main.rs b/lazy-supplements/src/main.rs index 346538b..c6aae67 100644 --- a/lazy-supplements/src/main.rs +++ b/lazy-supplements/src/main.rs @@ -1,5 +1,5 @@ use clap::{Parser, Subcommand}; -use lazy_supplements::{cli::{InitArgs, NodeArgs, NodeCommand}, *}; +use lazy_supplements::{cli::{InitArgs, NodeArgs, NodeCommand, ServerArgs}, *}; #[derive(Debug, Parser)] struct Cli { @@ -11,6 +11,7 @@ struct Cli { enum Command { Node(NodeArgs), Init(InitArgs), + Server(ServerArgs), } @@ -22,5 +23,6 @@ async fn main() { NodeCommand::Join(y) => println!("{y:?}"), }, Command::Init(x) => x.init_config().await, + Command::Server(x) => x.start_server().await.unwrap(), } } \ No newline at end of file