use std::net::SocketAddr;
use peerlink::{Command, Config, Event};
#[derive(Debug)]
enum Message {
Ping(u64),
Pong(u64),
}
impl peerlink::Message for Message {
const MAX_SIZE: usize = 12;
fn encode(&self, dest: &mut impl std::io::Write) -> usize {
let (msg_type, value) = match &self {
Message::Ping(p) => (b"ping", p),
Message::Pong(p) => (b"pong", p),
};
let mut written = 0;
written += dest.write(msg_type).unwrap();
written += dest.write(&value.to_le_bytes()).unwrap();
written
}
fn decode(buffer: &[u8]) -> Result<(Self, usize), peerlink::DecodeError> {
const VALUE_OFFSET: usize = 4;
const MSG_LEN: usize = 12;
if buffer.len() >= MSG_LEN {
let value = u64::from_le_bytes(buffer[VALUE_OFFSET..MSG_LEN].try_into().unwrap());
match &buffer[0..4] {
b"ping" => Ok((Message::Ping(value), MSG_LEN)),
b"pong" => Ok((Message::Pong(value), MSG_LEN)),
_ => Err(peerlink::DecodeError::MalformedMessage),
}
} else {
Err(peerlink::DecodeError::NotEnoughData)
}
}
}
fn server() -> std::io::Result<()> {
let bind_addr = "127.0.0.1:8080".parse().unwrap();
println!("Server: starting to listen on address {}", bind_addr);
let handle = peerlink::run::<_>(Config {
bind_addr: vec![bind_addr],
..Default::default()
})?;
loop {
match handle.receive_blocking().unwrap() {
Event::ConnectedFrom { peer, addr, .. } => {
println!("Inbound peer connect: peer_id={} ip={}", peer, addr);
}
Event::Disconnected { peer, reason } => {
println!(
"Inbound peer disconnect: peer_id={}, reason={:?}",
peer, reason
);
}
Event::Message {
peer,
message,
size,
} => match message {
Message::Ping(p) => {
assert_eq!(size, 12);
println!("Incoming ping: peer={}, value={}", peer, p);
handle.send(Command::Message(peer, Message::Pong(p)))?;
}
Message::Pong(p) => {
assert_eq!(size, 12);
println!("Incoming pong: peer={}, value={}", peer, p);
}
},
_ => {}
}
}
}
fn client() -> std::io::Result<()> {
let handle = peerlink::run(Config::default())?;
let server_addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
handle.send(Command::connect(server_addr))?;
let peer_id = match handle.receive_blocking()? {
Event::ConnectedTo {
target,
result: Ok(peer_id),
} if target == server_addr.into() => {
println!("Connected to server at {}", target);
peer_id
}
event => panic!("Unexpected event: {:?}", event),
};
let mut ping = 0;
loop {
std::thread::sleep(std::time::Duration::from_secs(5));
handle.send(Command::Message(peer_id, Message::Ping(ping)))?;
println!("Sending a ping: value={}", ping);
match handle.receive_blocking()? {
Event::Message {
message: Message::Pong(pong),
..
} => {
println!("Received a pong: value={}", pong);
}
Event::Disconnected { .. } => {
println!("The server has disconnected, exiting.");
break Ok(());
}
event => panic!("Unexpected event: {:?}", event),
}
ping += 1;
}
}
fn main() -> std::io::Result<()> {
env_logger::init();
match std::env::args().nth(1).as_deref() {
Some("client") => client(),
Some("server") => server(),
_ => {
eprintln!("The first arg must be either 'client' or 'server'");
Ok(())
}
}
}