Rewrite to chatty but functional API.

This commit is contained in:
2025-06-14 22:16:13 +02:00
parent d1832bc794
commit db6f55bc47
20 changed files with 423 additions and 175 deletions

112
gamenight-cli/Cargo.lock generated
View File

@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "adler2"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "android-tzdata"
@@ -84,9 +84,9 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bumpalo"
version = "3.17.0"
version = "3.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
[[package]]
name = "byteorder"
@@ -102,18 +102,18 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.25"
version = "1.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "chrono"
@@ -264,6 +264,19 @@ dependencies = [
"gamenight-api-client-rs",
"inquire",
"tokio",
"uuid",
]
[[package]]
name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
]
[[package]]
@@ -333,9 +346,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.13"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
dependencies = [
"base64",
"bytes",
@@ -566,9 +579,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "mime"
@@ -588,9 +601,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
@@ -603,7 +616,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
@@ -614,7 +627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"wasi",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.59.0",
]
@@ -719,6 +732,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "redox_syscall"
version = "0.5.12"
@@ -730,9 +749,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.18"
version = "0.12.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5"
checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
dependencies = [
"base64",
"bytes",
@@ -743,12 +762,9 @@ dependencies = [
"http-body-util",
"hyper",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"mime_guess",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
@@ -767,9 +783,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustversion"
@@ -882,9 +898,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.15.0"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
@@ -904,9 +920,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.101"
version = "2.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462"
dependencies = [
"proc-macro2",
"quote",
@@ -999,9 +1015,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.4"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [
"bitflags 2.9.1",
"bytes",
@@ -1039,9 +1055,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.33"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
]
@@ -1093,6 +1109,18 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
"getrandom",
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "want"
version = "0.3.1"
@@ -1104,9 +1132,18 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
@@ -1418,6 +1455,15 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.1",
]
[[package]]
name = "writeable"
version = "0.6.1"

View File

@@ -9,4 +9,5 @@ tokio = { version = "1", features = ["full"] }
inquire = { version = "0.7.5", features = ["date"] }
async-trait = "0.1"
dyn-clone = "1.0"
chrono = "0.4"
chrono = "0.4"
uuid = { version = "1.3.0", features = ["serde", "v4"] }

View File

@@ -1,27 +1,20 @@
use std::fmt::Display;
use chrono::{DateTime, Local};
use gamenight_api_client_rs::models;
use uuid::Uuid;
#[derive(Clone)]
pub struct Gamenight {
pub id: Uuid,
pub name: String,
pub start_time: DateTime<Local>
pub start_time: DateTime<Local>,
pub owner_id: Uuid,
}
impl From<models::Gamenight> for Gamenight {
fn from(value: models::Gamenight) -> Self {
Self {
name: value.name,
start_time: DateTime::parse_from_rfc3339(&value.datetime).unwrap().into()
}
}
}
impl Display for Gamenight {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, r#"
write!(f, r#"
Name: {}
When: {}
"#, self.name, self.start_time.format("%d-%m-%Y %H:%M"))
When: {}"#, self.name, self.start_time.format("%d-%m-%Y %H:%M"))
}
}

View File

@@ -1 +1,2 @@
pub mod gamenight;
pub mod gamenight;
pub mod user;

View File

@@ -0,0 +1,7 @@
use uuid::Uuid;
#[derive(Clone)]
pub struct User {
pub id: Uuid,
pub username: String
}

View File

@@ -0,0 +1,34 @@
use std::fmt::Display;
use async_trait::async_trait;
use gamenight_api_client_rs::{apis::default_api::join_post, models::GamenightId};
use uuid::Uuid;
use super::{Flow, FlowOutcome, FlowResult, GamenightState};
#[derive(Clone)]
pub struct Join {
gamenight_id: Uuid
}
impl Join {
pub fn new(gamenight_id: Uuid) -> Self {
Self {
gamenight_id
}
}
}
#[async_trait]
impl<'a> Flow<'a> for Join {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
let _ = join_post(&state.configuration, Some(GamenightId{gamenight_id: self.gamenight_id.to_string()})).await?;
Ok((FlowOutcome::Successful, state))
}
}
impl Display for Join {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Join")
}
}

View File

