This commit is contained in:
clizia 2025-03-05 16:34:18 +01:00
parent 2650d751f0
commit 06f769ac99
8 changed files with 460 additions and 118 deletions

209
Cargo.lock generated
View file

@ -26,6 +26,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anstream"
version = "0.6.18"
@ -269,6 +275,21 @@ version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "castaway"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.2.15"
@ -330,6 +351,20 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "compact_str"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"rustversion",
"ryu",
"static_assertions",
]
[[package]]
name = "console-api"
version = "0.5.0"
@ -450,6 +485,41 @@ dependencies = [
"typenum",
]
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.95",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.95",
]
[[package]]
name = "digest"
version = "0.10.7"
@ -485,6 +555,7 @@ dependencies = [
"hyper-util",
"petname",
"rand 0.9.0-beta.1",
"ratatui",
"reqwest",
"serde",
"serde_json",
@ -548,6 +619,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "foreign-types"
version = "0.3.2"
@ -724,6 +801,11 @@ name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "hdrhistogram"
@ -1051,6 +1133,12 @@ dependencies = [
"syn 2.0.95",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.0.3"
@ -1092,6 +1180,25 @@ dependencies = [
"hashbrown 0.15.2",
]
[[package]]
name = "indoc"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "instability"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d"
dependencies = [
"darling",
"indoc",
"proc-macro2",
"quote",
"syn 2.0.95",
]
[[package]]
name = "ipnet"
version = "2.11.0"
@ -1113,6 +1220,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.14.0"
@ -1178,6 +1294,15 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "lru"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
dependencies = [
"hashbrown 0.15.2",
]
[[package]]
name = "matchers"
version = "0.1.0"
@ -1372,6 +1497,12 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -1550,6 +1681,27 @@ dependencies = [
"zerocopy 0.8.14",
]
[[package]]
name = "ratatui"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
dependencies = [
"bitflags 2.6.0",
"cassowary",
"compact_str",
"crossterm",
"indoc",
"instability",
"itertools 0.13.0",
"lru",
"paste",
"strum",
"unicode-segmentation",
"unicode-truncate",
"unicode-width 0.2.0",
]
[[package]]
name = "redox_syscall"
version = "0.5.8"
@ -1923,12 +2075,40 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.95",
]
[[package]]
name = "subtle"
version = "2.6.1"
@ -2278,6 +2458,35 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-truncate"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
dependencies = [
"itertools 0.13.0",
"unicode-segmentation",
"unicode-width 0.1.14",
]
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "untrusted"
version = "0.9.0"

View file

@ -34,3 +34,4 @@ petname = "2.0.2"
crossterm = "0.28.1"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
ratatui = "0.29.0"

View file

@ -1,6 +1,6 @@
use std::{io::{Stdout, Write}, ops::BitOrAssign, time::Duration};
use axum::response::sse::Event;
use axum::response::{sse::Event, AppendHeaders};
use clap::builder::NonEmptyStringValueParser;
use lib::{client::Client, message::{Message, MessageKind}, message_read::MessageReader, player::Player};
use crossterm::{
@ -8,107 +8,67 @@ use crossterm::{
disable_raw_mode, enable_raw_mode, Clear, ClearType, EnableLineWrap, EnterAlternateScreen
}
};
use ratatui::{
buffer::Buffer,
layout::Rect,
style::Stylize,
symbols::border,
text::{Line, Text},
widgets::{Block, Paragraph, Widget},
DefaultTerminal,
Frame,
};
const HELP: &str = r#"CIAOTERPIA
atm posso fare questo:
(ricorda di premere i bottoni)
- '1' mando giocante
- '2' mando lobbando (futuro)
"#;
// async fn delete_player(player: &Player, client: reqwest::Client, addr: &str) -> anyhow::Result<()> {
// let player_id = &player.name;
// let response = client
// .get([&addr, "/delete/", &player_id].concat())
// .send().await;
fn create_message_player(player: &Player) -> anyhow::Result<Message, anyhow::Error> {
Message::new(
&player.get_name(),
MessageKind::Test,
player.encode()?
)
}
// if let Err(e) = &response {
// println!("{e}\n");
// return Ok(())
// }
async fn delete_player(player: &Player, client: reqwest::Client, addr: &str) -> anyhow::Result<()> {
let player_id = &player.name;
let response = client
.get([&addr, "/delete/", &player_id].concat())
.send().await;
// println!("{}", response?.text().await?);
if let Err(e) = &response {
println!("{e}\n");
return Ok(())
}
// Ok(())
// }
println!("{}", response?.text().await?);
// async fn handle_terminal(player: &Player, stdout: &mut Stdout, client: reqwest::Client, addr: &str) -> anyhow::Result<()> {
// 'handler: loop {
// while let Ok(_event_happened) = poll(Duration::from_millis(2)) {
// match event::read().expect("diomerds") {
// TermEvent::Key(key) => {
// match (key.code, key.modifiers) {
// (KeyCode::Char('c'), KeyModifiers::CONTROL) => break 'handler,
// (KeyCode::Char('h'), KeyModifiers::NONE) => {
// for line in HELP.split('\n') {
// println!("{line}")
// }
// },
// (KeyCode::Char('1'), KeyModifiers::NONE) => {
// send_player(&player, client.clone(), addr).await?;
// },
// (KeyCode::Char('2'), KeyModifiers::NONE) => {
// delete_player(&player, client.clone(), addr).await?;
// },
// (_, _) => println!("{:?}\n", key),
// }
// },
// _ => continue,
// }
// }
// }
Ok(())
}
async fn send_player(player: &Player, client: reqwest::Client, addr: &str) -> anyhow::Result<()> {
let player_message = create_message_player(&player)?;
let response = client
.post([&addr, "/create/player"].concat())
.header("Content-Type", "application/json")
.body(player_message.encode()?)
.send().await;
if let Err(e) = &response {
println!("{e}\n");
return Ok(())
}
println!("{}", response?.text().await?);
Ok(())
}
async fn handle_terminal(player: &Player, stdout: &mut Stdout, client: reqwest::Client, addr: &str) -> anyhow::Result<()> {
'handler: loop {
while let Ok(_event_happened) = poll(Duration::from_millis(2)) {
match event::read().expect("diomerds") {
TermEvent::Key(key) => {
match (key.code, key.modifiers) {
(KeyCode::Char('c'), KeyModifiers::CONTROL) => break 'handler,
(KeyCode::Char('h'), KeyModifiers::NONE) => {
for line in HELP.split('\n') {
println!("{line}")
}
},
(KeyCode::Char('1'), KeyModifiers::NONE) => {
send_player(&player, client.clone(), addr).await?;
},
(KeyCode::Char('2'), KeyModifiers::NONE) => {
delete_player(&player, client.clone(), addr).await?;
},
(_, _) => println!("{:?}\n", key),
}
},
_ => continue,
}
}
}
Ok(())
}
// Ok(())
// }
#[tokio::main]
pub async fn main() -> anyhow::Result<()> {
let mut stdout = std::io::stdout();
enable_raw_mode()?;
execute!(
stdout,
Clear(ClearType::All),
EnableLineWrap,
cursor::Show,
cursor::EnableBlinking,
EnterAlternateScreen,
)?;
let player = Player::new()?;
let addr = "http://127.0.0.1:8080";
let client = reqwest::Client::new();
// println!("{}", HELP);
handle_terminal(&player, &mut stdout, client.clone(), &addr).await?;
disable_raw_mode()?;
Ok(())
let mut terminal = ratatui::init();
let app_result = Client::default().run(&mut terminal).await;
ratatui::restore();
app_result
}

