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 RepoRegister {
27 name: String,
28 path: String,
29 },
30 RepoUnregister {
31 name: String,
32 },
33 RepoList,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(tag = "type", content = "data")]
38pub enum Response {
39 Pong,
40 Ok,
41 DaemonStatus(DaemonStatus),
42 ClientInfo(ClientInfo),
43 Pair(PairPayload),
45 PairedClient(PairedClient),
46 PairedClients(Vec<PairedClient>),
47 Revoked(u32),
49 Repo(RepoInfo),
50 Repos(Vec<RepoInfo>),
51 Error(VexProtoError),
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct DaemonStatus {
56 pub uptime_secs: u64,
57 pub connected_clients: u32,
58 pub version: String,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct PairPayload {
64 pub token_id: String,
65 pub token_secret: String,
66 pub host: Option<String>,
68}
69
70impl PairPayload {
71 pub fn pairing_string(&self) -> String {
73 format!("{}:{}", self.token_id, self.token_secret)
74 }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct PairedClient {
79 pub token_id: String,
80 pub label: Option<String>,
81 pub created_at: String,
82 pub expires_at: Option<String>,
83 pub last_seen: Option<String>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct RepoInfo {
88 pub name: String,
89 pub path: String,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct ClientInfo {
94 pub token_id: Option<String>,
95 pub is_local: bool,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum Transport {
101 Unix,
102 Tcp,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106#[serde(tag = "code", content = "message")]
107pub enum VexProtoError {
108 Unauthorized,
109 LocalOnly,
110 NotFound,
111 Internal(String),
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct AuthToken {
117 pub token_id: String,
118 pub token_secret: String,
120}
121
122pub mod framing {
125 use serde::{Deserialize, Serialize};
126 use std::io;
127 use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
128
129 #[derive(Debug)]
130 pub enum VexFrameError {
131 Io(io::Error),
132 Json(serde_json::Error),
133 }
134
135 impl std::fmt::Display for VexFrameError {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 match self {
138 VexFrameError::Io(e) => write!(f, "IO error: {e}"),
139 VexFrameError::Json(e) => write!(f, "JSON error: {e}"),
140 }
141 }
142 }
143
144 impl std::error::Error for VexFrameError {}
145
146 impl From<io::Error> for VexFrameError {
147 fn from(e: io::Error) -> Self {
148 VexFrameError::Io(e)
149 }
150 }
151
152 impl From<serde_json::Error> for VexFrameError {
153 fn from(e: serde_json::Error) -> Self {
154 VexFrameError::Json(e)
155 }
156 }
157
158 pub async fn send<W, T>(w: &mut W, msg: &T) -> Result<(), VexFrameError>
160 where
161 W: AsyncWrite + Unpin,
162 T: Serialize,
163 {
164 let body = serde_json::to_vec(msg)?;
165 w.write_u32(body.len() as u32).await?;
166 w.write_all(&body).await?;
167 Ok(())
168 }
169
170 pub async fn recv<R, T>(r: &mut R) -> Result<T, VexFrameError>
172 where
173 R: AsyncRead + Unpin,
174 T: for<'de> Deserialize<'de>,
175 {
176 let len = r.read_u32().await?;
177 let mut buf = vec![0u8; len as usize];
178 r.read_exact(&mut buf).await?;
179 Ok(serde_json::from_slice(&buf)?)
180 }
181}