diff options
Diffstat (limited to 'karyons_p2p/examples')
-rw-r--r-- | karyons_p2p/examples/chat.rs | 141 | ||||
-rwxr-xr-x | karyons_p2p/examples/chat_simulation.sh | 25 | ||||
-rw-r--r-- | karyons_p2p/examples/monitor.rs | 93 | ||||
-rwxr-xr-x | karyons_p2p/examples/net_simulation.sh | 73 | ||||
-rw-r--r-- | karyons_p2p/examples/peer.rs | 82 |
5 files changed, 414 insertions, 0 deletions
diff --git a/karyons_p2p/examples/chat.rs b/karyons_p2p/examples/chat.rs new file mode 100644 index 0000000..4358362 --- /dev/null +++ b/karyons_p2p/examples/chat.rs @@ -0,0 +1,141 @@ +use std::sync::Arc; + +use async_std::io; +use async_trait::async_trait; +use clap::Parser; +use smol::{channel, future, Executor}; + +use karyons_net::{Endpoint, Port}; + +use karyons_p2p::{ + protocol::{ArcProtocol, Protocol, ProtocolEvent, ProtocolID}, + ArcPeer, Backend, Config, P2pError, PeerID, Version, +}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Optional list of bootstrap peers to start the seeding process. + #[arg(short)] + bootstrap_peers: Vec<Endpoint>, + + /// Optional list of peer endpoints for manual connections. + #[arg(short)] + peer_endpoints: Vec<Endpoint>, + + /// Optional endpoint for accepting incoming connections. + #[arg(short)] + listen_endpoint: Option<Endpoint>, + + /// Optional TCP/UDP port for the discovery service. + #[arg(short)] + discovery_port: Option<Port>, + + /// Username + #[arg(long)] + username: String, +} + +pub struct ChatProtocol { + username: String, + peer: ArcPeer, +} + +impl ChatProtocol { + fn new(username: &str, peer: ArcPeer) -> ArcProtocol { + Arc::new(Self { + peer, + username: username.to_string(), + }) + } +} + +#[async_trait] +impl Protocol for ChatProtocol { + async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<(), P2pError> { + let selfc = self.clone(); + let stdin = io::stdin(); + let task = ex.spawn(async move { + loop { + let mut input = String::new(); + stdin.read_line(&mut input).await.unwrap(); + let msg = format!("> {}: {}", selfc.username, input.trim()); + selfc.peer.broadcast(&Self::id(), &msg).await; + } + }); + + let listener = self.peer.register_listener::<Self>().await; + loop { + let event = listener.recv().await.unwrap(); + + match event { + ProtocolEvent::Message(msg) => { + let msg = String::from_utf8(msg).unwrap(); + println!("{msg}"); + } + ProtocolEvent::Shutdown => { + break; + } + } + } + + task.cancel().await; + listener.cancel().await; + Ok(()) + } + + fn version() -> Result<Version, P2pError> { + "0.1.0, 0.1.0".parse() + } + + fn id() -> ProtocolID { + "CHAT".into() + } +} + +fn main() { + env_logger::init(); + let cli = Cli::parse(); + + // Create a PeerID based on the username. + let peer_id = PeerID::new(cli.username.as_bytes()); + + // Create the configuration for the backend. + let config = Config { + listen_endpoint: cli.listen_endpoint, + peer_endpoints: cli.peer_endpoints, + bootstrap_peers: cli.bootstrap_peers, + discovery_port: cli.discovery_port.unwrap_or(0), + ..Default::default() + }; + + // Create a new Backend + let backend = Backend::new(peer_id, config); + + let (ctrlc_s, ctrlc_r) = channel::unbounded(); + let handle = move || ctrlc_s.try_send(()).unwrap(); + ctrlc::set_handler(handle).unwrap(); + + // Create a new Executor + let ex = Arc::new(Executor::new()); + + let ex_cloned = ex.clone(); + let task = ex.spawn(async { + let username = cli.username; + + // Attach the ChatProtocol + let c = move |peer| ChatProtocol::new(&username, peer); + backend.attach_protocol::<ChatProtocol>(c).await.unwrap(); + + // Run the backend + backend.run(ex_cloned).await.unwrap(); + + // Wait for ctrlc signal + ctrlc_r.recv().await.unwrap(); + + // Shutdown the backend + backend.shutdown().await; + }); + + future::block_on(ex.run(task)); +} diff --git a/karyons_p2p/examples/chat_simulation.sh b/karyons_p2p/examples/chat_simulation.sh new file mode 100755 index 0000000..82bbe96 --- /dev/null +++ b/karyons_p2p/examples/chat_simulation.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# build +cargo build --release --example chat + +tmux new-session -d -s karyons_chat + +tmux send-keys -t karyons_chat "../../target/release/examples/chat --username 'user1'\ + -l 'tcp://127.0.0.1:40000' -d '40010'" Enter + +tmux split-window -h -t karyons_chat +tmux send-keys -t karyons_chat "../../target/release/examples/chat --username 'user2'\ + -l 'tcp://127.0.0.1:40001' -d '40011' -b 'tcp://127.0.0.1:40010 ' " Enter + +tmux split-window -h -t karyons_chat +tmux send-keys -t karyons_chat "../../target/release/examples/chat --username 'user3'\ + -l 'tcp://127.0.0.1:40002' -d '40012' -b 'tcp://127.0.0.1:40010'" Enter + +tmux split-window -h -t karyons_chat +tmux send-keys -t karyons_chat "../../target/release/examples/chat --username 'user4'\ + -b 'tcp://127.0.0.1:40010'" Enter + +tmux select-layout tiled + +tmux attach -t karyons_chat diff --git a/karyons_p2p/examples/monitor.rs b/karyons_p2p/examples/monitor.rs new file mode 100644 index 0000000..cd4defc --- /dev/null +++ b/karyons_p2p/examples/monitor.rs @@ -0,0 +1,93 @@ +use std::sync::Arc; + +use clap::Parser; +use easy_parallel::Parallel; +use smol::{channel, future, Executor}; + +use karyons_net::{Endpoint, Port}; + +use karyons_p2p::{Backend, Config, PeerID}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Optional list of bootstrap peers to start the seeding process. + #[arg(short)] + bootstrap_peers: Vec<Endpoint>, + + /// Optional list of peer endpoints for manual connections. + #[arg(short)] + peer_endpoints: Vec<Endpoint>, + + /// Optional endpoint for accepting incoming connections. + #[arg(short)] + listen_endpoint: Option<Endpoint>, + + /// Optional TCP/UDP port for the discovery service. + #[arg(short)] + discovery_port: Option<Port>, + + /// Optional user id + #[arg(long)] + userid: Option<String>, +} + +fn main() { + env_logger::init(); + let cli = Cli::parse(); + + let peer_id = match cli.userid { + Some(userid) => PeerID::new(userid.as_bytes()), + None => PeerID::random(), + }; + + // Create the configuration for the backend. + let config = Config { + listen_endpoint: cli.listen_endpoint, + peer_endpoints: cli.peer_endpoints, + bootstrap_peers: cli.bootstrap_peers, + discovery_port: cli.discovery_port.unwrap_or(0), + ..Default::default() + }; + + // Create a new Backend + let backend = Backend::new(peer_id, config); + + let (ctrlc_s, ctrlc_r) = channel::unbounded(); + let handle = move || ctrlc_s.try_send(()).unwrap(); + ctrlc::set_handler(handle).unwrap(); + + let (signal, shutdown) = channel::unbounded::<()>(); + + // Create a new Executor + let ex = Arc::new(Executor::new()); + + let task = async { + let monitor = backend.monitor().await; + + let monitor_task = ex.spawn(async move { + loop { + let event = monitor.recv().await.unwrap(); + println!("{}", event); + } + }); + + // Run the backend + backend.run(ex.clone()).await.unwrap(); + + // Wait for ctrlc signal + ctrlc_r.recv().await.unwrap(); + + // Shutdown the backend + backend.shutdown().await; + + monitor_task.cancel().await; + + drop(signal); + }; + + // Run four executor threads. + Parallel::new() + .each(0..4, |_| future::block_on(ex.run(shutdown.recv()))) + .finish(|| future::block_on(task)); +} diff --git a/karyons_p2p/examples/net_simulation.sh b/karyons_p2p/examples/net_simulation.sh new file mode 100755 index 0000000..b223b63 --- /dev/null +++ b/karyons_p2p/examples/net_simulation.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# build +cargo build --release --example peer + +tmux new-session -d -s karyons_p2p + +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer1'\ + -l 'tcp://127.0.0.1:30000' -d '30010'" Enter + +tmux split-window -h -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer2'\ + -l 'tcp://127.0.0.1:30001' -d '30011' -b 'tcp://127.0.0.1:30010 ' " Enter + +tmux split-window -h -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer3'\ + -l 'tcp://127.0.0.1:30002' -d '30012' -b 'tcp://127.0.0.1:30010'" Enter + +tmux split-window -h -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer4'\ + -l 'tcp://127.0.0.1:30003' -d '30013' -b 'tcp://127.0.0.1:30010'" Enter + +tmux split-window -h -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer5'\ + -l 'tcp://127.0.0.1:30004' -d '30014' -b 'tcp://127.0.0.1:30010'" Enter + +tmux split-window -h -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer6'\ + -l 'tcp://127.0.0.1:30005' -d '30015' -b 'tcp://127.0.0.1:30010'" Enter + +tmux select-layout even-horizontal + +sleep 3; + +tmux select-pane -t karyons_p2p:0.0 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer7'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30011'" Enter + +tmux select-pane -t karyons_p2p:0.2 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer8'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30012' -p 'tcp://127.0.0.1:30005'" Enter + +tmux select-pane -t karyons_p2p:0.4 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer9'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30013'" Enter + +tmux select-pane -t karyons_p2p:0.6 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer10'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30014'" Enter + +tmux select-pane -t karyons_p2p:0.8 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer11'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30015'" Enter + +tmux select-pane -t karyons_p2p:0.10 + +tmux split-window -v -t karyons_p2p +tmux send-keys -t karyons_p2p "../../target/release/examples/peer --userid 'peer12'\ + -b 'tcp://127.0.0.1:30010' -b 'tcp://127.0.0.1:30015' -b 'tcp://127.0.0.1:30011'" Enter + +tmux set-window-option -t karyons_p2p synchronize-panes on + +tmux attach -t karyons_p2p diff --git a/karyons_p2p/examples/peer.rs b/karyons_p2p/examples/peer.rs new file mode 100644 index 0000000..f805d68 --- /dev/null +++ b/karyons_p2p/examples/peer.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; + +use clap::Parser; +use easy_parallel::Parallel; +use smol::{channel, future, Executor}; + +use karyons_net::{Endpoint, Port}; + +use karyons_p2p::{Backend, Config, PeerID}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Optional list of bootstrap peers to start the seeding process. + #[arg(short)] + bootstrap_peers: Vec<Endpoint>, + + /// Optional list of peer endpoints for manual connections. + #[arg(short)] + peer_endpoints: Vec<Endpoint>, + + /// Optional endpoint for accepting incoming connections. + #[arg(short)] + listen_endpoint: Option<Endpoint>, + + /// Optional TCP/UDP port for the discovery service. + #[arg(short)] + discovery_port: Option<Port>, + + /// Optional user id + #[arg(long)] + userid: Option<String>, +} + +fn main() { + env_logger::init(); + let cli = Cli::parse(); + + let peer_id = match cli.userid { + Some(userid) => PeerID::new(userid.as_bytes()), + None => PeerID::random(), + }; + + // Create the configuration for the backend. + let config = Config { + listen_endpoint: cli.listen_endpoint, + peer_endpoints: cli.peer_endpoints, + bootstrap_peers: cli.bootstrap_peers, + discovery_port: cli.discovery_port.unwrap_or(0), + ..Default::default() + }; + + // Create a new Backend + let backend = Backend::new(peer_id, config); + + let (ctrlc_s, ctrlc_r) = channel::unbounded(); + let handle = move || ctrlc_s.try_send(()).unwrap(); + ctrlc::set_handler(handle).unwrap(); + + let (signal, shutdown) = channel::unbounded::<()>(); + + // Create a new Executor + let ex = Arc::new(Executor::new()); + + let task = async { + // Run the backend + backend.run(ex.clone()).await.unwrap(); + + // Wait for ctrlc signal + ctrlc_r.recv().await.unwrap(); + + // Shutdown the backend + backend.shutdown().await; + + drop(signal); + }; + + // Run four executor threads. + Parallel::new() + .each(0..4, |_| future::block_on(ex.run(shutdown.recv()))) + .finish(|| future::block_on(task)); +} |