kanata_tcp_protocol/
lib.rs

1use serde::{Deserialize, Serialize};
2use std::str::FromStr;
3
4#[derive(Debug, Serialize, Deserialize)]
5pub enum ServerMessage {
6    LayerChange { new: String },
7    LayerNames { names: Vec<String> },
8    CurrentLayerInfo { name: String, cfg_text: String },
9    ConfigFileReload { new: String },
10    CurrentLayerName { name: String },
11    MessagePush { message: serde_json::Value },
12    Error { msg: String },
13}
14
15#[derive(Serialize, Deserialize, Debug)]
16#[serde(tag = "status")]
17pub enum ServerResponse {
18    Ok,
19    Error { msg: String },
20}
21
22impl ServerResponse {
23    pub fn as_bytes(&self) -> Vec<u8> {
24        let mut msg = serde_json::to_vec(self).expect("ServerResponse should serialize");
25        msg.push(b'\n');
26        msg
27    }
28}
29
30impl ServerMessage {
31    pub fn as_bytes(&self) -> Vec<u8> {
32        let mut msg = serde_json::to_vec(self).expect("ServerMessage should serialize");
33        msg.push(b'\n');
34        msg
35    }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub enum ClientMessage {
40    ChangeLayer {
41        new: String,
42    },
43    RequestLayerNames {},
44    RequestCurrentLayerInfo {},
45    RequestCurrentLayerName {},
46    ActOnFakeKey {
47        name: String,
48        action: FakeKeyActionMessage,
49    },
50    SetMouse {
51        x: u16,
52        y: u16,
53    },
54    Reload {},
55    ReloadNext {},
56    ReloadPrev {},
57    ReloadNum {
58        index: usize,
59    },
60    ReloadFile {
61        path: String,
62    },
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
66pub enum FakeKeyActionMessage {
67    Press,
68    Release,
69    Tap,
70    Toggle,
71}
72
73impl FromStr for ClientMessage {
74    type Err = serde_json::Error;
75
76    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
77        serde_json::from_str(s)
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_server_response_json_format() {
87        // Test that our API contract matches expected JSON structure
88        assert_eq!(
89            serde_json::to_string(&ServerResponse::Ok).unwrap(),
90            r#"{"status":"Ok"}"#
91        );
92        assert_eq!(
93            serde_json::to_string(&ServerResponse::Error {
94                msg: "test".to_string()
95            })
96            .unwrap(),
97            r#"{"status":"Error","msg":"test"}"#
98        );
99    }
100
101    #[test]
102    fn test_as_bytes_includes_newline() {
103        // Test our specific logic that adds newline termination
104        let response = ServerResponse::Ok;
105        let bytes = response.as_bytes();
106        assert!(bytes.ends_with(b"\n"), "Response should end with newline");
107
108        let error_response = ServerResponse::Error {
109            msg: "test".to_string(),
110        };
111        let error_bytes = error_response.as_bytes();
112        assert!(
113            error_bytes.ends_with(b"\n"),
114            "Error response should end with newline"
115        );
116    }
117}