cal_redis/
constants.rs

1// File: cal-redis/src/constants.rs
2
3/// Base prefix for all Redis keys
4pub const KEY_PREFIX: &str = "cal";
5
6/// Separator for key components
7pub const KEY_SEPARATOR: &str = ":";
8
9// ==================== Global Keys (not account-scoped) ====================
10
11/// Regions hash - stores all jambonz objects
12/// Format: cal:jambonz
13pub const JAMBONZ_KEY: &str = "cal:jambonz";
14
15/// Regions hash - stores all regions
16/// Format: cal:regions
17pub const REGIONS_KEY: &str = "cal:regions";
18
19/// Region identifiers hash - maps various IDs to region ID
20/// Format: cal:region:idents
21pub const REGION_IDENTS_KEY: &str = "cal:region:idents";
22
23/// Proxies hash - stores all proxies
24/// Format: cal:proxies
25pub const PROXIES_KEY: &str = "cal:proxies";
26
27/// WebSocket connections hash - maps connection ID to account ID
28/// Format: cal:ws:connections
29pub const WS_CONNECTIONS_KEY: &str = "cal:ws:connections";
30
31/// Global events channel
32/// Format: cal:events
33pub const GLOBAL_EVENTS_CHANNEL: &str = "cal:events";
34
35// ==================== Account-Scoped Keys ====================
36
37/// Accounts hash - stores account summaries
38/// Format: cal:accounts
39pub const ACCOUNTS_KEY: &str = "cal:accounts";
40
41/// Account identifiers hash - maps various IDs to account ID
42/// Format: cal:account:idents
43pub const ACCOUNT_IDENTS_KEY: &str = "cal:account:idents";
44
45/// Users hash - stores all users
46/// Format: cal:users
47pub const USERS_KEY: &str = "cal:users";
48
49/// User identifiers hash - maps email/username to user ID
50/// Format: cal:user:idents
51pub const USER_IDENTS_KEY: &str = "cal:user:idents";
52
53// ==================== Key Builders ====================
54
55/// Build a key with the standard prefix
56#[inline]
57pub fn build_key(components: &[&str]) -> String {
58    let mut key = String::with_capacity(128);
59    key.push_str(KEY_PREFIX);
60    for component in components {
61        key.push_str(KEY_SEPARATOR);
62        key.push_str(component);
63    }
64    key
65}
66
67/// Build an account-scoped key
68#[inline]
69pub fn build_account_key(account_id: &str, components: &[&str]) -> String {
70    let mut parts = vec!["account", account_id];
71    parts.extend_from_slice(components);
72    build_key(&parts)
73}
74
75/// Build a trunk lookup key
76#[inline]
77pub fn build_trunk_key(trunk_ip: &str) -> String {
78    build_key(&["trunk", trunk_ip])
79}
80
81// ==================== Account Collection Keys ====================
82
83pub struct AccountKeys;
84
85impl AccountKeys {
86    /// Account devices hash
87    /// Format: cal:account:{account_id}:devices
88    pub fn devices(account_id: &str) -> String {
89        build_account_key(account_id, &["devices"])
90    }
91
92    /// Account device identifiers hash
93    /// Format: cal:account:{account_id}:device:idents
94    pub fn device_idents(account_id: &str) -> String {
95        build_account_key(account_id, &["device", "idents"])
96    }
97
98    /// Account DDIs hash
99    /// Format: cal:account:{account_id}:ddis
100    pub fn ddis(account_id: &str) -> String {
101        build_account_key(account_id, &["ddis"])
102    }
103
104    /// Account trunks hash
105    /// Format: cal:account:{account_id}:trunks
106    pub fn trunks(account_id: &str) -> String {
107        build_account_key(account_id, &["trunks"])
108    }
109
110    /// Account hooks hash
111    /// Format: cal:account:{account_id}:hooks
112    pub fn hooks(account_id: &str) -> String {
113        build_account_key(account_id, &["hooks"])
114    }
115
116    /// Account assets hash
117    /// Format: cal:account:{account_id}:assets
118    pub fn assets(account_id: &str) -> String {
119        build_account_key(account_id, &["assets"])
120    }
121
122    /// Account addresses hash
123    /// Format: cal:account:{account_id}:addresses
124    pub fn addresses(account_id: &str) -> String {
125        build_account_key(account_id, &["addresses"])
126    }
127
128    // Account contacts hash
129    /// Format: cal:account:{account_id}:contacts
130    pub fn contacts(account_id: &str) -> String {
131        build_account_key(account_id, &["contacts"])
132    }
133
134    /// Account contact identifiers hash (phone numbers and emails to contact ID mapping)
135    /// Format: cal:account:{account_id}:contact:idents
136    pub fn contact_idents(account_id: &str) -> String {
137        build_account_key(account_id, &["contact", "idents"])
138    }
139}
140
141// ==================== Agent Keys ====================
142
143pub struct AgentKeys;
144
145impl AgentKeys {
146    /// Agent status
147    /// Format: cal:account:{account_id}:agent:status:{user_id}
148    pub fn status(account_id: &str, user_id: &str) -> String {
149        build_account_key(account_id, &["agent", "status", user_id])
150    }
151
152    /// Account agents by user hash
153    /// Format: cal:account:{account_id}:agents:by_user
154    pub fn by_user(account_id: &str) -> String {
155        build_account_key(account_id, &["agents", "by_user"])
156    }
157
158    /// Account registered agents set
159    /// Format: cal:account:{account_id}:agents:registered
160    pub fn registered(account_id: &str) -> String {
161        build_account_key(account_id, &["agents", "registered"])
162    }
163
164    /// Account available agents set
165    /// Format: cal:account:{account_id}:agents:available
166    pub fn available(account_id: &str) -> String {
167        build_account_key(account_id, &["agents", "available"])
168    }
169
170    /// Account connected agents set
171    /// Format: cal:account:{account_id}:agents:connected
172    pub fn connected(account_id: &str) -> String {
173        build_account_key(account_id, &["agents", "connected"])
174    }
175}
176
177// ==================== Session Keys ====================
178
179pub struct SessionKeys;
180
181impl SessionKeys {
182    /// Session data
183    /// Format: cal:account:{account_id}:session:{session_id}
184    pub fn session(account_id: &str, session_id: &str) -> String {
185        build_account_key(account_id, &["session", session_id])
186    }
187
188    /// Active sessions set
189    /// Format: cal:account:{account_id}:sessions:active
190    pub fn active(account_id: &str) -> String {
191        build_account_key(account_id, &["sessions", "active"])
192    }
193}
194
195// ==================== Queue Keys ====================
196
197pub struct QueueKeys;
198
199impl QueueKeys {
200    /// Queue data
201    /// Format: cal:account:{account_id}:queue:{queue_name}
202    pub fn queue(account_id: &str, queue_name: &str) -> String {
203        build_account_key(account_id, &["queue", queue_name])
204    }
205
206    /// Queue metadata hash
207    /// Format: cal:account:{account_id}:queues:meta
208    pub fn metadata(account_id: &str) -> String {
209        build_account_key(account_id, &["queues", "meta"])
210    }
211
212    /// Active queues set
213    /// Format: cal:account:{account_id}:queues:active
214    pub fn active(account_id: &str) -> String {
215        build_account_key(account_id, &["queues", "active"])
216    }
217}
218
219// ==================== Conversation Keys ====================
220
221pub struct ConversationKeys;
222
223impl ConversationKeys {
224    /// Conversation data
225    /// Format: cal:account:{account_id}:conversation:{conversation_id}
226    pub fn conversation(account_id: &str, conversation_id: &str) -> String {
227        build_account_key(account_id, &["conversation", conversation_id])
228    }
229
230    /// Active conversations set
231    /// Format: cal:account:{account_id}:conversations:active
232    pub fn active(account_id: &str) -> String {
233        build_account_key(account_id, &["conversations", "active"])
234    }
235
236    /// Conversations by phone number
237    /// Format: cal:account:{account_id}:conversations:by_phone
238    pub fn by_phone(account_id: &str) -> String {
239        build_account_key(account_id, &["conversations", "by_phone"])
240    }
241}
242
243// ==================== Channel Keys ====================
244
245pub struct ChannelKeys;
246
247impl ChannelKeys {
248    /// Account events channel
249    /// Format: cal:account:{account_id}:events
250    pub fn account_events(account_id: &str) -> String {
251        build_account_key(account_id, &["events"])
252    }
253
254    /// Agent events channel
255    /// Format: cal:account:{account_id}:agent:{user_id}:events
256    pub fn agent_events(account_id: &str, user_id: &str) -> String {
257        build_account_key(account_id, &["agent", user_id, "events"])
258    }
259}
260
261// ==================== Helper Functions ====================
262
263/// Extract account ID from a key
264/// Returns None if the key doesn't follow the account pattern
265pub fn extract_account_id(key: &str) -> Option<&str> {
266    let parts: Vec<&str> = key.split(KEY_SEPARATOR).collect();
267    if parts.len() >= 3 && parts[0] == KEY_PREFIX && parts[1] == "account" {
268        Some(parts[2])
269    } else {
270        None
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use super::*;
277
278    #[test]
279    fn test_build_key() {
280        assert_eq!(build_key(&["test", "key"]), "cal:test:key");
281    }
282
283    #[test]
284    fn test_build_account_key() {
285        assert_eq!(
286            build_account_key("123", &["devices"]),
287            "cal:account:123:devices"
288        );
289    }
290
291    #[test]
292    fn test_extract_account_id() {
293        assert_eq!(
294            extract_account_id("cal:account:123:devices"),
295            Some("123")
296        );
297        assert_eq!(
298            extract_account_id("cal:regions"),
299            None
300        );
301    }
302}