1- use crate :: env:: RedisMode ;
1+ use crate :: { env:: RedisMode , response:: ApiResponse } ;
2+ use axum:: http:: StatusCode ;
23use colored:: Colorize ;
34use rustis:: {
45 client:: Client ,
5- commands:: { GenericCommands , SetCondition , SetExpiration , StringCommands } ,
6+ commands:: { GenericCommands , SetExpiration , StringCommands } ,
67 resp:: { BulkString , cmd} ,
78} ;
89use serde:: { Serialize , de:: DeserializeOwned } ;
@@ -59,6 +60,43 @@ impl Cache {
5960 instance
6061 }
6162
63+ pub async fn ratelimit (
64+ & self ,
65+ limit_identifier : impl AsRef < str > ,
66+ limit : u64 ,
67+ limit_window : u64 ,
68+ client : impl AsRef < str > ,
69+ ) -> Result < ( ) , ApiResponse > {
70+ let key = format ! (
71+ "ratelimit::{}::{}" ,
72+ limit_identifier. as_ref( ) ,
73+ client. as_ref( )
74+ ) ;
75+
76+ let now = chrono:: Utc :: now ( ) . timestamp ( ) ;
77+ let expiry = self . client . expiretime ( & key) . await . unwrap_or_default ( ) ;
78+ let expire_unix: u64 = if expiry > now + 2 {
79+ expiry as u64
80+ } else {
81+ now as u64 + limit_window
82+ } ;
83+
84+ let limit_used = self . client . get :: < u64 > ( & key) . await . unwrap_or_default ( ) + 1 ;
85+ self . client
86+ . set_with_options ( key, limit_used, None , SetExpiration :: Exat ( expire_unix) )
87+ . await ?;
88+
89+ if limit_used >= limit {
90+ return Err ( ApiResponse :: error ( & format ! (
91+ "you are ratelimited, retry in {}s" ,
92+ expiry - now
93+ ) )
94+ . with_status ( StatusCode :: TOO_MANY_REQUESTS ) ) ;
95+ }
96+
97+ Ok ( ( ) )
98+ }
99+
62100 #[ tracing:: instrument( skip( self , fn_compute) ) ]
63101 pub async fn cached < T , F , Fut > (
64102 & self ,
@@ -83,13 +121,7 @@ impl Cache {
83121
84122 let serialized = rmp_serde:: to_vec ( & result) ?;
85123 self . client
86- . set_with_options (
87- key,
88- serialized,
89- SetCondition :: None ,
90- SetExpiration :: Ex ( ttl) ,
91- false ,
92- )
124+ . set_with_options ( key, serialized, None , SetExpiration :: Ex ( ttl) )
93125 . await ?;
94126
95127 Ok ( result)
0 commit comments