aboutsummaryrefslogtreecommitdiff
path: root/karyons_p2p/examples
diff options
context:
space:
mode:
Diffstat (limited to 'karyons_p2p/examples')
-rw-r--r--karyons_p2p/examples/chat.rs141
-rwxr-xr-xkaryons_p2p/examples/chat_simulation.sh25
-rw-r--r--karyons_p2p/examples/monitor.rs93
-rwxr-xr-xkaryons_p2p/examples/net_simulation.sh73
-rw-r--r--karyons_p2p/examples/peer.rs82
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));
+}