cal_core/
queue.rs

1// File: cal-core/src/queue.rs
2
3use crate::{ContactRef, RecordReference};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::collections::{BTreeMap, VecDeque};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct QueueGroup {
11    pub name: String,
12    #[serde(rename = "type")]
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub queue_type: Option<String>,
15    pub device_id: String,
16    pub account_id: String,
17    pub entries: VecDeque<Entry>,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct Entry {
23    pub call_sid: String,
24    pub from: String,
25    pub priority: i32,
26    pub timestamp: i64,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub contact: Option<ContactRef>,
29}
30
31impl QueueGroup {
32    pub fn new(name: String, queue_type: Option<String>, device_id: String, account_id: String) -> Self {
33        Self {
34            name,
35            queue_type,
36            device_id,
37            account_id,
38            entries: VecDeque::new(),
39        }
40    }
41
42    pub fn get_type(&self) -> String {
43        self.queue_type.clone().unwrap_or_else(|| "callable-queue".to_string())
44    }
45
46    pub fn add(&mut self, call_sid: String, from: String, priority: i32, contact: Option<ContactRef>) -> Entry {
47        let entry = Entry {
48            call_sid: call_sid.clone(),
49            from,
50            priority,
51            timestamp: chrono::Utc::now().timestamp_millis(),
52            contact,
53        };
54        self.entries.push_back(entry.clone());
55        entry
56    }
57
58    pub fn remove(&mut self, call_sid: &str) {
59        self.entries.retain(|entry| entry.call_sid != call_sid);
60    }
61
62    pub fn pop(&mut self) -> Option<Entry> {
63        self.entries.pop_front()
64    }
65
66    pub fn pop_by_priority(&mut self) -> Option<Entry> {
67        if self.entries.is_empty() {
68            return None;
69        }
70
71        // Find the index of the entry with the minimum prioritized timestamp
72        let min_index = self.entries
73            .iter()
74            .enumerate()
75            .min_by_key(|(_, entry)| entry.get_prioritized_timestamp())
76            .map(|(index, _)| index)?;
77
78        // Remove and return the entry at that index
79        self.entries.remove(min_index)
80    }
81}
82
83impl Entry {
84    pub fn get_prioritized_timestamp(&self) -> i64 {
85        // Lower priority number = higher priority (1 is highest)
86        // Multiply by -1 to reverse the order so lower numbers come first
87        self.timestamp * (self.priority as i64) * -1
88    }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct QueueStat {
94    #[serde(rename = "_id")]
95    pub id: String,
96    pub timestamp: DateTime<Utc>,
97    pub meta: MetaData,
98    pub entry: Entry,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub user: Option<RecordReference>,
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub contact: Option<ContactRef>,
103    pub queue_name: String,
104    pub queue_time: Option<i64>,
105    pub queue_count: Option<i64>,
106    pub status: String,
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub data: Option<BTreeMap<String, String>>,
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct MetaData {
114    pub account: RecordReference,
115    pub device: RecordReference,
116}
117
118impl QueueStat {
119    pub fn new(
120        id: String,
121        timestamp: DateTime<Utc>,
122        meta: MetaData,
123        entry: Entry,
124        user: Option<RecordReference>,
125        contact: Option<ContactRef>,
126        queue_name: String,
127        queue_time: Option<i64>,
128        queue_count: Option<i64>,
129        status: String,
130        data: Option<BTreeMap<String, String>>,
131    ) -> Self {
132        Self {
133            id,
134            timestamp,
135            meta,
136            entry,
137            user,
138            contact,
139            queue_name,
140            queue_time,
141            queue_count,
142            status,
143            data,
144        }
145    }
146}
147
148impl MetaData {
149    pub fn new(account: RecordReference, device: RecordReference) -> Self {
150        Self { account, device }
151    }
152}
153
154// If you need Display implementations
155impl std::fmt::Display for QueueStat {
156    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157        write!(
158            f,
159            "QueueStat(id={}, timestamp={}, meta={:?}, entry={:?}, user={:?}, contact={:?}, \
160             queueName={}, queueTime={:?}, queueCount={:?}, status={}, data={:?})",
161            self.id,
162            self.timestamp,
163            self.meta,
164            self.entry,
165            self.user,
166            self.contact,
167            self.queue_name,
168            self.queue_time,
169            self.queue_count,
170            self.status,
171            self.data
172        )
173    }
174}
175
176impl std::fmt::Display for MetaData {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        write!(
179            f,
180            "QueueStat.MetaData(account={:?}, device={:?})",
181            self.account, self.device
182        )
183    }
184}