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