Skip to main content

lfsx_server/
model.rs

1use serde::{Deserialize, Serialize};
2
3use crate::locks::Lock;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum Operation {
8    Upload,
9    Download,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize)]
13pub struct ObjectId {
14    pub oid: String,
15    pub size: u64,
16}
17
18#[derive(Debug, Deserialize)]
19pub struct BatchRequest {
20    pub operation: Operation,
21    #[serde(default)]
22    pub transfers: Vec<String>,
23    pub objects: Vec<ObjectId>,
24}
25
26#[derive(Debug, Deserialize)]
27pub struct RetainRequest {
28    pub oids: Vec<String>,
29    #[serde(default)]
30    pub dry_run: bool,
31}
32
33#[derive(Debug, Deserialize)]
34pub struct DedupeRequest {
35    #[serde(default)]
36    pub dry_run: bool,
37}
38
39#[derive(Debug, Serialize)]
40pub struct BatchResponse {
41    pub transfer: &'static str,
42    pub objects: Vec<ObjectSpec>,
43}
44
45#[derive(Debug, Serialize)]
46pub struct ObjectSpec {
47    #[serde(flatten)]
48    pub id: ObjectId,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub actions: Option<Actions>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub error: Option<ObjectError>,
53}
54
55#[derive(Debug, Default, Serialize)]
56pub struct Actions {
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub upload: Option<Action>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub download: Option<Action>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub verify: Option<Action>,
63}
64
65#[derive(Debug, Serialize)]
66pub struct Action {
67    pub href: String,
68    pub expires_in: u32,
69}
70
71#[derive(Debug, Serialize)]
72pub struct ObjectError {
73    pub code: u16,
74    pub message: String,
75}
76
77impl ObjectSpec {
78    pub fn missing(id: ObjectId) -> Self {
79        Self {
80            id,
81            actions: None,
82            error: Some(ObjectError {
83                code: 404,
84                message: "object not found".into(),
85            }),
86        }
87    }
88
89    pub fn too_large(id: ObjectId, limit: u64) -> Self {
90        Self {
91            error: Some(ObjectError {
92                code: 413,
93                message: format!(
94                    "object is {} bytes, over the {limit} byte limit this server accepts",
95                    id.size
96                ),
97            }),
98            id,
99            actions: None,
100        }
101    }
102
103    pub fn over_quota(id: ObjectId, used: u64, limit: u64) -> Self {
104        Self {
105            id,
106            actions: None,
107            error: Some(ObjectError {
108                code: 507,
109                message: format!(
110                    "this repository holds {used} bytes of its {limit} byte budget — collect what \
111                     it no longer references, or ask for more room"
112                ),
113            }),
114        }
115    }
116}
117
118#[derive(Debug, Deserialize)]
119pub struct CreateLockRequest {
120    pub path: String,
121}
122
123#[derive(Debug, Deserialize)]
124pub struct ListLocksQuery {
125    pub path: Option<String>,
126    pub id: Option<String>,
127}
128
129#[derive(Debug, Default, Deserialize)]
130pub struct VerifyLocksRequest {}
131
132#[derive(Debug, Deserialize)]
133pub struct UnlockRequest {
134    #[serde(default)]
135    pub force: bool,
136}
137
138#[derive(Debug, Serialize)]
139pub struct LockResponse {
140    pub lock: Lock,
141}
142
143#[derive(Debug, Serialize)]
144pub struct ListLocksResponse {
145    pub locks: Vec<Lock>,
146    pub next_cursor: &'static str,
147}
148
149#[derive(Debug, Serialize)]
150pub struct VerifyLocksResponse {
151    pub ours: Vec<Lock>,
152    pub theirs: Vec<Lock>,
153    pub next_cursor: &'static str,
154}
155
156#[derive(Debug, Serialize)]
157pub struct StatsResponse {
158    pub objects: u64,
159    pub bytes: u64,
160    pub locks: usize,
161}