Skip to content

Commit

Permalink
use msgpack with redis
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcountryman committed Sep 23, 2023
1 parent c0f20d3 commit 51ddfe4
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 18 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
[features]
default = ["axum-core", "memory-store"]
memory-store = []
redis-store = ["fred"]
redis-store = ["fred", "rmp-serde"]
sqlx-store = ["sqlx"]
sqlite-store = ["sqlx/sqlite", "sqlx-store"]
postgres-store = ["sqlx/postgres", "sqlx-store"]
Expand All @@ -27,8 +27,10 @@ tower-cookies = "0.9"
tower-layer = "0.3"
tower-service = "0.3"
uuid = { version = "1.4.1", features = ["v4", "serde"] }

axum-core = { optional = true, version = "0.3" }
fred = { optional = true, version = "6", features = ["serde-json"] }
fred = { optional = true, version = "6" }
rmp-serde = { optional = true, version = "1.1.2" }
sqlx = { optional = true, version = "0.7.1", features = [
"time",
"uuid",
Expand Down
18 changes: 11 additions & 7 deletions examples/redis-store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ const COUNTER_KEY: &str = "counter";
struct Counter(usize);

#[tokio::main]
async fn main() {
let config = RedisConfig::from_url("redis://127.0.0.1:6379/1").unwrap();
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RedisConfig::from_url("redis://127.0.0.1:6379/1")?;
let client = RedisClient::new(config, None, None);

let _ = client.connect();
let _ = client.wait_for_connect().await.unwrap();
let redis_conn = client.connect();
client.wait_for_connect().await?;

let session_store = RedisStore::new(client);
let session_service = ServiceBuilder::new()
.layer(HandleErrorLayer::new(|_: BoxError| async {
.layer(HandleErrorLayer::new(|err: BoxError| async {
dbg!(err);
StatusCode::BAD_REQUEST
}))
.layer(
Expand All @@ -39,8 +40,11 @@ async fn main() {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
.await?;

redis_conn.await??;

Ok(())
}

async fn handler(session: Session) -> impl IntoResponse {
Expand Down
40 changes: 31 additions & 9 deletions src/redis_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ use crate::{
};

/// An error type for `RedisStore`.
#[allow(clippy::enum_variant_names)]
#[derive(thiserror::Error, Debug)]
pub enum RedisStoreError {
/// A variant to map to `fred::error::RedisError` errors.
#[error("Redis error: {0}")]
RedisError(#[from] fred::error::RedisError),

/// A variant to map `serde_json` errors.
#[error("JSON serialization/deserialization error: {0}")]
SerdeJsonError(#[from] serde_json::Error),
/// A variant to map `rmp_serde` encode errors.
#[error("Rust MsgPack encode error: {0}")]
RmpSerdeEncodeError(#[from] rmp_serde::encode::Error),

/// A variant to map `rmp_serde` decode errors.
#[error("Rust MsgPack decode error: {0}")]
RmpSerdeDecodeError(#[from] rmp_serde::decode::Error),
}

/// A Redis session store.
Expand All @@ -27,6 +32,23 @@ pub struct RedisStore {

impl RedisStore {
/// Create a new Redis store with the provided client.
///
/// # Examples
///
/// ```rust,no_run
/// use fred::prelude::*;
/// use tower_sessions::RedisStore;
///
/// # tokio_test::block_on(async {
/// let config = RedisConfig::from_url("redis://127.0.0.1:6379/1").unwrap();
/// let client = RedisClient::new(config, None, None);
///
/// let _ = client.connect();
/// client.wait_for_connect().await.unwrap();
///
/// let session_store = RedisStore::new(client);
/// })
/// ```
pub fn new(client: RedisClient) -> Self {
Self { client }
}
Expand All @@ -45,7 +67,7 @@ impl SessionStore for RedisStore {
self.client
.set(
session_record.id().to_string(),
serde_json::to_string(&session_record)?,
rmp_serde::to_vec(&session_record)?.as_slice(),
expiration,
None,
false,
Expand All @@ -58,16 +80,16 @@ impl SessionStore for RedisStore {
async fn load(&self, session_id: &SessionId) -> Result<Option<Session>, Self::Error> {
let record_value = self
.client
.get::<serde_json::Value, _>(session_id.to_string())
.get::<Option<Vec<u8>>, _>(session_id.to_string())
.await?;

let session = match record_value {
serde_json::Value::Null => None,

record_value => {
let session_record: SessionRecord = serde_json::from_value(record_value.clone())?;
Some(record_value) => {
let session_record: SessionRecord = rmp_serde::from_slice(&record_value)?;
Some(session_record.into())
}

None => None,
};

Ok(session)
Expand Down

0 comments on commit 51ddfe4

Please sign in to comment.