Skip to content

Commit

Permalink
Introduce DbPoolError to store Redis and timeout errors
Browse files Browse the repository at this point in the history
  • Loading branch information
shinghim committed Jan 5, 2025
1 parent d940ed2 commit 61bfaf0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 12 deletions.
18 changes: 14 additions & 4 deletions payjoin-directory/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use futures::StreamExt;
use redis::{AsyncCommands, Client, ErrorKind, RedisError, RedisResult};
use tracing::debug;

use crate::error::DbPoolError;

const DEFAULT_COLUMN: &str = "";
const PJ_V1_COLUMN: &str = "pjv1";

Expand All @@ -19,19 +21,21 @@ impl DbPool {
Ok(Self { client, timeout })
}

/// Peek using [`DEFAULT_COLUMN`] as the channel type.
pub async fn push_default(&self, subdirectory_id: &str, data: Vec<u8>) -> RedisResult<()> {
self.push(subdirectory_id, DEFAULT_COLUMN, data).await
}

pub async fn peek_default(&self, subdirectory_id: &str) -> Option<RedisResult<Vec<u8>>> {
pub async fn peek_default(&self, subdirectory_id: &str) -> Result<Vec<u8>, DbPoolError> {
self.peek_with_timeout(subdirectory_id, DEFAULT_COLUMN).await
}

pub async fn push_v1(&self, subdirectory_id: &str, data: Vec<u8>) -> RedisResult<()> {
self.push(subdirectory_id, PJ_V1_COLUMN, data).await
}

pub async fn peek_v1(&self, subdirectory_id: &str) -> Option<RedisResult<Vec<u8>>> {
/// Peek using [`PJ_V1_COLUMN`] as the channel type.
pub async fn peek_v1(&self, subdirectory_id: &str) -> Result<Vec<u8>, DbPoolError> {
self.peek_with_timeout(subdirectory_id, PJ_V1_COLUMN).await
}

Expand All @@ -52,8 +56,14 @@ impl DbPool {
&self,
subdirectory_id: &str,
channel_type: &str,
) -> Option<RedisResult<Vec<u8>>> {
tokio::time::timeout(self.timeout, self.peek(subdirectory_id, channel_type)).await.ok()
) -> Result<Vec<u8>, DbPoolError> {
match tokio::time::timeout(self.timeout, self.peek(subdirectory_id, channel_type)).await {
Ok(redis_result) => match redis_result {
Ok(result) => Ok(result),
Err(redis_err) => Err(DbPoolError::Redis(redis_err)),
},
Err(elapsed) => Err(DbPoolError::Timeout(elapsed)),
}
}

async fn peek(&self, subdirectory_id: &str, channel_type: &str) -> RedisResult<Vec<u8>> {
Expand Down
25 changes: 25 additions & 0 deletions payjoin-directory/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#[derive(Debug)]
pub enum DbPoolError {
Redis(redis::RedisError),
Timeout(tokio::time::error::Elapsed),
}

impl std::fmt::Display for DbPoolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use DbPoolError::*;

match &self {
Redis(error) => write!(f, "Redis error: {}", error),
Timeout(timeout) => write!(f, "Timeout: {}", timeout),
}
}
}

impl std::error::Error for DbPoolError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DbPoolError::Redis(e) => Some(e),
DbPoolError::Timeout(e) => Some(e),
}
}
}
20 changes: 12 additions & 8 deletions payjoin-directory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ const V1_UNAVAILABLE_RES_JSON: &str = r#"{{"errorCode": "unavailable", "message"
const ID_LENGTH: usize = 13;

mod db;
mod error;

use crate::db::DbPool;
use crate::error::DbPoolError;

#[cfg(feature = "_danger-local-https")]
type BoxError = Box<dyn std::error::Error + Send + Sync>;
Expand Down Expand Up @@ -341,11 +344,11 @@ async fn post_fallback_v1(
.await
.map_err(|e| HandlerError::BadRequest(e.into()))?;
match pool.peek_v1(id).await {
Some(result) => match result {
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
Err(e) => Err(HandlerError::BadRequest(e.into())),
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
Err(e) => match e {
DbPoolError::Redis(_) => Err(HandlerError::BadRequest(e.into())),
DbPoolError::Timeout(_) => Ok(none_response),
},
None => Ok(none_response),
}
}

Expand Down Expand Up @@ -409,11 +412,12 @@ async fn get_subdir(
trace!("get_subdir");
let id = check_id_length(id)?;
match pool.peek_default(id).await {
Some(result) => match result {
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
Err(e) => Err(HandlerError::BadRequest(e.into())),
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
Err(e) => match e {
DbPoolError::Redis(_) => Err(HandlerError::BadRequest(e.into())),
DbPoolError::Timeout(_) =>
Ok(Response::builder().status(StatusCode::ACCEPTED).body(empty())?),
},
None => Ok(Response::builder().status(StatusCode::ACCEPTED).body(empty())?),
}
}

Expand Down

0 comments on commit 61bfaf0

Please sign in to comment.