View file

@ -2,13 +2,13 @@ use std::fmt::Display;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)]
pub struct Card {
pub suit: Suit,
pub value: u8,
}
#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Suit {
Hearts,
Diamonds,

View file

@ -1,33 +1,101 @@
use tokio::{io::AsyncWriteExt, net::TcpStream};
use ratatui::crossterm::{event::{self, Event, KeyCode, KeyEvent, KeyEventKind}};
use ratatui::{
buffer::Buffer,
layout::{Constraint, Flex, Layout, Rect},
style::Stylize,
symbols::border,
text::{Line, Text},
widgets::{Block, Borders, Clear, Paragraph, Widget, Wrap},
DefaultTerminal,
Frame,
};
use crate::{message::Message, player::Player};
use crate::{message::{Message, MessageKind}, player::Player, ui::ui};
#[derive(Debug, Default)]
pub struct Client {
pub server_host: String,
pub server_port: u16,
pub stream: TcpStream,
pub addr: String,
pub client: reqwest::Client,
pub user: Option<Player>,
pub name: String,
pub exit: bool,
pub popup: bool,
pub response: String,
}
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?;
pub async fn run(&mut self, terminal: &mut DefaultTerminal) -> anyhow::Result<()> {
self.addr = "http://120.0.0.1:8080".to_string();
self.client = reqwest::Client::new();
Ok(Self {
server_host: host,
server_port: port,
stream,
})
}
while !self.exit {
terminal.draw(|frame| ui(frame, self))?;
crate::ui::handle_events(self).await?;
}
pub async fn send_message(&mut self, message: Message) -> anyhow::Result<()> {
let message_string = message.encode()?;
self.stream.write_all(&message_string.as_bytes()).await?;
Ok(())
}
pub async fn create_player() -> Option<Player> {
todo!()
pub fn exit(&mut self) {
self.exit = true;
}
pub async fn send_player(&mut self, player: &Player, addr: &str) -> anyhow::Result<()> {
let player_message = Message::new(
&player.get_name(),
MessageKind::CreatePlayer,
player.encode()?
)?;
let response = self.client
.post([&addr, "/create/player"].concat())
.header("Content-Type", "application/json")
.body(player_message.encode()?)
.send().await;
if let Err(e) = &response {
self.response = e.to_string();
return Ok(())
} else {
self.response = format!("{:?}", response?);
}
Ok(())
}
}
impl Widget for &Client {
fn render(self, area: Rect, buf: &mut Buffer) {
let title = Line::from(" durak tui test fre ".bold());
let instructions = Line::from(vec![
" create player ".into(),
"1".blue().bold(),
" create lobby ".into(),
"2".blue().bold(),
" quit ".into(),
"<Q>".blue().bold(),
]);
let block = Block::bordered()
.title(title.centered())
.title_bottom(instructions.centered())
.border_set(border::THICK);
let infos = Text::from(vec![
Line::from(vec![
"connected to: ".into(),
self.addr.clone().yellow(),
]),
Line::from(vec![
"username: ".into(),
self.name.clone().yellow(),
]),
]);
Paragraph::new(infos)
.left_aligned()
.block(block)
.render(area, buf);
}
}

