#![allow(deprecated)]
use base64::{engine::general_purpose::URL_SAFE, Engine as _};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
fmt::{self, Display, Write},
str::FromStr,
};
use thiserror::Error;
use throw_error::Error;
use url::Url;
pub const SERVER_FN_ERROR_HEADER: &str = "serverfnerror";
impl From<ServerFnError> for Error {
fn from(e: ServerFnError) -> Self {
Error::from(ServerFnErrorWrapper(e))
}
}
#[derive(
Debug,
Deserialize,
Serialize,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Clone,
Copy,
)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[deprecated(
since = "0.8.0",
note = "Now server_fn can return any error type other than ServerFnError, \
so the WrappedServerError variant will be removed in 0.9.0"
)]
pub struct NoCustomError;
impl fmt::Display for NoCustomError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Unit Type Displayed")
}
}
impl FromStr for NoCustomError {
type Err = ();
fn from_str(_s: &str) -> Result<Self, Self::Err> {
Ok(NoCustomError)
}
}
#[derive(Debug)]
#[deprecated(
since = "0.8.0",
note = "Now server_fn can return any error type other than ServerFnError, \
so the WrappedServerError variant will be removed in 0.9.0"
)]
pub struct WrapError<T>(pub T);
#[macro_export]
#[deprecated(
since = "0.8.0",
note = "Now server_fn can return any error type other than ServerFnError, \
so the WrappedServerError variant will be removed in 0.9.0"
)]
macro_rules! server_fn_error {
() => {{
use $crate::{ViaError, WrapError};
(&&&&&WrapError(())).to_server_error()
}};
($err:expr) => {{
use $crate::error::{ViaError, WrapError};
match $err {
error => (&&&&&WrapError(error)).to_server_error(),
}
}};
}
#[deprecated(
since = "0.8.0",
note = "Now server_fn can return any error type other than ServerFnError, \
so users should place their custom error type instead of \
ServerFnError"
)]
pub trait ViaError<E> {
fn to_server_error(&self) -> ServerFnError<E>;
}
impl<E: ServerFnErrorKind + std::error::Error + Clone> ViaError<E>
for &&&&WrapError<ServerFnError<E>>
{
fn to_server_error(&self) -> ServerFnError<E> {
self.0.clone()
}
}
#[deprecated]
pub(crate) trait ServerFnErrorKind {}
impl ServerFnErrorKind for ServerFnError {}
impl ViaError<NoCustomError> for &&&WrapError<()> {
fn to_server_error(&self) -> ServerFnError {
ServerFnError::WrappedServerError(NoCustomError)
}
}
impl<E: std::error::Error + Clone> ViaError<E> for &&WrapError<E> {
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::WrappedServerError(self.0.clone())
}
}
impl<E: Display + Clone> ViaError<E> for &WrapError<E> {
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::ServerError(self.0.to_string())
}
}
impl<E> ViaError<E> for WrapError<E> {
#[track_caller]
fn to_server_error(&self) -> ServerFnError<E> {
panic!(
"At {}, you call `to_server_error()` or use `server_fn_error!` \
with a value that does not implement `Clone` and either `Error` \
or `Display`.",
std::panic::Location::caller()
);
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub enum ServerFnError<E = NoCustomError> {
#[deprecated(
since = "0.8.0",
note = "Now server_fn can return any error type other than \
ServerFnError, so users should place their custom error type \
instead of ServerFnError"
)]
WrappedServerError(E),
Registration(String),
Request(String),
Response(String),
ServerError(String),
MiddlewareError(String),
Deserialization(String),
Serialization(String),
Args(String),
MissingArg(String),
}
impl ServerFnError<NoCustomError> {
pub fn new(msg: impl ToString) -> Self {
Self::ServerError(msg.to_string())
}
}
impl<CustErr> From<CustErr> for ServerFnError<CustErr> {
fn from(value: CustErr) -> Self {
ServerFnError::WrappedServerError(value)
}
}
impl<E: std::error::Error> From<E> for ServerFnError {
fn from(value: E) -> Self {
ServerFnError::ServerError(value.to_string())
}
}
impl<CustErr> Display for ServerFnError<CustErr>
where
CustErr: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
ServerFnError::Registration(s) => format!(
"error while trying to register the server function: {s}"
),
ServerFnError::Request(s) => format!(
"error reaching server to call server function: {s}"
),
ServerFnError::ServerError(s) =>
format!("error running server function: {s}"),
ServerFnError::MiddlewareError(s) =>
format!("error running middleware: {s}"),
ServerFnError::Deserialization(s) =>
format!("error deserializing server function results: {s}"),
ServerFnError::Serialization(s) =>
format!("error serializing server function arguments: {s}"),
ServerFnError::Args(s) => format!(
"error deserializing server function arguments: {s}"
),
ServerFnError::MissingArg(s) => format!("missing argument {s}"),
ServerFnError::Response(s) =>
format!("error generating HTTP response: {s}"),
ServerFnError::WrappedServerError(e) => format!("{e}"),
}
)
}
}
impl<CustErr> FromServerFnError for ServerFnError<CustErr>
where
CustErr: std::fmt::Debug
+ Display
+ Serialize
+ DeserializeOwned
+ 'static
+ FromStr
+ Display,
{
fn from_server_fn_error(value: ServerFnErrorErr) -> Self {
match value {
ServerFnErrorErr::Registration(value) => {
ServerFnError::Registration(value)
}
ServerFnErrorErr::Request(value) => ServerFnError::Request(value),
ServerFnErrorErr::ServerError(value) => {
ServerFnError::ServerError(value)
}
ServerFnErrorErr::MiddlewareError(value) => {
ServerFnError::MiddlewareError(value)
}
ServerFnErrorErr::Deserialization(value) => {
ServerFnError::Deserialization(value)
}
ServerFnErrorErr::Serialization(value) => {
ServerFnError::Serialization(value)
}
ServerFnErrorErr::Args(value) => ServerFnError::Args(value),
ServerFnErrorErr::MissingArg(value) => {
ServerFnError::MissingArg(value)
}
ServerFnErrorErr::Response(value) => ServerFnError::Response(value),
}
}
fn ser(&self) -> String {
let mut buf = String::new();
let result = match self {
ServerFnError::WrappedServerError(e) => {
write!(&mut buf, "WrappedServerFn|{e}")
}
ServerFnError::Registration(e) => {
write!(&mut buf, "Registration|{e}")
}
ServerFnError::Request(e) => write!(&mut buf, "Request|{e}"),
ServerFnError::Response(e) => write!(&mut buf, "Response|{e}"),
ServerFnError::ServerError(e) => {
write!(&mut buf, "ServerError|{e}")
}
ServerFnError::MiddlewareError(e) => {
write!(&mut buf, "MiddlewareError|{e}")
}
ServerFnError::Deserialization(e) => {
write!(&mut buf, "Deserialization|{e}")
}
ServerFnError::Serialization(e) => {
write!(&mut buf, "Serialization|{e}")
}
ServerFnError::Args(e) => write!(&mut buf, "Args|{e}"),
ServerFnError::MissingArg(e) => {
write!(&mut buf, "MissingArg|{e}")
}
};
match result {
Ok(()) => buf,
Err(_) => "Serialization|".to_string(),
}
}
fn de(data: &str) -> Self {
data.split_once('|')
.and_then(|(ty, data)| match ty {
"WrappedServerFn" => match CustErr::from_str(data) {
Ok(d) => Some(ServerFnError::WrappedServerError(d)),
Err(_) => None,
},
"Registration" => {
Some(ServerFnError::Registration(data.to_string()))
}
"Request" => Some(ServerFnError::Request(data.to_string())),
"Response" => Some(ServerFnError::Response(data.to_string())),
"ServerError" => {
Some(ServerFnError::ServerError(data.to_string()))
}
"Deserialization" => {
Some(ServerFnError::Deserialization(data.to_string()))
}
"Serialization" => {
Some(ServerFnError::Serialization(data.to_string()))
}
"Args" => Some(ServerFnError::Args(data.to_string())),
"MissingArg" => {
Some(ServerFnError::MissingArg(data.to_string()))
}
_ => None,
})
.unwrap_or_else(|| {
ServerFnError::Deserialization(format!(
"Could not deserialize error {data:?}"
))
})
}
}
impl<E> std::error::Error for ServerFnError<E>
where
E: std::error::Error + 'static,
ServerFnError<E>: std::fmt::Display,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ServerFnError::WrappedServerError(e) => Some(e),
_ => None,
}
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
pub enum ServerFnErrorErr {
#[error("error while trying to register the server function: {0}")]
Registration(String),
#[error("error reaching server to call server function: {0}")]
Request(String),
#[error("error running server function: {0}")]
ServerError(String),
#[error("error running middleware: {0}")]
MiddlewareError(String),
#[error("error deserializing server function results: {0}")]
Deserialization(String),
#[error("error serializing server function arguments: {0}")]
Serialization(String),
#[error("error deserializing server function arguments: {0}")]
Args(String),
#[error("missing argument {0}")]
MissingArg(String),
#[error("error creating response {0}")]
Response(String),
}
#[derive(Debug)]
pub struct ServerFnUrlError<E> {
path: String,
error: E,
}
impl<E: FromServerFnError> ServerFnUrlError<E> {
pub fn new(path: impl Display, error: E) -> Self {
Self {
path: path.to_string(),
error,
}
}
pub fn error(&self) -> &E {
&self.error
}
pub fn path(&self) -> &str {
&self.path
}
pub fn to_url(&self, base: &str) -> Result<Url, url::ParseError> {
let mut url = Url::parse(base)?;
url.query_pairs_mut()
.append_pair("__path", &self.path)
.append_pair("__err", &URL_SAFE.encode(self.error.ser()));
Ok(url)
}
pub fn strip_error_info(path: &mut String) {
if let Ok(mut url) = Url::parse(&*path) {
let pairs_previously = url
.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect::<Vec<_>>();
let mut pairs = url.query_pairs_mut();
pairs.clear();
for (key, value) in pairs_previously
.into_iter()
.filter(|(key, _)| key != "__path" && key != "__err")
{
pairs.append_pair(&key, &value);
}
drop(pairs);
*path = url.to_string();
}
}
pub fn decode_err(err: &str) -> E {
let decoded = match URL_SAFE.decode(err) {
Ok(decoded) => decoded,
Err(err) => {
return ServerFnErrorErr::Deserialization(err.to_string())
.into_app_error();
}
};
let s = match String::from_utf8(decoded) {
Ok(s) => s,
Err(err) => {
return ServerFnErrorErr::Deserialization(err.to_string())
.into_app_error();
}
};
E::de(&s)
}
}
impl<E> From<ServerFnUrlError<E>> for ServerFnError<E> {
fn from(error: ServerFnUrlError<E>) -> Self {
error.error.into()
}
}
impl<E> From<ServerFnUrlError<ServerFnError<E>>> for ServerFnError<E> {
fn from(error: ServerFnUrlError<ServerFnError<E>>) -> Self {
error.error
}
}
#[derive(Debug)]
#[doc(hidden)]
pub struct ServerFnErrorWrapper<E: FromServerFnError>(pub E);
impl<E: FromServerFnError> Display for ServerFnErrorWrapper<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.ser())
}
}
impl<E: FromServerFnError> std::error::Error for ServerFnErrorWrapper<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
pub trait FromServerFnError:
std::fmt::Debug + Serialize + DeserializeOwned + 'static
{
fn from_server_fn_error(value: ServerFnErrorErr) -> Self;
fn ser(&self) -> String {
serde_json::to_string(self).unwrap_or_else(|e| {
serde_json::to_string(&Self::from_server_fn_error(
ServerFnErrorErr::Serialization(e.to_string()),
))
.expect(
"error serializing should success at least with the \
Serialization error",
)
})
}
fn de(data: &str) -> Self {
serde_json::from_str(data).unwrap_or_else(|e| {
ServerFnErrorErr::Deserialization(e.to_string()).into_app_error()
})
}
}
pub trait IntoAppError<E> {
fn into_app_error(self) -> E;
}
impl<E> IntoAppError<E> for ServerFnErrorErr
where
E: FromServerFnError,
{
fn into_app_error(self) -> E {
E::from_server_fn_error(self)
}
}
#[test]
fn assert_from_server_fn_error_impl() {
fn assert_impl<T: FromServerFnError>() {}
assert_impl::<ServerFnError>();
}