JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Fixed imports!

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨ef0e853

⁨giterated-daemon/src/database_backend/mod.rs⁩ - ⁨14161⁩ bytes
Raw
1 pub mod handler;
2
3 use std::{str::FromStr, sync::Arc};
4
5 use giterated_models::error::OperationError;
6 use giterated_models::instance::Instance;
7 use giterated_models::object::{GiteratedObject, Object, ObjectRequestError};
8 use giterated_models::object_backend::ObjectBackend;
9 use giterated_models::operation::GiteratedOperation;
10 use giterated_models::repository::Repository;
11 use giterated_models::user::User;
12 use std::fmt::Debug;
13 use tokio::sync::Mutex;
14
15 use crate::backend::{RepositoryBackend, UserBackend};
16
17 use self::handler::{
18 repository_get_setting, repository_get_value, repository_set_setting, user_get_setting,
19 user_get_value, user_set_setting, OperationHandlers,
20 };
21
22 #[derive(Clone, Debug)]
23 pub struct Foobackend {}
24
25 #[async_trait::async_trait]
26 impl ObjectBackend for Foobackend {
27 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
28 &self,
29 _object: O,
30 _operation: D,
31 ) -> Result<D::Success, OperationError<D::Failure>> {
32 // We don't handle operations with this backend
33 Err(OperationError::Unhandled)
34 }
35
36 async fn get_object<O: GiteratedObject + Debug>(
37 &self,
38 _object_str: &str,
39 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
40 Err(OperationError::Unhandled)
41 }
42 }
43
44 /// A backend implementation which attempts to resolve data from the instance's database.
45 #[derive(Clone)]
46 pub struct DatabaseBackend {
47 pub(self) our_instance: Instance,
48 pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>,
49 pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
50 }
51
52 impl Debug for DatabaseBackend {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.debug_struct("DatabaseBackend").finish()
55 }
56 }
57
58 #[async_trait::async_trait]
59 impl ObjectBackend for DatabaseBackend {
60 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
61 &self,
62 object: O,
63 operation: D,
64 ) -> Result<D::Success, OperationError<D::Failure>> {
65 let serialized =
66 serde_json::to_value(operation).map_err(|e| OperationError::Internal(e.to_string()))?;
67 let object = object.to_string();
68 if let Ok(user) = User::from_str(&object) {
69 let mut handler = OperationHandlers::default();
70
71 handler
72 .insert(user_get_value)
73 .insert(user_get_setting)
74 .insert(user_set_setting);
75
76 match handler
77 .handle(
78 &user,
79 D::operation_name(),
80 serde_json::from_value(serialized.clone()).unwrap(),
81 self.clone(),
82 )
83 .await
84 {
85 Ok(result) => Ok(serde_json::from_slice(&result)
86 .map_err(|e| OperationError::Internal(e.to_string()))?),
87 Err(err) => match err {
88 OperationError::Internal(internal) => Err(OperationError::Internal(internal)),
89 OperationError::Unhandled => Err(OperationError::Unhandled),
90 OperationError::Operation(err) => Err(OperationError::Operation(
91 serde_json::from_slice(&err)
92 .map_err(|e| OperationError::Internal(e.to_string()))?,
93 )),
94 },
95 }
96 } else if let Ok(repository) = Repository::from_str(&object) {
97 let mut handler = OperationHandlers::default();
98
99 handler
100 .insert(repository_get_value)
101 .insert(repository_get_setting)
102 .insert(repository_set_setting);
103
104 match handler
105 .handle(
106 &repository,
107 D::operation_name(),
108 serde_json::from_value(serialized.clone()).unwrap(),
109 self.clone(),
110 )
111 .await
112 {
113 Ok(result) => Ok(serde_json::from_slice(&result)
114 .map_err(|e| OperationError::Internal(e.to_string()))?),
115 Err(err) => match err {
116 OperationError::Internal(internal) => Err(OperationError::Internal(internal)),
117 OperationError::Unhandled => Err(OperationError::Unhandled),
118 OperationError::Operation(err) => Err(OperationError::Operation(
119 serde_json::from_slice(&err)
120 .map_err(|e| OperationError::Internal(e.to_string()))?,
121 )),
122 },
123 }
124 } else if serde_json::from_str::<Instance>(&object).is_ok() {
125 Err(OperationError::Unhandled)
126 } else {
127 Err(OperationError::Unhandled)
128 }
129 }
130
131 async fn get_object<O: GiteratedObject + Debug>(
132 &self,
133 object_str: &str,
134 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
135 if let Ok(user) = User::from_str(object_str) {
136 let mut user_backend = self.user_backend.lock().await;
137
138 if user_backend
139 .exists(&user)
140 .await
141 .map_err(|e| OperationError::Internal(e.to_string()))?
142 {
143 Ok(unsafe {
144 Object::new_unchecked(
145 O::from_object_str(object_str)
146 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
147 self.clone(),
148 )
149 })
150 } else {
151 return Err(OperationError::Unhandled);
152 }
153 } else if let Ok(repository) = Repository::from_str(object_str) {
154 let mut repository_backend = self.repository_backend.lock().await;
155
156 if repository_backend
157 .exists(&repository)
158 .await
159 .map_err(|e| OperationError::Internal(e.to_string()))?
160 {
161 Ok(unsafe {
162 Object::new_unchecked(
163 O::from_object_str(object_str)
164 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
165 self.clone(),
166 )
167 })
168 } else {
169 return Err(OperationError::Unhandled);
170 }
171 } else if Instance::from_str(object_str).is_ok() {
172 return Err(OperationError::Unhandled);
173 } else {
174 // Invalid object type
175 return Err(OperationError::Unhandled);
176 }
177 }
178 }
179
180 // These tests verify that the essential handling of the database backend is
181 // functional and correct.
182 #[cfg(test)]
183 mod test {
184 use std::{str::FromStr, sync::Arc};
185
186 use anyhow::Error;
187
188 use giterated_models::authenticated::UserAuthenticationToken;
189
190 use giterated_models::instance::{
191 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
192 };
193
194 use giterated_models::object_backend::ObjectBackend;
195
196 use giterated_models::repository::{
197 Description, Repository, RepositoryFileInspectRequest, RepositorySummary,
198 RepositoryTreeEntry,
199 };
200 use giterated_models::settings::AnySetting;
201 use giterated_models::user::{DisplayName, User, UserDisplayName};
202 use giterated_models::value::{AnyValue, GiteratedObjectValue};
203 use serde_json::Value;
204 use tokio::sync::Mutex;
205
206 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
207
208 use super::DatabaseBackend;
209 pub struct TestUserDatabaseBackend;
210
211 #[async_trait::async_trait]
212 impl UserBackend for TestUserDatabaseBackend {
213 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
214 assert_eq!(name, DisplayName::value_name());
215
216 Ok(serde_json::from_slice(
217 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
218 )
219 .unwrap())
220 }
221 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
222 Ok(serde_json::from_slice(
223 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
224 )
225 .unwrap())
226 }
227 async fn write_setting(
228 &mut self,
229 _user: &User,
230 _name: &str,
231 _setting: &Value,
232 ) -> Result<(), Error> {
233 Ok(())
234 }
235 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
236 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
237 }
238 }
239
240 #[async_trait::async_trait]
241 impl AuthBackend for TestUserDatabaseBackend {
242 async fn register(
243 &mut self,
244 _request: RegisterAccountRequest,
245 ) -> Result<UserAuthenticationToken, Error> {
246 todo!()
247 }
248
249 async fn login(
250 &mut self,
251 _source: &Instance,
252 _request: AuthenticationTokenRequest,
253 ) -> Result<UserAuthenticationToken, Error> {
254 todo!()
255 }
256 }
257
258 pub struct TestUserRepositoryBackend;
259
260 #[async_trait::async_trait]
261 impl RepositoryBackend for TestUserRepositoryBackend {
262 async fn create_repository(
263 &mut self,
264 _user: &User,
265 _request: &RepositoryCreateRequest,
266 ) -> Result<Repository, GitBackendError> {
267 todo!()
268 }
269 async fn repository_file_inspect(
270 &mut self,
271 _requester: Option<&User>,
272 _request: &RepositoryFileInspectRequest,
273 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
274 todo!()
275 }
276 async fn repositories_for_user(
277 &mut self,
278 _requester: Option<&User>,
279 _user: &User,
280 ) -> Result<Vec<RepositorySummary>, Error> {
281 todo!()
282 }
283
284 async fn get_value(
285 &mut self,
286 _repository: &Repository,
287 _name: &str,
288 ) -> Result<AnyValue<Repository>, Error> {
289 Ok(serde_json::from_slice(
290 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
291 )
292 .unwrap())
293 }
294 async fn get_setting(
295 &mut self,
296 _repository: &Repository,
297 _name: &str,
298 ) -> Result<AnySetting, Error> {
299 Ok(serde_json::from_slice(
300 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
301 )
302 .unwrap())
303 }
304 async fn write_setting(
305 &mut self,
306 _repository: &Repository,
307 _name: &str,
308 _setting: &Value,
309 ) -> Result<(), Error> {
310 Ok(())
311 }
312
313 async fn exists(&mut self, repository: &Repository) -> Result<bool, Error> {
314 // Ok(true)
315 Ok(repository
316 == &Repository::from_str(
317 "test_user:test.giterated.dev/[email protected]",
318 )
319 .unwrap())
320 }
321 }
322
323 fn test_backend() -> DatabaseBackend {
324 DatabaseBackend {
325 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
326 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
327 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
328 }
329 }
330
331 #[tokio::test]
332 async fn test_user_get() {
333 let backend = test_backend();
334
335 let mut user = backend
336 .get_object::<User>("test_user:test.giterated.dev")
337 .await
338 .expect("object should have been returned");
339
340 user.get::<DisplayName>()
341 .await
342 .expect("object value should have been returned");
343 }
344
345 #[tokio::test]
346 async fn test_user_get_setting() {
347 let backend = test_backend();
348
349 let mut user = backend
350 .get_object::<User>("test_user:test.giterated.dev")
351 .await
352 .expect("object should have been returned");
353
354 user.get_setting::<UserDisplayName>()
355 .await
356 .expect("object value should have been returned");
357 }
358
359 #[tokio::test]
360 async fn test_user_set_setting() {
361 let backend = test_backend();
362
363 let mut user = backend
364 .get_object::<User>("test_user:test.giterated.dev")
365 .await
366 .expect("object should have been returned");
367
368 user.set_setting::<UserDisplayName>(UserDisplayName(String::from("test")))
369 .await
370 .expect("object value should have been returned");
371 }
372
373 #[tokio::test]
374 async fn test_respository_get() {
375 let backend = test_backend();
376
377 let mut repository = backend
378 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
379 .await
380 .expect("object should have been returned");
381
382 repository
383 .get::<Description>()
384 .await
385 .expect("object value should have been returned");
386 }
387
388 #[tokio::test]
389 async fn test_repository_get_setting() {
390 let backend = test_backend();
391
392 let mut repository = backend
393 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
394 .await
395 .expect("object should have been returned");
396
397 repository
398 .get_setting::<Description>()
399 .await
400 .expect("object value should have been returned");
401 }
402
403 #[tokio::test]
404 async fn test_repository_set_setting() {
405 let backend = test_backend();
406
407 let mut repository = backend
408 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
409 .await
410 .expect("object should have been returned");
411
412 repository
413 .set_setting::<Description>(Description(String::from("test")))
414 .await
415 .expect("object value should have been returned");
416 }
417 }
418