View file

@ -7,6 +7,6 @@ pub mod player;
pub mod message;
pub mod message_read;
pub mod constant;
pub mod routine;
pub mod db;
pub mod router;
pub mod ui;

View file

@ -6,7 +6,7 @@ use axum::Json;
use crate::card::Card;
#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone)]
#[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Clone)]
pub struct Player {
pub id: String,
pub name: String,

104
src/ui.rs Normal file
View file

@ -0,0 +1,104 @@
use ratatui::{
layout::{
Constraint,
Direction,
Layout,
Rect
},
style::{Color, Style, Stylize},
text::{Line, Span, Text},
widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Widget, Wrap},
Frame,
};
use ratatui::crossterm::{event::{self, Event, KeyCode, KeyEvent, KeyEventKind}};
use crate::{client::Client, player::Player};
async fn handle_key_event(mut client: &mut Client, key_event: KeyEvent) {
match key_event.code {
KeyCode::Char('q') => Client::exit(client),
KeyCode::Char('1') => {
if !client.name.is_empty() {
println!("user already created");
return
}
client.user = Some(Player::new().expect("toto"));
client.name = client.user.clone().unwrap().name;
},
KeyCode::Char('2') => {
todo!()
},
KeyCode::Char('3') => {
if let Some(player) = client.user.clone() {
let addr = client.addr.clone();
Client::send_player(&mut client, &player, &addr).await.unwrap();
return
}
}
_ => {}
}
}
pub async fn handle_events(client: &mut Client) -> anyhow::Result<()> {
match event::read()? {
Event::Key(key) if key.kind == KeyEventKind::Press => {
handle_key_event(client, key).await
}
_ => {}
};
Ok(())
}
pub fn ui(frame: &mut Frame, app: &Client) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(3),
Constraint::Min(1),
])
.split(frame.area());
let instructions = Line::from(vec![
" 1".blue().bold(),
" create player ".into(),
"2".blue().bold(),
" create lobby ".into(),
"3".blue().bold(),
" send player ".into(),
"<Q>".blue().bold(),
" quit ".into(),
]);
let infos = Text::from(vec![
Line::from(vec![
"connected to: ".into(),
app.addr.clone().yellow(),
]),
Line::from(vec![
"username: ".into(),
app.name.clone().yellow(),
]),
]);
let title = Line::from(" durak tui test fre ".bold());
let top_block = Block::default()
.title(title.centered())
.borders(Borders::ALL)
.style(Style::default());
frame.render_widget(Paragraph::new(infos).block(top_block), chunks[0]);
let server_message = Text::from(vec![
Line::from(vec![
"message: ".into(),
app.response.clone().blue(),
])
]);
let btm_block = Block::default()
.title_bottom(instructions.centered())
.borders(Borders::ALL)
.style(Style::default());
frame.render_widget(Paragraph::new(server_message).block(btm_block), chunks[1]);
}