Implement server and node ping command
This commit is contained in:
parent
1a99cfd1a2
commit
886ad9c1a6
8 changed files with 140 additions and 87 deletions
30
lazy-supplements/src/cli/config.rs
Normal file
30
lazy-supplements/src/cli/config.rs
Normal file
|
@ -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<PathBuf>,
|
||||
#[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<RawNodeConfig, Error> {
|
||||
Ok(RawNodeConfig::read_from(self.get_config_path_or_default()).await? + self.node_config)
|
||||
}
|
||||
pub async fn try_into_node_config(self) -> Result<NodeConfig, Error> {
|
||||
Ok((DEFAULT_RAW_NODE_CONFIG.clone() + self.try_into_raw_node_config().await?).try_into()?)
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<PathBuf>,
|
||||
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}");
|
||||
|
|
26
lazy-supplements/src/cli/server.rs
Normal file
26
lazy-supplements/src/cli/server.rs
Normal file
|
@ -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:?}"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,43 +14,4 @@ pub struct PartialConfig {
|
|||
node: Option<NodeConfig>,
|
||||
}
|
||||
|
||||
impl PartialConfig {
|
||||
pub fn new() -> Self {
|
||||
PartialConfig {
|
||||
node: Some(NodeConfig::default()),
|
||||
}
|
||||
}
|
||||
pub async fn read_or_create<T>(path: T) -> Result<Self, Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
if !path.as_ref().exists() {
|
||||
Self::new().write_to(&path).await?;
|
||||
}
|
||||
Self::read_from(&path).await
|
||||
}
|
||||
pub async fn read_from<T>(path:T) -> Result<Self, Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
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<T>(&self, path:T) -> Result<(), Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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<String, Error> {
|
|||
fn base64_to_keypair(base64: &str) -> Result<Keypair, Error> {
|
||||
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<IpAddr>,
|
||||
port: u16,
|
||||
pub secret: Keypair,
|
||||
pub database_path: PathBuf,
|
||||
pub listen_ips: Vec<IpAddr>,
|
||||
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<Swarm<ping::Behaviour>, 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<String>,
|
||||
pub secret: Option<String>,
|
||||
#[arg(long)]
|
||||
database_path: Option<PathBuf>,
|
||||
pub database_path: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
listen_ips: Option<Vec<IpAddr>>,
|
||||
pub listen_ips: Option<Vec<IpAddr>>,
|
||||
#[arg(long)]
|
||||
port: Option<u16>,
|
||||
pub port: Option<u16>,
|
||||
}
|
||||
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<RawNodeConfig> for RawNodeConfig {
|
||||
type Output = RawNodeConfig;
|
||||
fn add(mut self, another: RawNodeConfig) -> RawNodeConfig {
|
||||
self.merge(another);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use libp2p::identity;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static DEFAULT_RAW_NODE_CONFIG: LazyLock<RawNodeConfig> = 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),
|
||||
}
|
||||
});
|
|
@ -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(),
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue