1use serde::Serialize;
3use serde_json::{Value, json};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
6#[serde(rename_all = "snake_case")]
7pub enum State {
8 Submitted,
9 Queued,
10 Delivered,
11 Failed,
12 Unknown,
13}
14
15impl State {
16 pub fn from_message(message: &Value) -> Self {
17 match message["status"]
18 .as_str()
19 .map(str::to_ascii_lowercase)
20 .as_deref()
21 {
22 Some("delivered") => Self::Delivered,
23 Some("queued" | "pending" | "sending") => Self::Queued,
24 Some("failed") => Self::Failed,
25 Some(_) => Self::Unknown,
27 None if message["source"] == "desktop" => Self::Submitted,
28 None => Self::Unknown,
29 }
30 }
31 pub fn notice(self) -> &'static str {
32 match self {
33 Self::Submitted => "Submitted to Teams; delivery is not confirmed.",
34 Self::Queued => "Queued in Teams; delivery is not confirmed.",
35 Self::Delivered => "Delivered.",
36 Self::Failed => "Teams reports a failed send; check before resending.",
37 Self::Unknown => "Delivery is unknown; check before resending.",
38 }
39 }
40}
41
42pub fn client_message_id() -> String {
43 use rand::Rng;
44 rand::rng()
45 .random_range(100_000_000_000_000_000u64..1_000_000_000_000_000_000)
46 .to_string()
47}
48
49pub fn valid_client_message_id(id: &str) -> bool {
50 id.len() == 18 && id.bytes().all(|b| b.is_ascii_digit())
51}
52
53pub fn reconcile(chat: &str, id: &str, messages: &[Value]) -> Value {
55 let found = messages.iter().find(|m| m["clientMessageId"] == id);
56 json!({"chatId":chat,"clientMessageId":id,"found":found.is_some(),
57 "id":found.and_then(|m| m["id"].as_str()),
58 "status":found.and_then(|m|m["status"].as_str()),
59 "delivery_state":found.map(State::from_message).unwrap_or(State::Unknown),
60 "source":"desktop_cache","scope":"newest_50_cached_messages","retryable":false})
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 #[test]
67 fn success_is_not_delivery_and_unrecognised_labels_remain_unknown() {
68 for (message, expected) in [
69 (json!({"source":"desktop"}), State::Submitted),
70 (json!({"status":"Delivered"}), State::Delivered),
71 (json!({"status":"Queued"}), State::Queued),
72 (json!({"status":"SomeFutureStatus"}), State::Unknown),
73 (json!({"status":"Failed"}), State::Failed),
74 ] {
75 assert_eq!(State::from_message(&message), expected);
76 }
77 }
78 #[test]
79 fn readback_matches_only_the_original_client_id_and_never_infers_failure() {
80 let messages = vec![
81 json!({"id":"1","clientMessageId":"100000000000000001","status":"Delivered","body":{"content":"private"}}),
82 ];
83 let found = reconcile("chat", "100000000000000001", &messages);
84 assert_eq!(found["delivery_state"], "delivered");
85 assert!(found.get("body").is_none());
86 let missing = reconcile("chat", "100000000000000002", &messages);
87 assert_eq!(missing["found"], false);
88 assert_eq!(missing["delivery_state"], "unknown");
89 assert_eq!(missing["retryable"], false);
90 }
91}