valkey_module/context/
client.rs

1use crate::{
2    Context, RedisModuleClientInfo, RedisModule_DeauthenticateAndCloseClient,
3    RedisModule_GetClientCertificate, RedisModule_GetClientId, RedisModule_GetClientInfoById,
4    RedisModule_GetClientNameById, RedisModule_GetClientUserNameById,
5    RedisModule_SetClientNameById, Status, ValkeyError, ValkeyResult, ValkeyString, ValkeyValue
6};
7use std::ffi::CStr;
8use std::os::raw::c_void;
9
10impl RedisModuleClientInfo {
11    fn new() -> Self {
12        Self {
13            version: 1,
14            flags: 0,
15            id: 0,
16            addr: [0; 46],
17            port: 0,
18            db: 0,
19        }
20    }
21}
22
23/// GetClientNameById, GetClientUserNameById and GetClientCertificate use autoMemoryAdd on the ValkeyModuleString pointer
24/// after the callback (command, server event handler, ...) these ValkeyModuleString pointers will be freed automatically
25impl Context {
26    pub fn get_client_id(&self) -> u64 {
27        unsafe { RedisModule_GetClientId.unwrap()(self.ctx) }
28    }
29
30    /// wrapper for RedisModule_GetClientNameById
31    pub fn get_client_name_by_id(&self, client_id: u64) -> ValkeyResult<ValkeyString> {
32        let client_name = unsafe { RedisModule_GetClientNameById.unwrap()(self.ctx, client_id) };
33        if client_name.is_null() {
34            Err(ValkeyError::Str("Client/Client name is null"))
35        } else {
36            Ok(ValkeyString::from_redis_module_string(
37                self.ctx,
38                client_name,
39            ))
40        }
41    }
42
43    /// wrapper for RedisModule_GetClientNameById using current client ID
44    pub fn get_client_name(&self) -> ValkeyResult<ValkeyString> {
45        self.get_client_name_by_id(self.get_client_id())
46    }
47
48    /// wrapper for RedisModule_SetClientNameById
49    pub fn set_client_name_by_id(&self, client_id: u64, client_name: &ValkeyString) -> Status {
50        let resp = unsafe { RedisModule_SetClientNameById.unwrap()(client_id, client_name.inner) };
51        Status::from(resp)
52    }
53
54    /// wrapper for RedisModule_SetClientNameById using current client ID
55    pub fn set_client_name(&self, client_name: &ValkeyString) -> Status {
56        self.set_client_name_by_id(self.get_client_id(), client_name)
57    }
58
59    /// wrapper for RedisModule_GetClientUserNameById
60    pub fn get_client_username_by_id(&self, client_id: u64) -> ValkeyResult<ValkeyString> {
61        let client_username =
62            unsafe { RedisModule_GetClientUserNameById.unwrap()(self.ctx, client_id) };
63        if client_username.is_null() {
64            Err(ValkeyError::Str("Client/Username is null"))
65        } else {
66            Ok(ValkeyString::from_redis_module_string(
67                self.ctx,
68                client_username,
69            ))
70        }
71    }
72
73    /// wrapper for RedisModule_GetClientUserNameById using current client ID
74    pub fn get_client_username(&self) -> ValkeyResult<ValkeyString> {
75        self.get_client_username_by_id(self.get_client_id())
76    }
77
78    /// wrapper for RedisModule_GetClientCertificate
79    pub fn get_client_cert(&self) -> ValkeyResult<ValkeyString> {
80        let client_id = self.get_client_id();
81        let client_cert = unsafe { RedisModule_GetClientCertificate.unwrap()(self.ctx, client_id) };
82        if client_cert.is_null() {
83            Err(ValkeyError::Str("Client/Cert is null"))
84        } else {
85            Ok(ValkeyString::from_redis_module_string(
86                self.ctx,
87                client_cert,
88            ))
89        }
90    }
91
92    /// wrapper for RedisModule_GetClientInfoById
93    pub fn get_client_info_by_id(&self, client_id: u64) -> ValkeyResult<RedisModuleClientInfo> {
94        let mut mci = RedisModuleClientInfo::new();
95        let mci_ptr: *mut c_void = &mut mci as *mut _ as *mut c_void;
96        unsafe {
97            RedisModule_GetClientInfoById.unwrap()(mci_ptr, client_id);
98        };
99        if mci_ptr.is_null() {
100            Err(ValkeyError::Str("Client/Info is null"))
101        } else {
102            Ok(mci)
103        }
104    }
105
106    /// wrapper for RedisModule_GetClientInfoById using current client ID
107    pub fn get_client_info(&self) -> ValkeyResult<RedisModuleClientInfo> {
108        self.get_client_info_by_id(self.get_client_id())
109    }
110
111    /// wrapper to get the client IP address from RedisModuleClientInfo
112    pub fn get_client_ip_by_id(&self, client_id: u64) -> ValkeyResult<String> {
113        let client_info = self.get_client_info_by_id(client_id)?;
114        let c_str_addr = unsafe { CStr::from_ptr(client_info.addr.as_ptr()) };
115        let ip_addr_as_string = c_str_addr.to_string_lossy().into_owned();
116        Ok(ip_addr_as_string)
117    }
118
119    /// wrapper to get the client IP address from RedisModuleClientInfo using current client ID
120    pub fn get_client_ip(&self) -> ValkeyResult<String> {
121        self.get_client_ip_by_id(self.get_client_id())
122    }
123    
124    pub fn deauthenticate_and_close_client_by_id(&self, client_id: u64) -> Status {
125        let resp =
126            unsafe { RedisModule_DeauthenticateAndCloseClient.unwrap()(self.ctx, client_id) };
127        Status::from(resp)
128    }
129
130    pub fn deauthenticate_and_close_client(&self) -> Status {
131        self.deauthenticate_and_close_client_by_id(self.get_client_id())
132    }
133
134    pub fn config_get(&self, config: String) -> ValkeyResult<ValkeyString> {
135        match self.call("CONFIG", &["GET", &config])? {
136            ValkeyValue::Array(array) if array.len() == 2 => match &array[1] {
137                ValkeyValue::SimpleString(val) => Ok(ValkeyString::create(None, val.clone())),
138                _ => Err(ValkeyError::Str("Config value is not a string")),
139            },
140            _ => Err(ValkeyError::Str("Unexpected CONFIG GET response")),
141        }
142    }
143}