Add card table loading
This commit is contained in:
@@ -39,9 +39,9 @@ polars = { version = "0.39.2", default-features = false, features = [
|
|||||||
fantoccini = "0.19"
|
fantoccini = "0.19"
|
||||||
|
|
||||||
[target.'cfg(engine)'.dependencies]
|
[target.'cfg(engine)'.dependencies]
|
||||||
|
axum = { version = "0.6", features = ["macros"] }
|
||||||
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
|
||||||
perseus-axum = { version = "0.4.2" }
|
perseus-axum = { version = "0.4.2" }
|
||||||
axum = "0.6"
|
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
sea-orm = { version = "1.0", features = [
|
sea-orm = { version = "1.0", features = [
|
||||||
"sqlx-postgres",
|
"sqlx-postgres",
|
||||||
@@ -60,3 +60,6 @@ sea-orm = { version = "1.0" }
|
|||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(engine)', 'cfg(client)'] }
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(engine)', 'cfg(client)'] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ use crate::{
|
|||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(client)] {
|
||||||
|
use crate::endpoints::CARD_INFO;
|
||||||
|
use crate::templates::get_api_path;
|
||||||
|
use crate::models::card::CardTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Prop)]
|
#[derive(Prop)]
|
||||||
pub struct LayoutProps<'a, G: Html> {
|
pub struct LayoutProps<'a, G: Html> {
|
||||||
pub content_state: ContentState,
|
pub content_state: ContentState,
|
||||||
@@ -51,12 +59,42 @@ pub fn Layout<'a, G: Html>(
|
|||||||
|
|
||||||
let content_state_header = content_state.clone();
|
let content_state_header = content_state.clone();
|
||||||
|
|
||||||
|
#[cfg(client)]
|
||||||
|
{
|
||||||
|
// TODO -> try to use suspense
|
||||||
|
spawn_local_scoped(cx, async move {
|
||||||
|
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
|
||||||
|
let card_table_loaded = (*global_state.constants.is_loaded.get()).clone();
|
||||||
|
if !card_table_loaded {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let response = client
|
||||||
|
.get(get_api_path(CARD_INFO).as_str())
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// TODO add error handling
|
||||||
|
let response = response.json::<CardTable>().await.unwrap();
|
||||||
|
global_state.constants.card_table.set(Some(response));
|
||||||
|
global_state.constants.is_loaded.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
view! { cx,
|
view! { cx,
|
||||||
// Main page header, including login functionality
|
// Main page header, including login functionality
|
||||||
Header(content_state = content_state_header)
|
Header(content_state = content_state_header)
|
||||||
|
|
||||||
// Modals
|
// Modals
|
||||||
section(class = "flex-2") {
|
section(class = "flex-2") {
|
||||||
|
(match (*global_state.constants.card_table.get()).clone() {
|
||||||
|
Some(card_table) => { view!{ cx,
|
||||||
|
p { "DONE" }
|
||||||
|
} },
|
||||||
|
None => { view!{ cx, p { "Loading cards" } } },
|
||||||
|
})
|
||||||
|
|
||||||
(match *global_state.modals_open.login.get() {
|
(match *global_state.modals_open.login.get() {
|
||||||
OpenState::Open => {
|
OpenState::Open => {
|
||||||
view! { cx,
|
view! { cx,
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ pub const LOGIN: &str = "/api/login";
|
|||||||
#[cfg(engine)]
|
#[cfg(engine)]
|
||||||
pub const LOGIN_TEST: &str = "/api/login-test";
|
pub const LOGIN_TEST: &str = "/api/login-test";
|
||||||
pub const FORGOT_PASSWORD: &str = "/api/forgot-password";
|
pub const FORGOT_PASSWORD: &str = "/api/forgot-password";
|
||||||
|
pub const CARD_INFO: &str = "/api/card-info";
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ use perseus::{prelude::*, state::GlobalStateCreator};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::auth::WebAuthInfo,
|
models::{auth::WebAuthInfo, card::CardTable},
|
||||||
state_enums::{LoginState, OpenState},
|
state_enums::{LoginState, OpenState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
#[rx(alias = "AppStateRx")]
|
#[rx(alias = "AppStateRx")]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
#[rx(nested)]
|
||||||
|
pub constants: ConstData,
|
||||||
#[rx(nested)]
|
#[rx(nested)]
|
||||||
pub auth: AuthData,
|
pub auth: AuthData,
|
||||||
#[rx(nested)]
|
#[rx(nested)]
|
||||||
@@ -19,6 +22,13 @@ pub struct AppState {
|
|||||||
pub style: StyleData,
|
pub style: StyleData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
|
#[rx(alias = "ConstDataRx")]
|
||||||
|
pub struct ConstData {
|
||||||
|
pub is_loaded: bool,
|
||||||
|
pub card_table: Option<CardTable>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
#[rx(alias = "AuthDataRx")]
|
#[rx(alias = "AuthDataRx")]
|
||||||
pub struct AuthData {
|
pub struct AuthData {
|
||||||
@@ -58,6 +68,10 @@ pub fn get_global_state_creator() -> GlobalStateCreator {
|
|||||||
#[engine_only_fn]
|
#[engine_only_fn]
|
||||||
pub async fn get_build_state() -> AppState {
|
pub async fn get_build_state() -> AppState {
|
||||||
AppState {
|
AppState {
|
||||||
|
constants: ConstData {
|
||||||
|
is_loaded: false,
|
||||||
|
card_table: None
|
||||||
|
},
|
||||||
auth: AuthData {
|
auth: AuthData {
|
||||||
state: LoginState::Unknown,
|
state: LoginState::Unknown,
|
||||||
pending_username: String::new(),
|
pending_username: String::new(),
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ pub enum MonsterAttribute {
|
|||||||
Light,
|
Light,
|
||||||
Water,
|
Water,
|
||||||
Wind,
|
Wind,
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@@ -51,13 +52,14 @@ pub enum TrapType {
|
|||||||
Normal,
|
Normal,
|
||||||
Continuous,
|
Continuous,
|
||||||
Counter,
|
Counter,
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub enum CardTypeInfo {
|
pub enum CardTypeInfo {
|
||||||
Monster {
|
Monster {
|
||||||
level: u32, // level/rank/link rating
|
level: Option<u32>, // level/rank/link rating
|
||||||
atk: u32,
|
atk: Option<u32>,
|
||||||
def: Option<u32>,
|
def: Option<u32>,
|
||||||
pendulum_scale: Option<u32>,
|
pendulum_scale: Option<u32>,
|
||||||
attribute: MonsterAttribute,
|
attribute: MonsterAttribute,
|
||||||
@@ -170,16 +172,16 @@ impl CardTable {
|
|||||||
"Continuous" => TrapType::Continuous,
|
"Continuous" => TrapType::Continuous,
|
||||||
"Counter" => TrapType::Counter,
|
"Counter" => TrapType::Counter,
|
||||||
"Normal" => TrapType::Normal,
|
"Normal" => TrapType::Normal,
|
||||||
unknown => panic!("Unknown trap type {}", unknown),
|
_ => TrapType::Unknown,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CardTypeInfo::Monster {
|
CardTypeInfo::Monster {
|
||||||
level: row[level_idx].try_extract().unwrap(),
|
level: row[level_idx].try_extract().ok(),
|
||||||
atk: row[atk_idx].try_extract().unwrap(),
|
atk: row[atk_idx].try_extract().ok(),
|
||||||
def: row[def_idx].try_extract().ok(),
|
def: row[def_idx].try_extract().ok(),
|
||||||
pendulum_scale: row[pendulum_scale_idx].try_extract().ok(),
|
pendulum_scale: row[pendulum_scale_idx].try_extract().ok(),
|
||||||
attribute: match row[attribute_idx].get_str().unwrap() {
|
attribute: match row[attribute_idx].get_str().unwrap_or("NONE") {
|
||||||
"DARK" => MonsterAttribute::Dark,
|
"DARK" => MonsterAttribute::Dark,
|
||||||
"DIVINE" => MonsterAttribute::Divine,
|
"DIVINE" => MonsterAttribute::Divine,
|
||||||
"EARTH" => MonsterAttribute::Earth,
|
"EARTH" => MonsterAttribute::Earth,
|
||||||
@@ -187,6 +189,7 @@ impl CardTable {
|
|||||||
"LIGHT" => MonsterAttribute::Light,
|
"LIGHT" => MonsterAttribute::Light,
|
||||||
"WATER" => MonsterAttribute::Water,
|
"WATER" => MonsterAttribute::Water,
|
||||||
"WIND" => MonsterAttribute::Wind,
|
"WIND" => MonsterAttribute::Wind,
|
||||||
|
"NONE" => MonsterAttribute::None,
|
||||||
unknown => panic!("Unknown attribute {}", unknown),
|
unknown => panic!("Unknown attribute {}", unknown),
|
||||||
},
|
},
|
||||||
monster_type: row[monster_type_idx]
|
monster_type: row[monster_type_idx]
|
||||||
@@ -390,18 +393,14 @@ impl CardTable {
|
|||||||
"frameType",
|
"frameType",
|
||||||
"ygoprodeck_url",
|
"ygoprodeck_url",
|
||||||
"linkval",
|
"linkval",
|
||||||
"race"
|
"race",
|
||||||
])])
|
])])
|
||||||
// Remove link markers, unless it's needed later
|
// Remove link markers, unless it's needed later
|
||||||
.select([col("*").exclude(["linkmarkers"])])
|
.select([col("*").exclude(["linkmarkers"])])
|
||||||
// TODO add banlist support
|
// TODO add banlist support
|
||||||
.select([col("*").exclude(["banlist_info"])])
|
.select([col("*").exclude(["banlist_info"])])
|
||||||
// TODO readd
|
// TODO readd
|
||||||
.select([col("*").exclude([
|
.select([col("*").exclude(["card_sets", "card_images", "card_prices"])])
|
||||||
"card_sets",
|
|
||||||
"card_images",
|
|
||||||
"card_prices",
|
|
||||||
])])
|
|
||||||
// Filter out "Skill Card"
|
// Filter out "Skill Card"
|
||||||
.filter(col("type").str().contains(lit("Skill Card"), false).not())
|
.filter(col("type").str().contains(lit("Skill Card"), false).not())
|
||||||
// Filters for testing
|
// Filters for testing
|
||||||
|
|||||||
18
src/server/constants/card_table.rs
Normal file
18
src/server/constants/card_table.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::server::server_state::ServerState;
|
||||||
|
use axum::{debug_handler, extract::State, http::StatusCode, Json};
|
||||||
|
|
||||||
|
use crate::models::card::CardTable;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CARD_TABLE: CardTable =
|
||||||
|
CardTable::new_from_server_json(Path::new("./data/cardinfo.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub async fn get_card_table(State(_): State<ServerState>) -> Result<Json<CardTable>, StatusCode> {
|
||||||
|
Ok(Json(CARD_TABLE.clone()))
|
||||||
|
}
|
||||||
1
src/server/constants/mod.rs
Normal file
1
src/server/constants/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod card_table;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod constants;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
pub mod server_state;
|
pub mod server_state;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// (Server only) Routes
|
// (Server only) Routes
|
||||||
use crate::endpoints::{FORGOT_PASSWORD, LOGIN, LOGIN_TEST, REGISTER};
|
use crate::endpoints::{CARD_INFO, FORGOT_PASSWORD, LOGIN, LOGIN_TEST, REGISTER};
|
||||||
use axum::routing::{post, Router};
|
use axum::routing::{get, post, Router};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
auth::{
|
auth::{
|
||||||
@@ -8,6 +8,7 @@ use super::{
|
|||||||
login::{post_login_user, post_test_login},
|
login::{post_login_user, post_test_login},
|
||||||
register::post_register_user,
|
register::post_register_user,
|
||||||
},
|
},
|
||||||
|
constants::card_table::get_card_table,
|
||||||
server_state::ServerState,
|
server_state::ServerState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -17,5 +18,6 @@ pub fn get_api_router(state: ServerState) -> Router {
|
|||||||
.route(LOGIN, post(post_login_user))
|
.route(LOGIN, post(post_login_user))
|
||||||
.route(LOGIN_TEST, post(post_test_login))
|
.route(LOGIN_TEST, post(post_test_login))
|
||||||
.route(FORGOT_PASSWORD, post(post_forgot_password))
|
.route(FORGOT_PASSWORD, post(post_forgot_password))
|
||||||
|
.route(CARD_INFO, get(get_card_table))
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
// Not a page, global state that is shared between all pages
|
|
||||||
|
|
||||||
use perseus::{prelude::*, state::GlobalStateCreator};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::data::card::CardTable;
|
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(engine)] {
|
|
||||||
use std::thread;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use crate::data::store::DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
|
||||||
#[rx(alias = "AppStateRx")]
|
|
||||||
pub struct AppState {
|
|
||||||
pub card_table: CardTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
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 card_table = thread::spawn(move || DATA.lock().unwrap().deref().card_table.clone())
|
|
||||||
.join()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
AppState { card_table }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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()
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user