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

ambee/giterated

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

Please fix

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨2c88faf

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