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, Serialize)]
34pub struct BatchResponse {
35    pub transfer: &'static str,
36    pub objects: Vec<ObjectSpec>,
37}
38
39#[derive(Debug, Serialize)]
40pub struct ObjectSpec {
41    #[serde(flatten)]
42    pub id: ObjectId,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub actions: Option<Actions>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub error: Option<ObjectError>,
47}
48
49#[derive(Debug, Default, Serialize)]
50pub struct Actions {
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub upload: Option<Action>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub download: Option<Action>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub verify: Option<Action>,
57}
58
59#[derive(Debug, Serialize)]
60pub struct Action {
61    pub href: String,
62    pub expires_in: u32,
63}
64
65#[derive(Debug, Serialize)]
66pub struct ObjectError {
67    pub code: u16,
68    pub message: String,
69}
70
71impl ObjectSpec {
72    pub fn missing(id: ObjectId) -> Self {
73        Self {
74            id,
75            actions: None,
76            error: Some(ObjectError {
77                code: 404,
78                message: "object not found".into(),
79            }),
80        }
81    }
82
83    pub fn too_large(id: ObjectId, limit: u64) -> Self {
84        Self {
85            error: Some(ObjectError {
86                code: 413,
87                message: format!(
88                    "object is {} bytes, over the {limit} byte limit this server accepts",
89                    id.size
90                ),
91            }),
92            id,
93            actions: None,
94        }
95    }
96
97    pub fn over_quota(id: ObjectId, used: u64, limit: u64) -> Self {
98        Self {
99            id,
100            actions: None,
101            error: Some(ObjectError {
102                code: 507,
103                message: format!(
104                    "this repository holds {used} bytes of its {limit} byte budget — collect what \
105                     it no longer references, or ask for more room"
106                ),
107            }),
108        }
109    }
110}
111
112#[derive(Debug, Deserialize)]
113pub struct CreateLockRequest {
114    pub path: String,
115}
116
117#[derive(Debug, Deserialize)]
118pub struct ListLocksQuery {
119    pub path: Option<String>,
120    pub id: Option<String>,
121}
122
123#[derive(Debug, Default, Deserialize)]
124pub struct VerifyLocksRequest {}
125
126#[derive(Debug, Deserialize)]
127pub struct UnlockRequest {
128    #[serde(default)]
129    pub force: bool,
130}
131
132#[derive(Debug, Serialize)]
133pub struct LockResponse {
134    pub lock: Lock,
135}
136
137#[derive(Debug, Serialize)]
138pub struct ListLocksResponse {
139    pub locks: Vec<Lock>,
140    pub next_cursor: &'static str,
141}
142
143#[derive(Debug, Serialize)]
144pub struct VerifyLocksResponse {
145    pub ours: Vec<Lock>,
146    pub theirs: Vec<Lock>,
147    pub next_cursor: &'static str,
148}
149
150#[derive(Debug, Serialize)]
151pub struct StatsResponse {
152    pub objects: u64,
153    pub bytes: u64,
154    pub locks: usize,
155}