clia_sse_msg_codec/
lib.rs

1//! Encode and Decode SSE Messages
2
3const ID_HEAD: &str = "id: ";
4const EVENT_HEAD: &str = "event: ";
5const DATA_HEAD: &str = "data: ";
6
7/// Parsed SSE Message struct
8#[derive(Debug, Clone, Eq, PartialEq)]
9pub struct SseMsg {
10    pub id: Option<String>,
11    pub event: Option<String>,
12    pub data: Option<String>,
13}
14
15/// Encode a SSE message
16pub fn encode(id: Option<&str>, event: Option<&str>, data: Option<&str>) -> String {
17    let mut result = String::new();
18
19    if let Some(id) = id {
20        result.push_str("id: ");
21        result.push_str(id);
22        result.push_str("\n");
23    }
24    if let Some(event) = event {
25        result.push_str("event: ");
26        result.push_str(event);
27        result.push_str("\n");
28    }
29    if let Some(data) = data {
30        let processed = data.replace("\n", "\ndata: ");
31        result.push_str("data: ");
32        result.push_str(&processed);
33        result.push_str("\n");
34    }
35    result.push_str("\n");
36    result
37}
38
39/// Decode a SSE message
40pub fn decode(msg: &str) -> SseMsg {
41    let mut sse_msg = SseMsg {
42        id: None,
43        event: None,
44        data: None,
45    };
46    
47    let v: Vec<&str> = msg.split('\n').collect();
48
49    let mut data = String::new();
50    
51    for line in v {
52        if line.starts_with(ID_HEAD) {
53            sse_msg.id = Some(line[ID_HEAD.len()..].to_string());
54        } else if line.starts_with("event: ") {
55            sse_msg.event = Some(line[EVENT_HEAD.len()..].to_string());
56        } else if line.starts_with("data: ") {
57            if data.len() > 0 {
58                data.push_str("\n");
59            }
60            data.push_str(&line[DATA_HEAD.len()..]);
61        }
62    }
63
64    if data.len() > 0 {
65        sse_msg.data = Some(data);
66    }
67
68    sse_msg
69}
70
71#[cfg(test)]
72mod tests {
73    use super::SseMsg;
74
75    #[test]
76    fn test_encode() {
77        let encoded = super::encode(Some("test-id"), Some("test-event"), Some("test-data line1\nline2"));
78        assert_eq!(encoded, "id: test-id\nevent: test-event\ndata: test-data line1\ndata: line2\n\n".to_owned());
79    }
80
81    #[test]
82    fn test_decode() {
83        let msg = "id: test-id\nevent: test-event\ndata: test-data line1\ndata: line2\n\n";
84        let decoded = super::decode(msg);
85        assert_eq!(decoded, SseMsg {
86            id: Some("test-id".to_owned()),
87            event: Some("test-event".to_owned()),
88            data: Some("test-data line1\nline2".to_owned()),
89        });
90    }
91}