bunch of things
This commit is contained in:
parent
f66600cabc
commit
ea80597050
13 changed files with 224 additions and 13 deletions
12
Cargo.toml
12
Cargo.toml
|
@ -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
15
src/bin/client.rs
Normal 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
8
src/bin/server.rs
Normal 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(())
|
||||
}
|
|
@ -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
28
src/client.rs
Normal 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(())
|
||||
}
|
||||
}
|
|
@ -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
8
src/lib.rs
Normal 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;
|
|
@ -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();
|
||||
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -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
46
src/message.rs
Normal 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
44
src/message_read.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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
54
src/server.rs
Normal 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(())
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue