use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::{Duration, Instant},
};
use rand::Rng;
use serde::{Deserialize, Serialize};
use warqueen::{
ClientDisconnectionDetails, ClientEvent, ClientNetworking, ClientOnServerDisconnectionDetails,
ClientOnServerEvent, NetReceive, NetSend, ServerListenerNetworking,
};
#[derive(Serialize, Deserialize, NetSend, NetReceive)]
enum MessageClientToServer {
String(String),
}
#[derive(Serialize, Deserialize, NetSend, NetReceive)]
enum MessageServerToClient {
String(String),
}
fn client() {
let server_address = "127.0.0.1:21001".parse().unwrap();
let mut client = ClientNetworking::new(server_address, None);
let mut last_sent_time = Instant::now();
let halt = Arc::new(AtomicBool::new(false));
let halt_cloned = Arc::clone(&halt);
ctrlc::set_handler(move || {
println!();
halt_cloned.store(true, Ordering::Relaxed);
})
.unwrap();
loop {
while let Some(event) = client.poll_event_from_server() {
match event {
ClientEvent::Connected => {
println!("Connected");
}
ClientEvent::Message(message) => match message {
MessageServerToClient::String(content) => {
println!("The server says \"{content}\"")
}
},
ClientEvent::Disconnected(details) => {
match details {
ClientDisconnectionDetails::None => {
println!("Server disconnected, let's terminate");
}
ClientDisconnectionDetails::Timeout => {
println!("Server timed out, let's terminate");
}
}
return;
}
ClientEvent::FailedToConnect => {
println!("Failed to connect, let's terminate");
return;
}
}
}
if last_sent_time.elapsed() > Duration::from_millis(1500) {
last_sent_time = Instant::now();
println!("We say \"jaaj\" to the server");
let message = MessageClientToServer::String("jaaj".to_string());
client.send_message_to_server(message);
}
if halt.load(Ordering::Relaxed) {
println!("Let's disconnect");
client.disconnect().wait_for_proper_disconnection();
break;
}
std::thread::sleep(Duration::from_millis(10));
}
}
fn server() {
let desired_port = 21001;
let server_listener = ServerListenerNetworking::new(Some(desired_port), None, None);
let actual_port = server_listener.server_port();
println!("Opened on port {actual_port}");
let mut clients = vec![];
let mut next_client_id = 0;
let mut last_sent_time = Instant::now();
let halt = Arc::new(AtomicBool::new(false));
let halt_cloned = Arc::clone(&halt);
ctrlc::set_handler(move || {
println!();
halt_cloned.store(true, Ordering::Relaxed);
})
.unwrap();
loop {
while let Some(new_client) = server_listener.poll_client() {
let address = new_client.client_address();
let client_id = next_client_id;
next_client_id += 1;
println!("Connected to client at {address}, given id {client_id}");
clients.push((new_client, client_id));
}
let mut disconnected_ids = vec![];
for (client, client_id) in clients.iter() {
while let Some(event) = client.poll_event_from_client() {
match event {
ClientOnServerEvent::Message(message) => match message {
MessageClientToServer::String(content) => {
println!("Client {client_id} says \"{content}\"");
}
},
ClientOnServerEvent::Disconnected(details) => {
match details {
ClientOnServerDisconnectionDetails::None => {
println!("Client {client_id} disconnected")
}
ClientOnServerDisconnectionDetails::Timeout => {
println!("Client {client_id} timed out")
}
}
disconnected_ids.push(*client_id);
}
}
}
}
clients.retain(|(_client, client_id)| !disconnected_ids.contains(client_id));
if last_sent_time.elapsed() > Duration::from_millis(2500) && !clients.is_empty() {
last_sent_time = Instant::now();
let random_client_index = rand::rng().random_range(0..clients.len());
let (client, client_id) = &clients[random_client_index];
println!("We say \"uwu\" to the client {client_id}");
let message = MessageServerToClient::String("uwu".to_string());
client.send_message_to_client(message);
}
if halt.load(Ordering::Relaxed) {
println!("Let's disconnect everyone");
for (client, client_id) in clients {
println!("Disconnecting client {client_id}");
client.disconnect().wait_for_proper_disconnection();
}
return;
}
std::thread::sleep(Duration::from_millis(10));
}
}
fn main() {
if std::env::args().any(|arg| arg.contains("client")) {
client();
} else if std::env::args().any(|arg| arg.contains("server")) {
server();
} else {
panic!("Neither `client` nor `server` specified in command line");
}
}