Skip to content

Commit

Permalink
Create a server error type.
Browse files Browse the repository at this point in the history
  • Loading branch information
nihohit committed Feb 29, 2024
1 parent 6a06372 commit c73b18e
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 25 deletions.
40 changes: 21 additions & 19 deletions redis/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use crate::types::{
make_extension_error, ErrorKind, InternalValue, RedisError, RedisResult, Value,
ErrorKind, InternalValue, RedisError, RedisResult, ServerError, ServerErrorKind, Value,
};

use combine::{
Expand Down Expand Up @@ -97,27 +97,29 @@ where

let error = || {
line().map(|line: &str| {
let desc = "An error was signalled by the server";
let mut pieces = line.splitn(2, ' ');
let kind = match pieces.next().unwrap() {
"ERR" => ErrorKind::ResponseError,
"EXECABORT" => ErrorKind::ExecAbortError,
"LOADING" => ErrorKind::BusyLoadingError,
"NOSCRIPT" => ErrorKind::NoScriptError,
"MOVED" => ErrorKind::Moved,
"ASK" => ErrorKind::Ask,
"TRYAGAIN" => ErrorKind::TryAgain,
"CLUSTERDOWN" => ErrorKind::ClusterDown,
"CROSSSLOT" => ErrorKind::CrossSlot,
"MASTERDOWN" => ErrorKind::MasterDown,
"READONLY" => ErrorKind::ReadOnly,
"NOTBUSY" => ErrorKind::NotBusy,
code => return make_extension_error(code, pieces.next()),
"ERR" => ServerErrorKind::ResponseError,
"EXECABORT" => ServerErrorKind::ExecAbortError,
"LOADING" => ServerErrorKind::BusyLoadingError,
"NOSCRIPT" => ServerErrorKind::NoScriptError,
"MOVED" => ServerErrorKind::Moved,
"ASK" => ServerErrorKind::Ask,
"TRYAGAIN" => ServerErrorKind::TryAgain,
"CLUSTERDOWN" => ServerErrorKind::ClusterDown,
"CROSSSLOT" => ServerErrorKind::CrossSlot,
"MASTERDOWN" => ServerErrorKind::MasterDown,
"READONLY" => ServerErrorKind::ReadOnly,
"NOTBUSY" => ServerErrorKind::NotBusy,
code => {
return ServerError::ExtensionError {
code: code.to_string(),
detail: pieces.next().map(|str| str.to_string()),
}
}
};
match pieces.next() {
Some(detail) => RedisError::from((kind, desc, detail.to_string())),
None => RedisError::from((kind, desc)),
}
let detail = pieces.next().map(|str| str.to_string());
ServerError::KnownError { kind, detail }
})
};

Expand Down
70 changes: 64 additions & 6 deletions redis/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,66 @@ pub enum ErrorKind {
Serialize,
}

#[derive(PartialEq, Debug)]
pub(crate) enum ServerErrorKind {
ResponseError,
ExecAbortError,
BusyLoadingError,
NoScriptError,
Moved,
Ask,
TryAgain,
ClusterDown,
CrossSlot,
MasterDown,
ReadOnly,
NotBusy,
}

#[derive(PartialEq, Debug)]
pub(crate) enum ServerError {
ExtensionError {
code: String,
detail: Option<String>,
},
KnownError {
kind: ServerErrorKind,
detail: Option<String>,
},
}

impl From<ServerError> for RedisError {
fn from(value: ServerError) -> Self {
// TODO - Consider changing RedisError to explicitly represent whether an error came from the server or not. Today it is only implied.
match value {
ServerError::ExtensionError { code, detail } => make_extension_error(code, detail),
ServerError::KnownError { kind, detail } => {
let desc = "An error was signalled by the server";
let kind = match kind {
ServerErrorKind::ResponseError => ErrorKind::ResponseError,
ServerErrorKind::ExecAbortError => ErrorKind::ExecAbortError,
ServerErrorKind::BusyLoadingError => ErrorKind::BusyLoadingError,
ServerErrorKind::NoScriptError => ErrorKind::NoScriptError,
ServerErrorKind::Moved => ErrorKind::Moved,
ServerErrorKind::Ask => ErrorKind::Ask,
ServerErrorKind::TryAgain => ErrorKind::TryAgain,
ServerErrorKind::ClusterDown => ErrorKind::ClusterDown,
ServerErrorKind::CrossSlot => ErrorKind::CrossSlot,
ServerErrorKind::MasterDown => ErrorKind::MasterDown,
ServerErrorKind::ReadOnly => ErrorKind::ReadOnly,
ServerErrorKind::NotBusy => ErrorKind::NotBusy,
};
match detail {
Some(detail) => RedisError::from((kind, desc, detail)),
None => RedisError::from((kind, desc)),
}
}
}
}
}

/// Internal low-level redis value enum.
#[derive(PartialEq, Eq, Debug)]
#[derive(PartialEq, Debug)]
pub(crate) enum InternalValue {
/// A nil response from the server.
Nil,
Expand All @@ -156,7 +214,7 @@ pub(crate) enum InternalValue {
Status(String),
/// A status response which represents the string "OK".
Okay,
ServerError(RedisError),
ServerError(ServerError),
}

impl InternalValue {
Expand All @@ -172,7 +230,7 @@ impl InternalValue {
)),
InternalValue::Status(val) => Ok(Value::Status(val)),
InternalValue::Okay => Ok(Value::Okay),
InternalValue::ServerError(err) => Err(err),
InternalValue::ServerError(err) => Err(err.into()),
}
}
}
Expand Down Expand Up @@ -789,12 +847,12 @@ impl RedisError {
}
}

pub fn make_extension_error(code: &str, detail: Option<&str>) -> RedisError {
pub fn make_extension_error(code: String, detail: Option<String>) -> RedisError {
RedisError {
repr: ErrorRepr::ExtensionError(
code.to_string(),
code,
match detail {
Some(x) => x.to_string(),
Some(x) => x,
None => "Unknown extension error encountered".to_string(),
},
),
Expand Down

0 comments on commit c73b18e

Please sign in to comment.