1use serde::{Deserialize, Serialize};
8
9pub const PROTOCOL_VERSION: u32 = 1;
10
11#[derive(Clone, Debug, Serialize, Deserialize)]
12pub struct HandshakeRequest {
13 pub client_version: u32,
14 pub client_name: String,
15}
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct HandshakeResponse {
19 pub server_version: u32,
20 pub server_name: String,
21 pub compatible: bool,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub enum AuthMethod {
26 None,
27 Signature {
28 public_key: String,
29 signature: String,
30 },
31 Token(String),
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub struct AuthRequest {
36 pub method: AuthMethod,
37 pub timestamp: u64,
38}
39
40#[derive(Clone, Debug, Serialize, Deserialize)]
41pub struct HashProto {
42 pub value: String,
43}
44
45#[derive(Clone, Debug, Serialize, Deserialize)]
46pub struct PatchProto {
47 pub id: HashProto,
48 pub operation_type: String,
49 pub touch_set: Vec<String>,
50 pub target_path: Option<String>,
51 pub payload: String,
52 pub parent_ids: Vec<HashProto>,
53 pub author: String,
54 pub message: String,
55 pub timestamp: u64,
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
59pub struct BranchProto {
60 pub name: String,
61 pub target_id: HashProto,
62}
63
64#[derive(Clone, Debug, Serialize, Deserialize)]
65pub struct BlobRef {
66 pub hash: HashProto,
67 pub data: String,
68}
69
70#[derive(Debug, Serialize, Deserialize)]
71pub struct PushRequest {
72 pub repo_id: String,
73 pub patches: Vec<PatchProto>,
74 pub branches: Vec<BranchProto>,
75 pub blobs: Vec<BlobRef>,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
79 pub signature: Option<Vec<u8>>,
80 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub known_branches: Option<Vec<BranchProto>>,
85 #[serde(default)]
87 pub force: bool,
88}
89
90#[derive(Debug, Serialize, Deserialize)]
91pub struct PushResponse {
92 pub success: bool,
93 pub error: Option<String>,
94 pub existing_patches: Vec<HashProto>,
95}
96
97#[derive(Debug, Serialize, Deserialize)]
98pub struct PullRequest {
99 pub repo_id: String,
100 pub known_branches: Vec<BranchProto>,
101 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub max_depth: Option<u32>,
105}
106
107#[derive(Debug, Serialize, Deserialize)]
108pub struct PullResponse {
109 pub success: bool,
110 pub error: Option<String>,
111 pub patches: Vec<PatchProto>,
112 pub branches: Vec<BranchProto>,
113 pub blobs: Vec<BlobRef>,
114}
115
116#[derive(Debug, Serialize, Deserialize)]
117pub struct ListReposResponse {
118 pub repo_ids: Vec<String>,
119}
120
121#[derive(Debug, Serialize, Deserialize)]
122pub struct RepoInfoResponse {
123 pub repo_id: String,
124 pub patch_count: u64,
125 pub branches: Vec<BranchProto>,
126 pub success: bool,
127 pub error: Option<String>,
128}
129
130pub fn hash_to_hex(h: &HashProto) -> String {
131 h.value.clone()
132}
133
134pub fn hex_to_hash(hex: &str) -> HashProto {
135 HashProto {
136 value: hex.to_string(),
137 }
138}
139
140pub fn canonical_push_bytes(req: &PushRequest) -> Vec<u8> {
143 let mut buf = Vec::new();
144
145 buf.extend_from_slice(req.repo_id.as_bytes());
146 buf.push(0);
147
148 buf.extend_from_slice(&(req.patches.len() as u64).to_le_bytes());
149 for patch in &req.patches {
150 buf.extend_from_slice(patch.id.value.as_bytes());
151 buf.push(0);
152 buf.extend_from_slice(patch.operation_type.as_bytes());
153 buf.push(0);
154 buf.extend_from_slice(patch.author.as_bytes());
155 buf.push(0);
156 buf.extend_from_slice(patch.message.as_bytes());
157 buf.push(0);
158 buf.extend_from_slice(&patch.timestamp.to_le_bytes());
159 buf.push(0);
160 }
161
162 buf.extend_from_slice(&(req.branches.len() as u64).to_le_bytes());
163 for branch in &req.branches {
164 buf.extend_from_slice(branch.name.as_bytes());
165 buf.push(0);
166 buf.extend_from_slice(branch.target_id.value.as_bytes());
167 buf.push(0);
168 }
169
170 buf
171}