@@ -1,8 +1,10 @@
use chrono::DateTime;
use gamenight_api_client_rs::apis::default_api::get_gamenights;
use inquire::Select;
use uuid::Uuid;
use crate::flows::view_gamenight::ViewGamenight;
use crate::{domain::{gamenight::Gamenight}, flows::view_gamenight::ViewGamenight};
use super::{exit::Exit, *};
@@ -22,9 +24,18 @@ impl<'a> Flow<'a> for ListGamenights {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
let response = get_gamenights(&state.configuration).await?;
let mut view_flows = response.into_iter().map(|gamenight| -> Box<dyn Flow<'a> + Send> {
Box::new(ViewGamenight::new(gamenight.into()))
}).collect::<Vec<Box<dyn Flow<'a> + Send>>>();
let mut view_flows: Vec<Box<dyn Flow<'_> + Send>> = vec![];
for response in response.iter() {
let gamenight = Gamenight {
id: Uuid::parse_str(&response.id)?,
name: response.name.clone(),
start_time:DateTime::parse_from_rfc3339(&response.datetime)?.into(),
owner_id: Uuid::parse_str(&response.owner_id)?
};
view_flows.push(Box::new(ViewGamenight::new(gamenight)));
}
view_flows.push(Box::new(Exit::new()));
let choice = Select::new("What gamenight would you like to view?", view_flows)
@@ -38,5 +49,4 @@ impl Display for ListGamenights {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "List all gamenights")
}
}
}

View File

@@ -2,7 +2,7 @@ use std::fmt::Display;
use async_trait::async_trait;
use chrono::ParseError;
use gamenight_api_client_rs::apis::configuration::Configuration;
use gamenight_api_client_rs::apis::{configuration::Configuration, Error};
use inquire::InquireError;
use dyn_clone::DynClone;
@@ -13,6 +13,7 @@ mod exit;
mod list_gamenights;
mod add_gamenight;
mod view_gamenight;
mod join;
pub struct GamenightState {
configuration: Configuration,
@@ -45,16 +46,24 @@ impl From<InquireError> for FlowError {
}
}
impl<T> From<gamenight_api_client_rs::apis::Error<T>> for FlowError {
fn from(value: gamenight_api_client_rs::apis::Error<T>) -> Self {
impl From<ParseError> for FlowError {
fn from(value: ParseError) -> Self {
Self {
error: value.to_string()
}
}
}
impl From<ParseError> for FlowError {
fn from(value: ParseError) -> Self {
impl<T> From<Error<T>> for FlowError {
fn from(value: Error<T>) -> Self {
Self {
error: value.to_string()
}
}
}
impl From<uuid::Error> for FlowError {
fn from(value: uuid::Error) -> Self {
Self {
error: value.to_string()
}

View File

@@ -1,7 +1,9 @@
use gamenight_api_client_rs::{apis::default_api::{participants_get, user_get}, models::{GamenightId, UserId}};
use inquire::Select;
use uuid::Uuid;
use crate::{domain::gamenight::Gamenight, flows::exit::Exit};
use crate::{domain::{gamenight::Gamenight, user::User}, flows::{exit::Exit, join::Join}};
use super::*;
@@ -18,12 +20,30 @@ impl ViewGamenight {
}
}
fn vec_user_to_usernames_string(users: Vec<User>) -> String {
let string_list: Vec<String> = users.iter().map(|x| {x.username.clone()}).collect();
string_list.join(", ")
}
#[async_trait]
impl<'a> Flow<'a> for ViewGamenight {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
print!("{}", self.gamenight);
let participants = participants_get(&state.configuration, Some(GamenightId{gamenight_id: self.gamenight.id.to_string()})).await?;
let mut users = vec![];
for participant in participants.participants.iter() {
let user = user_get(&state.configuration, Some(UserId{user_id: participant.clone()})).await?;
users.push(User {
id: Uuid::parse_str(&user.id)?,
username: user.username
});
}
println!("{}\nwho: {}", self.gamenight, vec_user_to_usernames_string(users));
let options: Vec<Box<dyn Flow<'a> + Send>> = vec![
Box::new(Join::new(self.gamenight.id)),
Box::new(Exit::new())
];
let choice = Select::new("What do you want to do:", options)