bunch of things

This commit is contained in:
clizia 2025-01-26 02:15:37 +01:00
parent f66600cabc
commit ea80597050
13 changed files with 224 additions and 13 deletions

View file

@ -3,6 +3,18 @@ name = "durak-frthistime"
version = "0.1.0"
edition = "2021"
[lib]
name = "lib"
path = "src/lib.rs"
[[bin]]
name = "server"
path = "src/bin/server.rs"
[[bin]]
name = "client"
path = "src/bin/client.rs"
[dependencies]
rand = "0.9.0-beta.1"
clap = "4.5.23"

15
src/bin/client.rs Normal file
View file

@ -0,0 +1,15 @@
use lib::{client::Client, message::Message};
#[tokio::main]
pub async fn main() -> anyhow::Result<()> {
let mut client = Client::connect("127.0.0.1", 8080).await?;
for i in 1..11 {
let message = Message::new(format!("Hello toto x {}!!!", i));
client.send_message(message.unwrap().clone()).await?;
}
client.send_message(Message::new("EXIT").unwrap()).await?;
Ok(())
}

8
src/bin/server.rs Normal file
View file

@ -0,0 +1,8 @@
use lib::server::Server;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut server = Server::new("127.0.0.1", 8080);
server.run().await?;
Ok(())
}

View file

