Skip to content

Commit 2842750

Browse files
committed
Introduce db::Error to store Redis and timeout errors
1 parent d940ed2 commit 2842750

File tree

3 files changed

+61
-19
lines changed

3 files changed

+61
-19
lines changed

payjoin-directory/src/db.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,54 @@ pub(crate) struct DbPool {
1313
timeout: Duration,
1414
}
1515

16+
/// Errors pertaining to [`DbPool`]
17+
#[derive(Debug)]
18+
pub(crate) enum Error {
19+
Redis(RedisError),
20+
Timeout(tokio::time::error::Elapsed),
21+
}
22+
23+
impl std::fmt::Display for Error {
24+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25+
use Error::*;
26+
27+
match &self {
28+
Redis(error) => write!(f, "Redis error: {}", error),
29+
Timeout(timeout) => write!(f, "Timeout: {}", timeout),
30+
}
31+
}
32+
}
33+
34+
impl std::error::Error for Error {
35+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
36+
match self {
37+
Error::Redis(e) => Some(e),
38+
Error::Timeout(e) => Some(e),
39+
}
40+
}
41+
}
42+
1643
impl DbPool {
1744
pub async fn new(timeout: Duration, db_host: String) -> RedisResult<Self> {
1845
let client = Client::open(format!("redis://{}", db_host))?;
1946
Ok(Self { client, timeout })
2047
}
2148

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

26-
pub async fn peek_default(&self, subdirectory_id: &str) -> Option<RedisResult<Vec<u8>>> {
54+
pub async fn peek_default(&self, subdirectory_id: &str) -> Result<Vec<u8>, Error> {
2755
self.peek_with_timeout(subdirectory_id, DEFAULT_COLUMN).await
2856
}
2957

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

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

@@ -52,8 +81,14 @@ impl DbPool {
5281
&self,
5382
subdirectory_id: &str,
5483
channel_type: &str,
55-
) -> Option<RedisResult<Vec<u8>>> {
56-
tokio::time::timeout(self.timeout, self.peek(subdirectory_id, channel_type)).await.ok()
84+
) -> Result<Vec<u8>, Error> {
85+
match tokio::time::timeout(self.timeout, self.peek(subdirectory_id, channel_type)).await {
86+
Ok(redis_result) => match redis_result {
87+
Ok(result) => Ok(result),
88+
Err(redis_err) => Err(Error::Redis(redis_err)),
89+
},
90+
Err(elapsed) => Err(Error::Timeout(elapsed)),
91+
}
5792
}
5893

5994
async fn peek(&self, subdirectory_id: &str, channel_type: &str) -> RedisResult<Vec<u8>> {

payjoin-directory/src/lib.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use tokio::net::TcpListener;
1515
use tokio::sync::Mutex;
1616
use tracing::{debug, error, info, trace};
1717

18+
use crate::db::{DbPool, Error};
19+
1820
pub const DEFAULT_DIR_PORT: u16 = 8080;
1921
pub const DEFAULT_DB_HOST: &str = "localhost:6379";
2022
pub const DEFAULT_TIMEOUT_SECS: u64 = 30;
@@ -34,7 +36,6 @@ const V1_UNAVAILABLE_RES_JSON: &str = r#"{{"errorCode": "unavailable", "message"
3436
const ID_LENGTH: usize = 13;
3537

3638
mod db;
37-
use crate::db::DbPool;
3839

3940
#[cfg(feature = "_danger-local-https")]
4041
type BoxError = Box<dyn std::error::Error + Send + Sync>;
@@ -312,6 +313,22 @@ impl From<hyper::http::Error> for HandlerError {
312313
fn from(e: hyper::http::Error) -> Self { HandlerError::InternalServerError(e.into()) }
313314
}
314315

316+
fn handle_peek(
317+
result: Result<Vec<u8>, Error>,
318+
timeout_response: Response<BoxBody<Bytes, hyper::Error>>,
319+
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
320+
match result {
321+
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
322+
Err(e) => match e {
323+
Error::Redis(re) => {
324+
error!("Redis error: {}", re);
325+
Err(HandlerError::InternalServerError(anyhow::Error::msg("Internal server error")))
326+
},
327+
Error::Timeout(_) => Ok(timeout_response),
328+
},
329+
}
330+
}
331+
315332
async fn post_fallback_v1(
316333
id: &str,
317334
query: String,
@@ -340,13 +357,7 @@ async fn post_fallback_v1(
340357
pool.push_default(id, v2_compat_body.into())
341358
.await
342359
.map_err(|e| HandlerError::BadRequest(e.into()))?;
343-
match pool.peek_v1(id).await {
344-
Some(result) => match result {
345-
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
346-
Err(e) => Err(HandlerError::BadRequest(e.into())),
347-
},
348-
None => Ok(none_response),
349-
}
360+
handle_peek(pool.peek_v1(id).await, none_response)
350361
}
351362

352363
async fn put_payjoin_v1(
@@ -408,13 +419,8 @@ async fn get_subdir(
408419
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
409420
trace!("get_subdir");
410421
let id = check_id_length(id)?;
411-
match pool.peek_default(id).await {
412-
Some(result) => match result {
413-
Ok(buffered_req) => Ok(Response::new(full(buffered_req))),
414-
Err(e) => Err(HandlerError::BadRequest(e.into())),
415-
},
416-
None => Ok(Response::builder().status(StatusCode::ACCEPTED).body(empty())?),
417-
}
422+
let timeout_response = Response::builder().status(StatusCode::ACCEPTED).body(empty())?;
423+
handle_peek(pool.peek_default(id).await, timeout_response)
418424
}
419425

420426
fn not_found() -> Response<BoxBody<Bytes, hyper::Error>> {

payjoin/src/ohttp.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{error, fmt};
33

44
use bitcoin::bech32::{self, EncodeError};
55
use bitcoin::key::constants::UNCOMPRESSED_PUBLIC_KEY_SIZE;
6+
use serde::{Deserialize, Deserializer};
67

78
pub const ENCAPSULATED_MESSAGE_BYTES: usize = 8192;
89
const N_ENC: usize = UNCOMPRESSED_PUBLIC_KEY_SIZE;

0 commit comments

Comments
 (0)