feat: implement MessagePack codec for server functions
Some checks failed
Build MIPS Binary / build (push) Failing after 1m12s
Some checks failed
Build MIPS Binary / build (push) Failing after 1m12s
This commit is contained in:
111
shared/src/codec.rs
Normal file
111
shared/src/codec.rs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
use leptos::server_fn::codec::{Encoding, FromReq, FromRes, IntoReq, IntoRes};
|
||||||
|
use leptos::server_fn::request::{ClientReq, Req};
|
||||||
|
use leptos::server_fn::response::{ClientRes, Res};
|
||||||
|
use leptos::server_fn::error::ServerFnError;
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
pub struct MessagePack;
|
||||||
|
|
||||||
|
impl Encoding for MessagePack {
|
||||||
|
const CONTENT_TYPE: &'static str = "application/msgpack";
|
||||||
|
const METHOD: leptos::server_fn::request::Method = leptos::server_fn::request::Method::POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "ssr", feature = "hydrate"))]
|
||||||
|
impl<Input, Output> IntoReq<MessagePack, Input, Output> for MessagePack
|
||||||
|
where
|
||||||
|
Input: Serialize + Send,
|
||||||
|
Output: Send,
|
||||||
|
{
|
||||||
|
fn into_req(args: Input, path: &str) -> Result<ClientReq, ServerFnError> {
|
||||||
|
let data = rmp_serde::to_vec(&args)
|
||||||
|
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||||
|
|
||||||
|
// ClientReq is typically http::Request or similar.
|
||||||
|
// If ClientReq::new(method, path) doesn't exist, check if ClientReq is alias for Request.
|
||||||
|
// In leptos 0.8+, ClientReq::try_new(method, uri, body) is available via trait extension usually or direct impl.
|
||||||
|
// Actually, ClientReq IS http::Request in server/ssr, and gloo_net::Request in hydrate (often).
|
||||||
|
|
||||||
|
// Let's assume ClientReq::post(path).body(...) or similar builders.
|
||||||
|
// Or if it's http::Request:
|
||||||
|
// http::Request::builder().method("POST").uri(path).header(...).body(data)
|
||||||
|
|
||||||
|
// But ClientReq type differs between Features.
|
||||||
|
// Let's try to use `ClientReq` assuming it has `try_new` as seen in other codecs (Json).
|
||||||
|
// If that fails, I will use conditional compilation for specific types.
|
||||||
|
|
||||||
|
// The error "expected a type, found a trait" suggests `ClientReq` handles differently.
|
||||||
|
// Let's look at `Json` codec usage pattern if possible - I can't read source.
|
||||||
|
|
||||||
|
// Let's try constructing via builder if available.
|
||||||
|
// Or better, let's look at what `ClientReq` is.
|
||||||
|
// In `leptos_server_fn::request`, `ClientReq` is public type alias.
|
||||||
|
|
||||||
|
// If I use `ClientReq::try_new`, I need it to be available.
|
||||||
|
// Let's try `ClientReq::new` again but verify imports.
|
||||||
|
// Maybe I need to import `http::Method`?
|
||||||
|
|
||||||
|
// Let's try using `http::Request` explicitly if possible, or just construct it.
|
||||||
|
// If `ClientReq` is `http::Request`, `ClientReq::builder()` works.
|
||||||
|
|
||||||
|
let req = ClientReq::builder()
|
||||||
|
.method("POST")
|
||||||
|
.uri(path)
|
||||||
|
.header("Content-Type", "application/msgpack")
|
||||||
|
.header("Accept", "application/msgpack")
|
||||||
|
.body(bytes::Bytes::from(data))
|
||||||
|
.map_err(|e| ServerFnError::Request(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "ssr", feature = "hydrate"))]
|
||||||
|
impl<Input, Output> FromRes<MessagePack, Input, Output> for MessagePack
|
||||||
|
where
|
||||||
|
Input: Send,
|
||||||
|
Output: DeserializeOwned + Send,
|
||||||
|
{
|
||||||
|
fn from_res(res: ClientRes) -> impl Future<Output = Result<Output, ServerFnError>> + Send {
|
||||||
|
async move {
|
||||||
|
let data = res.try_into_bytes().await?;
|
||||||
|
rmp_serde::from_slice(&data)
|
||||||
|
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl<Input, Output> FromReq<MessagePack, Input, Output> for MessagePack
|
||||||
|
where
|
||||||
|
Input: DeserializeOwned + Send,
|
||||||
|
Output: Send,
|
||||||
|
{
|
||||||
|
fn from_req(req: Req) -> impl Future<Output = Result<Input, ServerFnError>> + Send {
|
||||||
|
async move {
|
||||||
|
let body_bytes = req.try_into_bytes().await?;
|
||||||
|
rmp_serde::from_slice(&body_bytes)
|
||||||
|
.map_err(|e| ServerFnError::Args(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl<Input, Output> IntoRes<MessagePack, Input, Output> for MessagePack
|
||||||
|
where
|
||||||
|
Input: Send,
|
||||||
|
Output: Serialize + Send,
|
||||||
|
{
|
||||||
|
fn into_res(res: Output) -> impl Future<Output = Result<Res, ServerFnError>> + Send {
|
||||||
|
async move {
|
||||||
|
let data = rmp_serde::to_vec(&res)
|
||||||
|
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||||
|
|
||||||
|
let mut res = Res::new(200);
|
||||||
|
res.try_set_header("Content-Type", "application/msgpack")?;
|
||||||
|
res.try_set_body(bytes::Bytes::from(data))?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ pub mod xmlrpc;
|
|||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
|
pub mod codec;
|
||||||
|
|
||||||
pub mod server_fns;
|
pub mod server_fns;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::codec::MessagePack;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct UserResponse {
|
pub struct UserResponse {
|
||||||
@@ -19,7 +20,7 @@ pub struct SetupStatus {
|
|||||||
pub completed: bool,
|
pub completed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(GetSetupStatus, "/api/server_fns/GetSetupStatus")]
|
#[server(GetSetupStatus, "/api/server_fns/GetSetupStatus", encoding = "MessagePack")]
|
||||||
pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
||||||
use crate::DbContext;
|
use crate::DbContext;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(Setup, "/api/server_fns/Setup")]
|
#[server(Setup, "/api/server_fns/Setup", encoding = "MessagePack")]
|
||||||
pub async fn setup(username: String, password: String) -> Result<(), ServerFnError> {
|
pub async fn setup(username: String, password: String) -> Result<(), ServerFnError> {
|
||||||
use crate::DbContext;
|
use crate::DbContext;
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ pub async fn setup(username: String, password: String) -> Result<(), ServerFnErr
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(Login, "/api/server_fns/Login")]
|
#[server(Login, "/api/server_fns/Login", encoding = "MessagePack")]
|
||||||
pub async fn login(username: String, password: String) -> Result<UserResponse, ServerFnError> {
|
pub async fn login(username: String, password: String) -> Result<UserResponse, ServerFnError> {
|
||||||
use crate::DbContext;
|
use crate::DbContext;
|
||||||
use leptos_axum::ResponseOptions;
|
use leptos_axum::ResponseOptions;
|
||||||
@@ -110,7 +111,7 @@ pub async fn login(username: String, password: String) -> Result<UserResponse, S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(Logout, "/api/server_fns/Logout")]
|
#[server(Logout, "/api/server_fns/Logout", encoding = "MessagePack")]
|
||||||
pub async fn logout() -> Result<(), ServerFnError> {
|
pub async fn logout() -> Result<(), ServerFnError> {
|
||||||
use leptos_axum::ResponseOptions;
|
use leptos_axum::ResponseOptions;
|
||||||
use cookie::{Cookie, SameSite};
|
use cookie::{Cookie, SameSite};
|
||||||
@@ -131,7 +132,7 @@ pub async fn logout() -> Result<(), ServerFnError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(GetUser, "/api/server_fns/GetUser")]
|
#[server(GetUser, "/api/server_fns/GetUser", encoding = "MessagePack")]
|
||||||
pub async fn get_user() -> Result<Option<UserResponse>, ServerFnError> {
|
pub async fn get_user() -> Result<Option<UserResponse>, ServerFnError> {
|
||||||
use axum::http::HeaderMap;
|
use axum::http::HeaderMap;
|
||||||
use leptos_axum::extract;
|
use leptos_axum::extract;
|
||||||
|
|||||||
Reference in New Issue
Block a user