1use super::KoraError;
2use deadpool_redis::{Config, Pool, Runtime};
3use redis::AsyncCommands;
4use solana_sdk::pubkey::Pubkey;
5use std::str::FromStr;
6
7const TOKEN_ACCOUNT_CACHE_TTL: u64 = 3600 * 24; #[derive(Clone)]
10pub struct TokenAccountCache {
11 pool: Pool,
12}
13
14impl TokenAccountCache {
15 pub fn new(redis_url: &str) -> Result<Self, KoraError> {
16 let cfg = Config::from_url(redis_url);
17 let pool = cfg.create_pool(Some(Runtime::Tokio1)).map_err(|e| {
18 KoraError::InternalServerError(format!("Failed to create Redis pool: {}", e))
19 })?;
20
21 Ok(Self { pool })
22 }
23
24 pub async fn get_token_account(
25 &self,
26 user: &Pubkey,
27 mint: &Pubkey,
28 ) -> Result<Option<Pubkey>, KoraError> {
29 let key = format!("token_account:{}:{}", user, mint);
30 let mut conn = self.pool.get().await.map_err(|e| {
31 KoraError::InternalServerError(format!("Failed to get Redis connection: {}", e))
32 })?;
33
34 let result: Option<String> = conn.get(&key).await.map_err(|e| {
35 KoraError::InternalServerError(format!("Failed to get from Redis: {}", e))
36 })?;
37
38 match result {
39 Some(pubkey_str) => {
40 let pubkey = Pubkey::from_str(&pubkey_str).map_err(|e| {
41 KoraError::InternalServerError(format!("Invalid pubkey in cache: {}", e))
42 })?;
43 Ok(Some(pubkey))
44 }
45 None => Ok(None),
46 }
47 }
48
49 pub async fn set_token_account(
50 &self,
51 user: &Pubkey,
52 mint: &Pubkey,
53 token_account: &Pubkey,
54 ) -> Result<(), KoraError> {
55 let key = format!("token_account:{}:{}", user, mint);
56 let mut conn = self.pool.get().await.map_err(|e| {
57 KoraError::InternalServerError(format!("Failed to get Redis connection: {}", e))
58 })?;
59
60 conn.set_ex::<_, _, ()>(&key, token_account.to_string(), TOKEN_ACCOUNT_CACHE_TTL)
61 .await
62 .map_err(|e| {
63 KoraError::InternalServerError(format!("Failed to set in Redis: {}", e))
64 })?;
65
66 Ok(())
67 }
68
69 pub async fn _invalidate_token_account(
70 &self,
71 user: &Pubkey,
72 mint: &Pubkey,
73 ) -> Result<(), KoraError> {
74 let key = format!("token_account:{}:{}", user, mint);
75 let mut conn = self.pool.get().await.map_err(|e| {
76 KoraError::InternalServerError(format!("Failed to get Redis connection: {}", e))
77 })?;
78
79 conn.del::<_, ()>(&key).await.map_err(|e| {
80 KoraError::InternalServerError(format!("Failed to delete from Redis: {}", e))
81 })?;
82
83 Ok(())
84 }
85}