redis.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. use std::time::Duration;
  2. use redis::AsyncCommands;
  3. use serde::{Deserialize, Serialize};
  4. use crate::cache::{HttpCacheKey, HttpCacheStorage};
  5. /// Redis cache storage for the HTTP cache.
  6. ///
  7. /// This cache storage backend uses Redis to store the cache.
  8. pub struct HttpCacheRedis {
  9. cache_ttl: Duration,
  10. prefix: Option<Vec<u8>>,
  11. client: redis::Client,
  12. }
  13. impl std::fmt::Debug for HttpCacheRedis {
  14. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  15. f.debug_struct("HttpCacheRedis")
  16. .field("cache_ttl", &self.cache_ttl)
  17. .field("prefix", &self.prefix)
  18. .finish_non_exhaustive()
  19. }
  20. }
  21. /// Configuration for the Redis cache storage.
  22. #[derive(Debug, Clone, Serialize, Deserialize, Default)]
  23. pub struct Config {
  24. /// Commong key prefix
  25. pub key_prefix: Option<String>,
  26. /// Connection string to the Redis server.
  27. pub connection_string: String,
  28. }
  29. impl HttpCacheRedis {
  30. /// Create a new Redis cache.
  31. pub fn new(client: redis::Client) -> Self {
  32. Self {
  33. client,
  34. prefix: None,
  35. cache_ttl: Duration::from_secs(60),
  36. }
  37. }
  38. /// Set a prefix for the cache keys.
  39. ///
  40. /// This is useful to have all the HTTP cache keys under a common prefix,
  41. /// some sort of namespace, to make management of the database easier.
  42. pub fn set_prefix(mut self, prefix: Vec<u8>) -> Self {
  43. self.prefix = Some(prefix);
  44. self
  45. }
  46. }
  47. #[async_trait::async_trait]
  48. impl HttpCacheStorage for HttpCacheRedis {
  49. fn set_expiration_times(&mut self, cache_ttl: Duration, _cache_tti: Duration) {
  50. self.cache_ttl = cache_ttl;
  51. }
  52. async fn get(&self, key: &HttpCacheKey) -> Option<Vec<u8>> {
  53. let mut conn = self
  54. .client
  55. .get_multiplexed_tokio_connection()
  56. .await
  57. .map_err(|err| {
  58. tracing::error!("Failed to get redis connection: {:?}", err);
  59. err
  60. })
  61. .ok()?;
  62. let mut db_key = self.prefix.clone().unwrap_or_default();
  63. db_key.extend(&**key);
  64. conn.get(db_key)
  65. .await
  66. .map_err(|err| {
  67. tracing::error!("Failed to get value from redis: {:?}", err);
  68. err
  69. })
  70. .ok()?
  71. }
  72. async fn set(&self, key: HttpCacheKey, value: Vec<u8>) {
  73. let mut db_key = self.prefix.clone().unwrap_or_default();
  74. db_key.extend(&*key);
  75. let mut conn = match self.client.get_multiplexed_tokio_connection().await {
  76. Ok(conn) => conn,
  77. Err(err) => {
  78. tracing::error!("Failed to get redis connection: {:?}", err);
  79. return;
  80. }
  81. };
  82. let _: Result<(), _> = conn
  83. .set_ex(db_key, value, self.cache_ttl.as_secs())
  84. .await
  85. .map_err(|err| {
  86. tracing::error!("Failed to set value in redis: {:?}", err);
  87. err
  88. });
  89. }
  90. }