Compare commits

...

2 commits

Author SHA1 Message Date
72d3a1f54b Add PeerArg 2025-06-07 09:28:18 +09:00
51b12870dd Implement console writer 2025-06-07 09:21:07 +09:00
7 changed files with 99 additions and 48 deletions

View file

@ -27,6 +27,7 @@ tempfile = { version = "3.20.0", optional = true }
thiserror = "2.0.12"
tokio = { version = "1.45.0", features = ["macros", "rt"] }
toml = "0.8.22"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
uuid = { version = "1.17.0", features = ["v4"] }

View file

@ -1,10 +1,14 @@
mod writer;
use std::{collections::HashMap, ffi::OsString, hash::Hash, time::Duration};
use clap::{Args, Parser};
use futures::{future::BoxFuture, StreamExt};
use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
use tokio::time::sleep;
use libp2p::{core::transport::dummy::DummyTransport, noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
use rustyline::ExternalPrinter;
use tokio::{sync::Mutex, time::sleep};
use tracing_subscriber::EnvFilter;
use writer::ConsoleWriter;
use crate::{error::Error, global::GLOBAL};
@ -78,6 +82,17 @@ impl ConsoleArgs {
GLOBAL.launch_swarm().await
});
let mut rl = rustyline::DefaultEditor::new()?;
let mut printer = rl.create_external_printer()?;
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.with_writer(std::sync::Mutex::new(ConsoleWriter::try_from(&mut rl)?)
).init();
tokio::spawn(async move {
loop{
tracing::event!(tracing::Level::ERROR, "test");
tokio::time::sleep(Duration::from_secs(1)).await;
}
});
loop {
match rl.readline(">> ") {
Ok(line) => {

View file

@ -0,0 +1,31 @@
use std::io::Read;
use rustyline::{DefaultEditor, ExternalPrinter};
use crate::error::Error;
pub struct ConsoleWriter {
printer: Box<dyn ExternalPrinter + 'static + Send>
}
impl TryFrom<&mut DefaultEditor> for ConsoleWriter {
type Error = Error;
fn try_from(e: &mut DefaultEditor) -> Result<Self, Error> {
Ok(ConsoleWriter {
printer: Box::new(e.create_external_printer()?)
})
}
}
impl std::io::Write for ConsoleWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let msg = String::from_utf8_lossy(buf).into_owned();
let size = msg.as_bytes().len();
self.printer.as_mut().print(msg);
Ok(size)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}

View file

@ -9,5 +9,5 @@ mod server;
pub use config::ConfigArgs;
pub use console::{ConsoleArgs, ConsoleCommands};
pub use init::InitArgs;
pub use node::{ NodeArgs, NodeCommand, JoinNodeArgs , ConsoleNodeArgs};
pub use node::{ NodeArgs, NodeCommand, PeerArgs , ConsoleNodeArgs};
pub use server::ServerArgs;

View file

@ -1,9 +1,9 @@
use std::{net::IpAddr, path::PathBuf};
use std::{net::IpAddr, ops::Mul, path::PathBuf, str::FromStr};
use clap::{Args, Parser, Subcommand};
use futures::StreamExt;
use libp2p::{
multiaddr::Protocol, noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr
multiaddr::Protocol, noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr, PeerId
};
use tracing_subscriber::EnvFilter;
@ -35,47 +35,53 @@ pub async fn parse_and_run_console_node_command(s:Vec<String>) -> Result<(), Err
}
#[derive(Args, Debug)]
pub struct JoinNodeArgs {
#[arg(long)]
pub peer_ip: IpAddr,
#[arg(long)]
pub peer_port: u16,
//#[arg(long)]
//pub peer_id: String,
pub struct PeerArgs {
#[arg(value_parser = clap::value_parser!(PeerArg))]
pub peer: PeerArg,
}
#[derive(Clone, Debug)]
pub enum PeerArg {
Addr(Multiaddr),
Id(PeerId),
Number(u32),
}
impl FromStr for PeerArg {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(x) = s.parse::<Multiaddr>() {
Ok(Self::Addr(x))
} else if let Ok(x) = s.parse::<PeerId>() {
Ok(Self::Id(x))
} else if let Ok(x) = s.parse::<u32>() {
Ok(Self::Number(x))
} else {
Err(format!("Invalid value: {s}").to_string())
}
}
}
#[derive(Args, Debug)]
pub struct NodeJoinArgs {
#[command(flatten)]
pub config: ConfigArgs,
pub peer: PeerArgs,
pub pass: Option<String>,
}
#[derive(Debug, Subcommand)]
pub enum NodeCommand {
Ping(JoinNodeArgs),
Join(JoinNodeArgs),
Add(PeerArgs),
Ping(PeerArgs),
Join(PeerArgs),
List,
Delete(PeerArgs),
}
impl JoinNodeArgs {
pub async fn ping(self) -> Result<(), Error> {
let mut swarm = self.config.try_into_node_config().await?.try_into_swarm().await?;
let mut remote: Multiaddr = Multiaddr::empty();
remote.push(match self.peer_ip {
IpAddr::V4(x) => Protocol::Ip4(x),
IpAddr::V6(x) => Protocol::Ip6(x),
});
remote.push(Protocol::Tcp(self.peer_port));
let addr = remote.to_string();
swarm.dial(remote)?;
println!("Dialed {addr}");
loop{
match swarm.select_next_some().await {
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
SwarmEvent::Behaviour(event) => {
println!("{event:?}");
event.run().await;
},
_ => {}
}
}
impl PeerArgs {
pub async fn run(self) -> Result<(), Error> {
println!("{self:?}");
todo!()
}
}

View file

@ -34,9 +34,6 @@ pub struct NodeConfig {
impl NodeConfig {
pub async fn try_into_swarm (self) -> Result<Swarm<p2p::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(

View file

@ -1,10 +1,12 @@
use clap::{Parser, Subcommand};
use lazy_supplements::{cli::{ConsoleArgs, ConsoleCommands, InitArgs, NodeArgs, NodeCommand, ServerArgs}, *};
use lazy_supplements::{cli::{ConfigArgs, ConsoleArgs, ConsoleCommands, InitArgs, NodeArgs, NodeCommand, ServerArgs}, global::{Global, GLOBAL}, *};
#[derive(Debug, Parser)]
struct Cli {
#[command(subcommand)]
command: Command,
#[command(flatten)]
pub config: ConfigArgs,
}
#[derive(Debug, Subcommand)]
@ -18,11 +20,10 @@ enum Command {
#[tokio::main]
async fn main() {
match Cli::parse().command {
Command::Node(x) => match x.command {
NodeCommand::Ping(y) => y.ping().await.unwrap(),
NodeCommand::Join(y) => println!("{y:?}"),
},
let cli = Cli::parse();
let _ = GLOBAL.get_or_init_node_config(cli.config.try_into_node_config().await.unwrap()).await;
match cli.command {
Command::Node(x) => x.run().await.unwrap(),
Command::Init(x) => x.init_config().await,
Command::Server(x) => x.start_server().await.unwrap(),
Command::Console(x) => x.start_console(ConsoleCommands::default()).await.unwrap(),