@ -17,7 +17,7 @@ pub enum Suit {
}
impl Card {
pub fn new(suit: Suit, value: u8) -> Card {
pub fn new(suit: Suit, value: u8) -> Self {
Card {
suit,
value,

28
src/client.rs Normal file
View file

@ -0,0 +1,28 @@
use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::message::Message;
pub struct Client {
pub server_host: String,
pub server_port: u16,
pub stream: TcpStream,
}
impl Client {
pub async fn connect(host: impl Into<String>, port: u16) -> anyhow::Result<Self> {
let host = host.into();
let address = format!("{}:{}", host, port);
let stream = TcpStream::connect(address).await?;
Ok(Self {
server_host: host,
server_port: port,
stream,
})
}
pub async fn send_message(&mut self, message: Message) -> anyhow::Result<()> {
self.stream.write_all(&message.encode()).await?;
Ok(())
}
}

View file

@ -10,7 +10,7 @@ pub struct Deck {
}
impl Deck {
pub fn new() -> Deck {
pub fn new() -> Self {
// possible values go from 0 to 8 because Durak is played
// without cards with a value lower than 6 in real life
// and ace is the highest card
@ -35,7 +35,7 @@ impl Deck {
self.deck
}
pub fn shuffle(mut self) -> Deck {
pub fn shuffle(mut self) -> Self {
let mut rng = rng();
self.deck.shuffle(&mut rng); // shuffle modifies in place

8
src/lib.rs Normal file
View file

@ -0,0 +1,8 @@
pub mod server;
pub mod client;
pub mod card;
pub mod deck;
pub mod lobby;
pub mod player;
pub mod message;
pub mod message_read;

View file

@ -9,7 +9,7 @@ pub struct Lobby {
}
impl Lobby {
pub fn new() -> Lobby {
pub fn new() -> Self {
let players: Vec<Player> = Vec::new();
let deck = Deck::new().shuffle();

View file

@ -2,18 +2,14 @@ use std::collections::HashMap;
use std::io::{self, Error};
use std::net::SocketAddr;
use crate::lobby::Lobby;
use crate::player::Player;
use lib::lobby::Lobby;
use lib::player::Player;
use std::sync::{Arc, Mutex};
use anyhow::Result;
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
use tokio::net::{TcpListener, TcpStream};
mod card;
mod deck;
mod lobby;
mod player;
async fn handle_connection(mut stream: TcpStream, addr: SocketAddr) -> (Option<Player>, Option<Lobby>) {
let (mut read, mut write) = stream.split();
@ -51,7 +47,7 @@ async fn main() -> io::Result<()> {
let address = "127.0.0.1:8080".to_string();
let listener = TcpListener::bind(&address).await?;
let mut lobbies: HashMap<String, Lobby> = HashMap::new();
let mut lobbies: Arc<Mutex<HashMap<String, Lobby>>> = Arc::new(Mutex::new(HashMap::new()));
loop {
let (mut stream, addr) = listener.accept().await?;

46
src/message.rs Normal file
View file

@ -0,0 +1,46 @@
// everything here needs to be adjusted for the deserialized json
//
#[derive(Debug, Clone)]
pub struct Message {
pub length: u16,
pub content: String,
}
impl Message {
pub fn new(content: impl Into<String>) -> anyhow::Result<Self> {
let content = content.into();
let length = content.len() as u16;
Ok(Self {
length,
content,
})
}
pub fn encode(&self) -> Vec<u8> {
let mut buffer = Vec::new();
buffer.extend(&self.length.to_be_bytes());
buffer.extend(self.content.as_bytes());
buffer
}
pub fn decode(buffer: &[u8]) -> anyhow::Result<Self> {
// this `if` compares the buffer length to the minimum
// message size (which is 2 because it takes to bytes
// to write 0), it is now hardcoded but it MUST be moved
// into a constant in a special constant definition file
// byeeeeeeeeeeeeeeeeee luv ya
if buffer.len() < 2 {
return Err(anyhow::anyhow!("Invalid message length"));
}
let length = u16::from_be_bytes([buffer[0], buffer[1]]);
let content = String::from_utf8(buffer[2..2 + length as usize].to_vec())?;
Ok(Self {
length,
content,
})
}
}

44
src/message_read.rs Normal file
View file

@ -0,0 +1,44 @@
// every hardcoded 2 will one day be a constant in a special
// constant file but rn I AM LAZY AND ITS LATE
//
use crate::message::Message;
pub struct MessageReader {
pub buffer: Vec<u8>,
}
impl MessageReader {
pub fn new() -> Self {
Self { buffer: Vec::new() }
}
fn can_parse(&self) -> bool {
if self.buffer.len() < 2 {
return false;
}
let length = u16::from_be_bytes([self.buffer[0], self.buffer[1]]);
self.buffer.len() >= 2 + length as usize
}
fn parse_first(&mut self) -> anyhow::Result<Message> {
let length = u16::from_be_bytes([self.buffer[0], self.buffer[2]]);
let message_length = 2 + length as usize;
let message = self.buffer[..message_length].to_vec();
self.buffer = self.buffer[message_length..].to_vec();
Message::decode(&message)
}
pub fn read(&mut self, data: &[u8]) -> anyhow::Result<Vec<Message>> {
self.buffer.extend_from_slice(data);
let mut data = vec![];
while self.can_parse() {
let message = self.parse_first()?;
data.push(message);
}
Ok(data)
}
}

View file

@ -19,7 +19,7 @@ pub struct Player {
}
impl Player {
pub fn new(addr: SocketAddr, name: &str) -> Player {
pub fn new(addr: SocketAddr, name: &str) -> Self {
let hand_empty: Vec<Card> = Vec::new();
let to_digest: String = addr.to_string();

54
src/server.rs Normal file
View file

@ -0,0 +1,54 @@
use tokio::{io::AsyncReadExt, net::TcpListener};
use crate::message_read::MessageReader;
pub struct Server {
pub host: String,
pub port: u16,
}
impl Server {
pub fn new(host: impl Into<String>, port: u16) -> Self {
Server {
host: host.into(),
port,
}
}
pub async fn run(&mut self) -> anyhow::Result<()> {
let listener = TcpListener::bind(format!(
"{}:{}",
self.host,
self.port
)).await?;
println!("Server is running on {}:{}", self.host, self.port);
loop {
let (mut socket, addr) = listener.accept().await?;
println!("Connection received from {}", addr);
tokio::task::spawn(async move {
let mut message_reader = MessageReader::new();
'handler: loop {
let mut buffer = vec![0; 256];
let bytes_read = socket.read(&mut buffer).await?;
let messages = message_reader.read(&buffer[..bytes_read])?;
for message in messages {
if message.content == "EXIT" {
println!("Connection closed by the client");
break 'handler;
}
println!("Message:\n{:?}", message);
}
}
Ok::<(), anyhow::Error>(())
});
}
Ok(())
}
}