diff --git a/AobaClient/.cargo/config.toml b/AobaClient/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/AobaClient/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/AobaClient/Cargo.lock b/AobaClient/Cargo.lock index e45b868..5520202 100644 --- a/AobaClient/Cargo.lock +++ b/AobaClient/Cargo.lock @@ -42,6 +42,7 @@ dependencies = [ "serde_repr", "tonic", "tonic-build", + "tonic-web-wasm-client", ] [[package]] @@ -215,51 +216,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "axum" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" -dependencies = [ - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "itoa 1.0.15", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -2020,25 +1976,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "h2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.9.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.6.0" @@ -2154,12 +2091,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "hyper" version = "1.6.0" @@ -2169,11 +2100,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa 1.0.15", "pin-project-lite", "smallvec", @@ -2181,19 +2110,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.11" @@ -2695,12 +2611,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - [[package]] name = "memchr" version = "2.7.4" @@ -4500,23 +4410,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85839f0b32fd242bb3209262371d07feda6d780d16ee9d2bc88581b89da1549b" dependencies = [ "async-trait", - "axum", "base64", "bytes", - "h2", "http", "http-body", "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", "percent-encoding", "pin-project", "prost", - "socket2", - "tokio", "tokio-stream", - "tower", "tower-layer", "tower-service", "tracing", @@ -4536,6 +4438,31 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "tonic-web-wasm-client" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12abe1160d2a9a3e4bf578e2e37fd8b4f65c5e64fca6037d6f1ed6c0e02a78ac" +dependencies = [ + "base64", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "httparse", + "js-sys", + "pin-project", + "thiserror 2.0.12", + "tonic", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + [[package]] name = "tower" version = "0.5.2" @@ -4544,15 +4471,11 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap 2.9.0", "pin-project-lite", - "slab", "sync_wrapper", "tokio", - "tokio-util", "tower-layer", "tower-service", - "tracing", ] [[package]] diff --git a/AobaClient/Cargo.toml b/AobaClient/Cargo.toml index 29f6ada..f36f8eb 100644 --- a/AobaClient/Cargo.toml +++ b/AobaClient/Cargo.toml @@ -10,11 +10,15 @@ edition = "2021" dioxus = { version = "0.6.0", features = ["router"] } serde = "1.0.219" serde_repr = "0.1.20" -tonic = "*" +tonic = { version = "*", default-features = false, features = [ + "codegen", + "prost", +] } prost = "0.13" +tonic-web-wasm-client = "0.7" [build-dependencies] -tonic-build = "*" +tonic-build = { version = "*", default-features = false, features = ["prost"] } [features] default = ["web"] diff --git a/AobaClient/build.rs b/AobaClient/build.rs index 72d873a..fb2229e 100644 --- a/AobaClient/build.rs +++ b/AobaClient/build.rs @@ -1,6 +1,7 @@ fn main() -> Result<(), Box> { tonic_build::configure() .build_server(false) + .build_client(true) .compile_protos(&["..\\AobaServer\\Proto\\Aoba.proto"], &["..\\AobaServer\\Proto\\"])?; Ok(()) diff --git a/AobaClient/src/components/media_grid.rs b/AobaClient/src/components/media_grid.rs index 3c98f7f..e7e9020 100644 --- a/AobaClient/src/components/media_grid.rs +++ b/AobaClient/src/components/media_grid.rs @@ -1,36 +1,98 @@ -use dioxus::prelude::*; +use std::str::FromStr; -#[component] -pub fn MediaGrid() -> Element { - rsx! { - div{ - class: "mediaGrid", - {(0..50).map(|_| rsx!{ - MediaItem {} - })} +use dioxus::prelude::*; +use tonic::{metadata::MetadataValue, IntoRequest, Request}; + +use crate::rpc::{ + aoba::{MediaModel, PageFilter}, + get_rpc_client, +}; + +#[derive(PartialEq, Clone, Props)] +pub struct MediaGridProps { + pub query: Option, + pub page: Option, + pub page_size: Option, +} + +impl IntoRequest for MediaGridProps { + fn into_request(self) -> tonic::Request { + let f: PageFilter = self.into(); + f.into_request() + } +} + +impl Into for MediaGridProps { + fn into(self) -> PageFilter { + PageFilter { + page: self.page, + page_size: self.page_size, + query: self.query, } } } #[component] -pub fn MediaItem() -> Element { +pub fn MediaGrid(props: MediaGridProps) -> Element { + let media_result = use_resource(|| async move { + let mut client = get_rpc_client(); + let mut req = Request::new(PageFilter::default()); + req.metadata_mut() + .insert("authorization", "Bearer ".parse().unwrap()); + let result = client.list_media(req).await; + return result.expect("Failed to load media").into_inner(); + }); + + match &*media_result.read_unchecked() { + Some(result) => rsx! { + div{ + class: "mediaGrid", + {result.items.iter().map(|itm| rsx!{ + MediaItem { item: itm.clone() } + })} + } + }, + None => rsx!(), + } + // let items = media_result..unwrap().items; + // rsx! { + // div{ + // class: "mediaGrid", + // {items.iter().map(|itm| rsx!{ + // MediaItem { item: itm.clone() } + // })} + // } + // } +} + +#[derive(PartialEq, Clone, Props)] +pub struct MediaItemProps { + pub item: MediaModel, +} + +#[component] +pub fn MediaItem(props: MediaItemProps) -> Element { + let filename = props.item.file_name; + let id = props.item.id.unwrap().value; + let mtype = props.item.media_type.to_string(); + // let url = "https://aoba.app/i/{}"; rsx! { div{ class: "mediaItem", - img{} + img{ src: "https://aoba.app/i/{id}" } div { class: "info", span{ class: "name", - "Filename" + "{filename}" }, div{ class: "details", span{ - "Type" + "{mtype}" }, span{ - "View Count" + "{props.item.view_count}" }, } } diff --git a/AobaClient/src/rpc.rs b/AobaClient/src/rpc.rs index 9b1efb6..6200b61 100644 --- a/AobaClient/src/rpc.rs +++ b/AobaClient/src/rpc.rs @@ -1,7 +1,7 @@ use std::sync::RwLock; use aoba::aoba_rpc_client::AobaRpcClient; -use tonic::transport::Channel; +use tonic_web_wasm_client::Client; pub mod aoba { tonic::include_proto!("aoba"); @@ -13,25 +13,24 @@ static RPC_CLIENT: RpcConnection = RpcConnection { #[derive(Default)] pub struct RpcConnection { - client: RwLock>>, + client: RwLock>>, } impl RpcConnection { - pub async fn get_client(&self) -> AobaRpcClient { - self.ensure_client().await; + pub fn get_client(&self) -> AobaRpcClient { + self.ensure_client(); return self.client.read().unwrap().clone().unwrap(); } - async fn ensure_client(&self) { + fn ensure_client(&self) { if self.client.read().unwrap().is_none() { - let c = AobaRpcClient::connect("http://localhost:5000") - .await - .expect("Failed to connect RPC"); + let wasm_client = Client::new("http://localhost:5164".into()); + let c = AobaRpcClient::new(wasm_client); *self.client.write().unwrap() = Some(c); } } } -pub async fn get_rpc_client() -> AobaRpcClient { - return RPC_CLIENT.get_client().await; +pub fn get_rpc_client() -> AobaRpcClient { + return RPC_CLIENT.get_client(); } diff --git a/AobaClient/src/views/home.rs b/AobaClient/src/views/home.rs index f4996f5..16bd59a 100644 --- a/AobaClient/src/views/home.rs +++ b/AobaClient/src/views/home.rs @@ -5,7 +5,6 @@ use dioxus::prelude::*; pub fn Home() -> Element { rsx! { div { id: "content", - "This is home" Search { }, MediaGrid { } } diff --git a/AobaClient/src/views/login.rs b/AobaClient/src/views/login.rs index d98cf85..1961c51 100644 --- a/AobaClient/src/views/login.rs +++ b/AobaClient/src/views/login.rs @@ -9,7 +9,7 @@ pub fn Login() -> Element { id: "centralModal", form{ Input { type : "text", name: "username", label: "Username" }, - Input{ type : "password", name: "password", label: "Password" }, + Input { type : "password", name: "password", label: "Password" }, Button{text: "Login!"} } }