From 0a68829d6cc07ba9f9f0a3a16d8909117535b8e4 Mon Sep 17 00:00:00 2001 From: matkam7 Date: Thu, 21 Sep 2023 20:03:16 -0400 Subject: [PATCH] Add working API calls, fix warnings --- Cargo.toml | 3 +- src/components/layout.rs | 2 +- src/data/mod.rs | 3 +- src/data/store.rs | 8 ++-- src/endpoints.rs | 2 + src/handler/mod.rs | 20 ++++++++++ src/main.rs | 30 +++++--------- src/templates/add_game_form.rs | 67 +++++++++++++++++++++----------- src/templates/global_state.rs | 47 ++++++++++++++++++++++ src/templates/mod.rs | 11 +++--- src/templates/one_v_one_board.rs | 4 +- src/templates/overall_board.rs | 19 +++------ 12 files changed, 147 insertions(+), 69 deletions(-) create mode 100644 src/endpoints.rs create mode 100644 src/handler/mod.rs create mode 100644 src/templates/global_state.rs diff --git a/Cargo.toml b/Cargo.toml index 08bf1cd..f87e447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ env_logger = "0.10.0" log = "0.4.20" once_cell = "1.18.0" web-sys = "0.3.64" +cfg-if = { version = "1.0.0", features = [] } [target.'cfg(engine)'.dev-dependencies] @@ -26,4 +27,4 @@ tower-http = { version = "0.3", features = [ "fs" ] } [target.'cfg(client)'.dependencies] wasm-bindgen = "0.2" -reqwest = "0.11" +reqwest = { version = "0.11", features = ["json"] } diff --git a/src/components/layout.rs b/src/components/layout.rs index 383ac75..bf10903 100644 --- a/src/components/layout.rs +++ b/src/components/layout.rs @@ -11,7 +11,7 @@ pub struct LayoutProps<'a, G: Html> { #[component] pub fn Layout<'a, G: Html>( cx: Scope<'a>, - LayoutProps { title, children }: LayoutProps<'a, G>, + LayoutProps { title: _, children }: LayoutProps<'a, G>, ) -> View { let children = children.call(cx); diff --git a/src/data/mod.rs b/src/data/mod.rs index e7ca638..469501c 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,3 +1,4 @@ pub mod pool_match; + +#[cfg(engine)] pub mod store; -pub mod global_state; diff --git a/src/data/store.rs b/src/data/store.rs index f1016b9..06abbe6 100644 --- a/src/data/store.rs +++ b/src/data/store.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; + use once_cell::sync::Lazy; use std::sync::Mutex; use serde::{Serialize, Deserialize}; -use crate::data::pool_match::{PoolMatchList, PoolMatch}; +use crate::data::pool_match::PoolMatchList; use std::fs; use std::path::Path; @@ -14,7 +14,7 @@ pub struct Store { impl Store { fn new() -> Store { - fs::create_dir_all("data"); + fs::create_dir_all("data").unwrap(); match Path::new("data/store.json").exists() { false => { Store { @@ -27,6 +27,8 @@ impl Store { } } } + // TODO -> Store data + #[allow(dead_code)] pub fn write(&self) { let contents = serde_json::to_string(&self).unwrap(); fs::write("data/store.json", contents).unwrap(); diff --git a/src/endpoints.rs b/src/endpoints.rs new file mode 100644 index 0000000..37504c6 --- /dev/null +++ b/src/endpoints.rs @@ -0,0 +1,2 @@ + +pub const MATCH: &str = "/api/post-match"; diff --git a/src/handler/mod.rs b/src/handler/mod.rs new file mode 100644 index 0000000..3b8b579 --- /dev/null +++ b/src/handler/mod.rs @@ -0,0 +1,20 @@ +use axum::{ + extract::Json, +}; +use crate::data::pool_match::{PoolMatch, PoolMatchList}; +use std::thread; +use crate::data::store::DATA; + +pub async fn post_match(Json(pool_match): Json) -> Json { + // Update the store with the new match + let matches = thread::spawn(move || { + // Get the store + let mut store = DATA.lock().unwrap(); + // Add the match + (*store).matches.pool_matches.push(pool_match); + // Return all pool matches + (*store).matches.clone() + }).join().unwrap(); + + Json(matches) +} diff --git a/src/main.rs b/src/main.rs index 116d524..cec2899 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,38 +2,28 @@ mod components; mod templates; mod data; mod error_views; +#[cfg(engine)] +mod handler; +mod endpoints; use perseus::prelude::*; use sycamore::prelude::view; #[cfg(engine)] -use axum::{ - body::Body, - extract::{Path, Query}, - http::{Request, StatusCode}, - response::{IntoResponse, Response}, - routing::{get, get_service}, - Router, -}; -#[cfg(engine)] -use perseus::turbine::ApiResponse as PerseusApiResponse; +use axum::routing::post; #[cfg(engine)] use perseus::{ i18n::TranslationsManager, - path::*, server::ServerOptions, stores::MutableStore, - turbine::{SubsequentLoadQueryParams, Turbine}, + turbine::Turbine, }; #[cfg(engine)] -use tower_http::services::{ServeDir, ServeFile}; +use crate::endpoints::MATCH; +#[cfg(engine)] +use crate::handler::post_match; - -async fn print_something() { - println!("haha"); -} - #[cfg(engine)] pub async fn dflt_server( turbine: &'static Turbine, @@ -46,7 +36,7 @@ pub async fn dflt_server() -> PerseusApp { env_logger::init(); PerseusApp::new() - .global_state_creator(crate::data::global_state::get_global_state_creator()) + .global_state_creator(crate::templates::global_state::get_global_state_creator()) .template(crate::templates::index::get_template()) .template(crate::templates::add_game_form::get_template()) .template(crate::templates::one_v_one_board::get_template()) diff --git a/src/templates/add_game_form.rs b/src/templates/add_game_form.rs index 017e798..6ec07bd 100644 --- a/src/templates/add_game_form.rs +++ b/src/templates/add_game_form.rs @@ -1,47 +1,70 @@ -use std::ops::Deref; use crate::components::layout::Layout; use perseus::prelude::*; use serde::{Deserialize, Serialize}; use sycamore::prelude::*; -use crate::data::global_state::AppStateRx; -use web_sys::{window, Event}; -use crate::data::pool_match::PoolMatch; -#[cfg(client)] -use perseus::utils::get_path_prefix_client; -use crate::templates::get_api_path; +use web_sys::{Event}; + +cfg_if::cfg_if! { + if #[cfg(client)] { + use crate::data::pool_match::{PoolMatch, PoolMatchList}; + use crate::templates::global_state::AppStateRx; + use crate::endpoints::MATCH; + use crate::templates::get_api_path; + } +} // Reactive page #[derive(Serialize, Deserialize, Clone, ReactiveState)] #[rx(alias = "PageStateRx")] -struct PageState {} - +struct PageState { + name: String, +} fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStateRx) -> View { - let global_state = Reactor::::from_cx(cx).get_global_state::(cx); - let api_path = get_api_path("/api/test"); - let handle_add_match = move |event: Event| { + let handle_add_match = move |_event: Event| { #[cfg(client)] { - let path = get_api_path("/api/test"); - println!("{}", path); spawn_local_scoped(cx, async move { - reqwest::get(get_api_path("/api/test").as_str()).await.unwrap(); + let new_match = PoolMatch { + players: vec![], + winner: state.name.get().as_ref().clone(), + }; + + let client = reqwest::Client::new(); + let new_matches = client.post(get_api_path(MATCH).as_str()) + .json(&new_match) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + let global_state = Reactor::::from_cx(cx).get_global_state::(cx); + global_state.matches.set(new_matches); + }) } }; view! { cx, Layout(title = "Add Game Results") { - // Anything we put in here will be rendered inside the `
` block of the layout - button(on:click=handle_add_match) { - "Add result" + div (class = "flex flex-wrap") { + input (bind:value = state.name, + class = "appearance-none block w-full bg-gray-200 text-gray-700 border \ + border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none \ + focus:bg-white",) } - p { - (api_path) + div (class = "flex flex-wrap") { + button(on:click = handle_add_match, + class = "flex-shrink-0 bg-teal-500 hover:bg-teal-700 border-teal-500 \ + hover:border-teal-700 text-sm border-4 text-white py-1 px-2 rounded", + ) { + "Add result" + } } } } @@ -50,9 +73,9 @@ fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat #[engine_only_fn] async fn get_request_state( _info: StateGeneratorInfo<()>, - req: Request, + _req: Request, ) -> Result> { - Ok(PageState {}) + Ok(PageState { name: "Ferris".to_string() }) } #[engine_only_fn] diff --git a/src/templates/global_state.rs b/src/templates/global_state.rs new file mode 100644 index 0000000..642b2aa --- /dev/null +++ b/src/templates/global_state.rs @@ -0,0 +1,47 @@ +use perseus::{prelude::*, state::GlobalStateCreator}; +use serde::{Deserialize, Serialize}; + +cfg_if::cfg_if! { + if #[cfg(engine)] { + use std::thread; + use std::ops::Deref; + } +} + +#[cfg(engine)] +use crate::data::store::DATA; +use crate::data::pool_match::PoolMatchList; + +#[derive(Serialize, Deserialize, ReactiveState, Clone)] +#[rx(alias = "AppStateRx")] +pub struct AppState { + pub matches: PoolMatchList, +} + +pub fn get_global_state_creator() -> GlobalStateCreator { + GlobalStateCreator::new() + .build_state_fn(get_build_state) + .request_state_fn(get_request_state) +} + +#[engine_only_fn] +fn get_state() -> AppState { + let matches = thread::spawn(move || { + DATA.lock().unwrap().deref().matches.clone() + }).join().unwrap(); + + AppState { + matches + } +} + + +#[engine_only_fn] +pub async fn get_build_state() -> AppState { + get_state() +} + +#[engine_only_fn] +pub async fn get_request_state(_req: Request) -> AppState { + get_state() +} diff --git a/src/templates/mod.rs b/src/templates/mod.rs index 19b6c4e..f2368c1 100644 --- a/src/templates/mod.rs +++ b/src/templates/mod.rs @@ -2,10 +2,12 @@ pub mod index; pub mod add_game_form; pub mod one_v_one_board; pub mod overall_board; +pub mod global_state; #[cfg(client)] use perseus::utils::get_path_prefix_client; +#[allow(dead_code)] pub fn get_api_path(path: &str) -> String { #[cfg(engine)] { @@ -13,9 +15,8 @@ pub fn get_api_path(path: &str) -> String { } #[cfg(client)] { - let path = web_sys::window().unwrap().location().pathname().unwrap(); - // let base_path = get_path_prefix_client(); - // format!("{}{}", base_path, path) - path.to_string() + let origin = web_sys::window().unwrap().origin(); + let base_path = get_path_prefix_client(); + format!("{}{}{}", origin, base_path, path) } -} \ No newline at end of file +} diff --git a/src/templates/one_v_one_board.rs b/src/templates/one_v_one_board.rs index 787cffb..570e763 100644 --- a/src/templates/one_v_one_board.rs +++ b/src/templates/one_v_one_board.rs @@ -11,7 +11,7 @@ struct PageState { } -fn one_v_one_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStateRx) -> View { +fn one_v_one_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, _state: &'a PageStateRx) -> View { view! { cx, Layout(title = "1v1 Leaderboard") { // Anything we put in here will be rendered inside the `
` block of the layout @@ -23,7 +23,7 @@ fn one_v_one_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageSt #[engine_only_fn] async fn get_request_state( _info: StateGeneratorInfo<()>, - req: Request, + _req: Request, ) -> Result> { Ok(PageState {}) } diff --git a/src/templates/overall_board.rs b/src/templates/overall_board.rs index f8024cf..c3ab4bb 100644 --- a/src/templates/overall_board.rs +++ b/src/templates/overall_board.rs @@ -1,16 +1,8 @@ use crate::components::layout::Layout; use perseus::prelude::*; use serde::{Deserialize, Serialize}; -#[cfg(engine)] -use crate::data::store::DATA; -#[cfg(engine)] -use std::thread; use sycamore::prelude::*; -use crate::data::global_state::AppStateRx; - -use crate::data::pool_match::{ - PoolMatchList, PoolMatch -}; +use crate::templates::global_state::AppStateRx; // Reactive page @@ -20,7 +12,7 @@ struct PageState { } -fn overall_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStateRx) -> View { +fn overall_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, _state: &'a PageStateRx) -> View { let global_state = Reactor::::from_cx(cx).get_global_state::(cx); view! { cx, @@ -28,13 +20,12 @@ fn overall_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat // Anything we put in here will be rendered inside the `
` block of the layout ul { (View::new_fragment( - global_state.store.get() - .matches + global_state.matches.get() .pool_matches .iter() .rev() .enumerate() - .map(|(index, item)| { + .map(|(_index, item)| { let game = item.clone(); view! { cx, li { @@ -52,7 +43,7 @@ fn overall_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat #[engine_only_fn] async fn get_request_state( _info: StateGeneratorInfo<()>, - req: Request, + _req: Request, ) -> Result> { Ok(PageState {}) }