mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: make server functions work outside of WASM (#643)
This commit is contained in:
parent
b085a6c38e
commit
29fb1842a5
3 changed files with 76 additions and 7 deletions
|
@ -60,6 +60,7 @@ features = [
|
||||||
"HashChangeEvent",
|
"HashChangeEvent",
|
||||||
"InputEvent",
|
"InputEvent",
|
||||||
"KeyboardEvent",
|
"KeyboardEvent",
|
||||||
|
"MessageEvent",
|
||||||
"MouseEvent",
|
"MouseEvent",
|
||||||
"PageTransitionEvent",
|
"PageTransitionEvent",
|
||||||
"PointerEvent",
|
"PointerEvent",
|
||||||
|
|
|
@ -11,9 +11,6 @@ readme = "../README.md"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
server_fn_macro_default = { path = "./server_fn_macro_default", version = "0.2.0" }
|
server_fn_macro_default = { path = "./server_fn_macro_default", version = "0.2.0" }
|
||||||
form_urlencoded = "1"
|
form_urlencoded = "1"
|
||||||
gloo-net = "0.2"
|
|
||||||
js-sys = "0.3"
|
|
||||||
lazy_static = "1"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
@ -25,5 +22,14 @@ cfg-if = "1"
|
||||||
ciborium = "0.2.0"
|
ciborium = "0.2.0"
|
||||||
xxhash-rust = { version = "0.8.6", features = ["const_xxh64"] }
|
xxhash-rust = { version = "0.8.6", features = ["const_xxh64"] }
|
||||||
const_format = "0.2.30"
|
const_format = "0.2.30"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
gloo-net = "0.2"
|
||||||
|
js-sys = "0.3"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
reqwest = "0.11.14"
|
||||||
|
once_cell = "1.17.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
ssr = []
|
ssr = []
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
//!
|
//!
|
||||||
//! **Important**: All server functions must be registered by calling [ServerFn::register_in]
|
//! **Important**: All server functions must be registered by calling [ServerFn::register_in]
|
||||||
//! somewhere within your `main` function.
|
//! somewhere within your `main` function.
|
||||||
|
//! **Important**: Before calling a server function on a non-web platform, you must set the server URL by calling [`set_server_url`].
|
||||||
//!
|
//!
|
||||||
//! ```rust,ignore
|
//! ```rust,ignore
|
||||||
//! #[server(ReadFromDB)]
|
//! #[server(ReadFromDB)]
|
||||||
|
@ -54,6 +55,8 @@
|
||||||
//!
|
//!
|
||||||
//! // make sure you've registered it somewhere in main
|
//! // make sure you've registered it somewhere in main
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
|
//! // for non-web apps, you must set the server URL manually
|
||||||
|
//! server_fn::set_server_url("http://localhost:3000");
|
||||||
//! _ = ReadFromDB::register();
|
//! _ = ReadFromDB::register();
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -353,8 +356,9 @@ where
|
||||||
T: serde::Serialize + serde::de::DeserializeOwned + Sized,
|
T: serde::Serialize + serde::de::DeserializeOwned + Sized,
|
||||||
{
|
{
|
||||||
use ciborium::ser::into_writer;
|
use ciborium::ser::into_writer;
|
||||||
use js_sys::Uint8Array;
|
|
||||||
use serde_json::Deserializer as JSONDeserializer;
|
use serde_json::Deserializer as JSONDeserializer;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let url = format!("{}{}", get_server_url(), url);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Payload {
|
enum Payload {
|
||||||
|
@ -384,10 +388,11 @@ where
|
||||||
Encoding::Cbor => "application/cbor",
|
Encoding::Cbor => "application/cbor",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
let resp = match args_encoded {
|
let resp = match args_encoded {
|
||||||
Payload::Binary(b) => {
|
Payload::Binary(b) => {
|
||||||
let slice_ref: &[u8] = &b;
|
let slice_ref: &[u8] = &b;
|
||||||
let js_array = Uint8Array::from(slice_ref).buffer();
|
let js_array = js_sys::Uint8Array::from(slice_ref).buffer();
|
||||||
gloo_net::http::Request::post(url)
|
gloo_net::http::Request::post(url)
|
||||||
.header("Content-Type", content_type_header)
|
.header("Content-Type", content_type_header)
|
||||||
.header("Accept", accept_header)
|
.header("Accept", accept_header)
|
||||||
|
@ -404,20 +409,55 @@ where
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ServerFnError::Request(e.to_string()))?,
|
.map_err(|e| ServerFnError::Request(e.to_string()))?,
|
||||||
};
|
};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let resp = match args_encoded {
|
||||||
|
Payload::Binary(b) => CLIENT
|
||||||
|
.post(url)
|
||||||
|
.header("Content-Type", content_type_header)
|
||||||
|
.header("Accept", accept_header)
|
||||||
|
.body(b)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ServerFnError::Request(e.to_string()))?,
|
||||||
|
Payload::Url(s) => CLIENT
|
||||||
|
.post(url)
|
||||||
|
.header("Content-Type", content_type_header)
|
||||||
|
.header("Accept", accept_header)
|
||||||
|
.body(s)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ServerFnError::Request(e.to_string()))?,
|
||||||
|
};
|
||||||
|
|
||||||
// check for error status
|
// check for error status
|
||||||
let status = resp.status();
|
let status = resp.status();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let status = status.as_u16();
|
||||||
if (500..=599).contains(&status) {
|
if (500..=599).contains(&status) {
|
||||||
return Err(ServerFnError::ServerError(resp.status_text()));
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
let status_text = resp.status_text();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let status_text = status.to_string();
|
||||||
|
return Err(ServerFnError::ServerError(status_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
if enc == Encoding::Cbor {
|
if enc == Encoding::Cbor {
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
let binary = resp
|
let binary = resp
|
||||||
.binary()
|
.binary()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))?;
|
.map_err(|e| ServerFnError::Deserialization(e.to_string()))?;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
let binary = binary.as_slice();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let binary = resp
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ServerFnError::Deserialization(e.to_string()))?;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let binary = binary.as_ref();
|
||||||
|
|
||||||
ciborium::de::from_reader(binary.as_slice())
|
ciborium::de::from_reader(binary)
|
||||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||||
} else {
|
} else {
|
||||||
let text = resp
|
let text = resp
|
||||||
|
@ -430,3 +470,25 @@ where
|
||||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lazily initialize the client to be reused for all server function calls.
|
||||||
|
#[cfg(any(all(not(feature = "ssr"), not(target_arch = "wasm32")), doc))]
|
||||||
|
static CLIENT: once_cell::sync::Lazy<reqwest::Client> =
|
||||||
|
once_cell::sync::Lazy::new(|| reqwest::Client::new());
|
||||||
|
|
||||||
|
#[cfg(any(all(not(feature = "ssr"), not(target_arch = "wasm32")), doc))]
|
||||||
|
static ROOT_URL: once_cell::sync::OnceCell<&'static str> =
|
||||||
|
once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
|
#[cfg(any(all(not(feature = "ssr"), not(target_arch = "wasm32")), doc))]
|
||||||
|
/// Set the root server url that all server function paths are relative to for the client. On WASM this will default to the origin.
|
||||||
|
pub fn set_server_url(url: &'static str) {
|
||||||
|
ROOT_URL.set(url).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "ssr"), not(target_arch = "wasm32")))]
|
||||||
|
fn get_server_url() -> &'static str {
|
||||||
|
ROOT_URL
|
||||||
|
.get()
|
||||||
|
.expect("Call set_root_url before calling a server function.")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue