1use serde::{Deserialize, Serialize};
2
3pub const DEFAULT_TCP_PORT: u16 = 7422;
5
6pub const DEFAULT_HTTP_PORT: u16 = 7423;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(tag = "type", content = "data")]
13pub enum Command {
14 Status,
15 Whoami,
16 PairCreate {
17 label: Option<String>,
18 expire_secs: Option<u64>,
20 },
21 PairList,
22 PairRevoke {
23 id: String,
24 },
25 PairRevokeAll,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(tag = "type", content = "data")]
30pub enum Response {
31 Pong,
32 Ok,
33 DaemonStatus(DaemonStatus),
34 ClientInfo(ClientInfo),
35 Pair(PairPayload),
37 PairedClient(PairedClient),
38 PairedClients(Vec<PairedClient>),
39 Revoked(u32),
41 Error(VexProtoError),
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct DaemonStatus {
46 pub uptime_secs: u64,
47 pub connected_clients: u32,
48 pub version: String,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct PairPayload {
54 pub token_id: String,
55 pub token_secret: String,
56 pub host: Option<String>,
58}
59
60impl PairPayload {
61 pub fn pairing_string(&self) -> String {
63 format!("{}:{}", self.token_id, self.token_secret)
64 }
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct PairedClient {
69 pub token_id: String,
70 pub label: Option<String>,
71 pub created_at: String,
72 pub expires_at: Option<String>,
73 pub last_seen: Option<String>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ClientInfo {
78 pub token_id: Option<String>,
79 pub is_local: bool,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(rename_all = "snake_case")]
84pub enum Transport {
85 Unix,
86 Tcp,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(tag = "code", content = "message")]
91pub enum VexProtoError {
92 Unauthorized,
93 LocalOnly,
94 NotFound,
95 Internal(String),
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct AuthToken {
101 pub token_id: String,
102 pub token_secret: String,
104}
105
106pub mod framing {
109 use serde::{Deserialize, Serialize};
110 use std::io;
111 use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
112
113 #[derive(Debug)]
114 pub enum VexFrameError {
115 Io(io::Error),
116 Json(serde_json::Error),
117 }
118
119 impl std::fmt::Display for VexFrameError {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 match self {
122 VexFrameError::Io(e) => write!(f, "IO error: {e}"),
123 VexFrameError::Json(e) => write!(f, "JSON error: {e}"),
124 }
125 }
126 }
127
128 impl std::error::Error for VexFrameError {}
129
130 impl From<io::Error> for VexFrameError {
131 fn from(e: io::Error) -> Self {
132 VexFrameError::Io(e)
133 }
134 }
135
136 impl From<serde_json::Error> for VexFrameError {
137 fn from(e: serde_json::Error) -> Self {
138 VexFrameError::Json(e)
139 }
140 }
141
142 pub async fn send<W, T>(w: &mut W, msg: &T) -> Result<(), VexFrameError>
144 where
145 W: AsyncWrite + Unpin,
146 T: Serialize,
147 {
148 let body = serde_json::to_vec(msg)?;
149 w.write_u32(body.len() as u32).await?;
150 w.write_all(&body).await?;
151 Ok(())
152 }
153
154 pub async fn recv<R, T>(r: &mut R) -> Result<T, VexFrameError>
156 where
157 R: AsyncRead + Unpin,
158 T: for<'de> Deserialize<'de>,
159 {
160 let len = r.read_u32().await?;
161 let mut buf = vec![0u8; len as usize];
162 r.read_exact(&mut buf).await?;
163 Ok(serde_json::from_slice(&buf)?)
164 }
165}