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

ambee/giterated

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

log internal errors

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨3923b5f

⁨giterated-daemon/src/database_backend/mod.rs⁩ - ⁨18178⁩ 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::{
8 AnyObject, GiteratedObject, Object, ObjectRequest, ObjectRequestError,
9 };
10 use giterated_models::object_backend::ObjectBackend;
11 use giterated_models::operation::GiteratedOperation;
12 use giterated_models::repository::Repository;
13 use giterated_models::user::User;
14 use std::fmt::Debug;
15 use tokio::sync::Mutex;
16
17 use crate::backend::{RepositoryBackend, UserBackend};
18
19 use self::handler::{
20 repository_commit_before, repository_diff, repository_file_from_id, repository_get_setting,
21 repository_get_value, repository_info, repository_set_setting, user_get_repositories,
22 user_get_setting, user_get_value, user_set_setting, OperationHandlers,
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(serde_json::from_slice(&result)
106 .map_err(|e| OperationError::Internal(e.to_string()))?),
107 Err(err) => match err {
108 OperationError::Internal(internal) => {
109 warn!("Internal Error: {:?}", OperationError::<()>::Internal(internal.clone()));
110
111 Err(OperationError::Internal(internal))
112 },
113 OperationError::Unhandled => Err(OperationError::Unhandled),
114 OperationError::Operation(err) => Err(OperationError::Operation(
115 serde_json::from_slice(&err)
116 .map_err(|e| OperationError::Internal(e.to_string()))?,
117 )),
118 },
119 }
120 } else if let Ok(repository) = Repository::from_str(&object) {
121 let mut handler = OperationHandlers::default();
122
123 handler
124 .insert(repository_info)
125 .insert(repository_file_from_id)
126 .insert(repository_diff)
127 .insert(repository_commit_before)
128 .insert(repository_get_value)
129 .insert(repository_get_setting)
130 .insert(repository_set_setting);
131
132 match handler
133 .handle(
134 &repository,
135 operation,
136 serde_json::from_value(serialized.clone()).unwrap(),
137 self.clone(),
138 )
139 .await
140 {
141 Ok(result) => Ok(serde_json::from_slice(&result)
142 .map_err(|e| OperationError::Internal(e.to_string()))?),
143 Err(err) => match err {
144 OperationError::Internal(internal) => {
145 warn!("Internal Error: {:?}", OperationError::<()>::Internal(internal.clone()));
146
147 Err(OperationError::Internal(internal))
148 },
149 OperationError::Unhandled => Err(OperationError::Unhandled),
150 OperationError::Operation(err) => Err(OperationError::Operation(
151 serde_json::from_slice(&err)
152 .map_err(|e| OperationError::Internal(e.to_string()))?,
153 )),
154 },
155 }
156 } else if let Ok(instance) = Instance::from_str(&object) {
157 if instance != self.our_instance {
158 // We don't handle other objects currently
159 return Err(OperationError::Unhandled);
160 }
161
162 if let Ok(object_request) = serde_json::from_value::<ObjectRequest>(serialized.clone())
163 {
164 let result = self.get_object::<AnyObject>(&object_request.0).await;
165
166 let result = result
167 .map(|success| serde_json::to_vec(&success.object()).unwrap())
168 .map_err(|err| match err {
169 OperationError::Operation(err) => {
170 OperationError::Operation(serde_json::to_vec(&err).unwrap())
171 }
172 OperationError::Internal(internal) => OperationError::Internal(internal),
173 OperationError::Unhandled => OperationError::Unhandled,
174 });
175
176 match result {
177 Ok(result) => Ok(serde_json::from_slice(&result)
178 .map_err(|e| OperationError::Internal(e.to_string()))?),
179 Err(err) => match err {
180 OperationError::Internal(internal) => {
181 warn!("Internal Error: {:?}", OperationError::<()>::Internal(internal.clone()));
182
183 Err(OperationError::Internal(internal))
184 }
185 OperationError::Unhandled => Err(OperationError::Unhandled),
186 OperationError::Operation(err) => Err(OperationError::Operation(
187 serde_json::from_slice(&err)
188 .map_err(|e| OperationError::Internal(e.to_string()))?,
189 )),
190 },
191 }
192 } else {
193 Err(OperationError::Unhandled)
194 }
195 } else {
196 Err(OperationError::Unhandled)
197 }
198 }
199
200 async fn get_object<O: GiteratedObject + Debug>(
201 &self,
202 object_str: &str,
203 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
204 if let Ok(user) = User::from_str(object_str) {
205 let mut user_backend = self.user_backend.lock().await;
206
207 if user_backend
208 .exists(&user)
209 .await
210 .map_err(|e| OperationError::Internal(e.to_string()))?
211 {
212 Ok(unsafe {
213 Object::new_unchecked(
214 O::from_object_str(object_str)
215 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
216 self.clone(),
217 )
218 })
219 } else {
220 return Err(OperationError::Unhandled);
221 }
222 } else if let Ok(repository) = Repository::from_str(object_str) {
223 let mut repository_backend = self.repository_backend.lock().await;
224
225 if repository_backend
226 .exists(&repository)
227 .await
228 .map_err(|e| OperationError::Internal(e.to_string()))?
229 {
230 Ok(unsafe {
231 Object::new_unchecked(
232 O::from_object_str(object_str)
233 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
234 self.clone(),
235 )
236 })
237 } else {
238 return Err(OperationError::Unhandled);
239 }
240 } else if let Ok(instance) = Instance::from_str(object_str) {
241 if instance != self.our_instance {
242 // We don't handle other objects currently
243 return Err(OperationError::Unhandled);
244 }
245
246 return Err(OperationError::Unhandled);
247 } else {
248 // Invalid object type
249 return Err(OperationError::Unhandled);
250 }
251 }
252 }
253
254 // These tests verify that the essential handling of the database backend is
255 // functional and correct.
256 #[cfg(test)]
257 mod test {
258 use std::{str::FromStr, sync::Arc};
259
260 use anyhow::Error;
261
262 use giterated_models::authenticated::UserAuthenticationToken;
263
264 use giterated_models::instance::{
265 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
266 };
267
268 use giterated_models::object_backend::ObjectBackend;
269
270 use giterated_models::repository::{
271 Commit, Description, Repository, RepositoryCommitBeforeRequest, RepositoryDiff,
272 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
273 RepositoryFileInspectRequest, RepositorySummary, RepositoryTreeEntry,
274 };
275 use giterated_models::settings::AnySetting;
276 use giterated_models::user::{DisplayName, User};
277 use giterated_models::value::{AnyValue, GiteratedObjectValue};
278 use serde_json::Value;
279 use tokio::sync::Mutex;
280
281 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
282
283 use super::DatabaseBackend;
284 pub struct TestUserDatabaseBackend;
285
286 #[async_trait::async_trait]
287 impl UserBackend for TestUserDatabaseBackend {
288 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
289 assert_eq!(name, DisplayName::value_name());
290
291 Ok(serde_json::from_slice(
292 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
293 )
294 .unwrap())
295 }
296 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
297 Ok(serde_json::from_slice(
298 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
299 )
300 .unwrap())
301 }
302 async fn write_setting(
303 &mut self,
304 _user: &User,
305 _name: &str,
306 _setting: &Value,
307 ) -> Result<(), Error> {
308 Ok(())
309 }
310 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
311 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
312 }
313 async fn repositories_for_user(
314 &mut self,
315 requester: Option<&User>,
316 user: &User,
317 ) -> Result<Vec<RepositorySummary>, Error> {
318 todo!()
319 }
320 }
321
322 #[async_trait::async_trait]
323 impl AuthBackend for TestUserDatabaseBackend {
324 async fn register(
325 &mut self,
326 _request: RegisterAccountRequest,
327 ) -> Result<UserAuthenticationToken, Error> {
328 todo!()
329 }
330
331 async fn login(
332 &mut self,
333 _source: &Instance,
334 _request: AuthenticationTokenRequest,
335 ) -> Result<UserAuthenticationToken, Error> {
336 todo!()
337 }
338 }
339
340 pub struct TestUserRepositoryBackend;
341
342 #[async_trait::async_trait]
343 impl RepositoryBackend for TestUserRepositoryBackend {
344 async fn create_repository(
345 &mut self,
346 _user: &User,
347 _request: &RepositoryCreateRequest,
348 ) -> Result<Repository, GitBackendError> {
349 todo!()
350 }
351 async fn repository_file_inspect(
352 &mut self,
353 requester: Option<&User>,
354 repository: &Repository,
355 request: &RepositoryFileInspectRequest,
356 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
357 todo!()
358 }
359 async fn repository_file_from_id(
360 &mut self,
361 requester: Option<&User>,
362 repository: &Repository,
363 request: &RepositoryFileFromIdRequest,
364 ) -> Result<RepositoryFile, Error> {
365 todo!()
366 }
367 async fn repository_diff(
368 &mut self,
369 requester: Option<&User>,
370 repository: &Repository,
371 request: &RepositoryDiffRequest,
372 ) -> Result<RepositoryDiff, Error> {
373 todo!()
374 }
375 async fn repository_commit_before(
376 &mut self,
377 requester: Option<&User>,
378 repository: &Repository,
379 request: &RepositoryCommitBeforeRequest,
380 ) -> Result<Commit, Error> {
381 todo!()
382 }
383 async fn get_value(
384 &mut self,
385 _repository: &Repository,
386 _name: &str,
387 ) -> Result<AnyValue<Repository>, Error> {
388 Ok(serde_json::from_slice(
389 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
390 )
391 .unwrap())
392 }
393 async fn get_setting(
394 &mut self,
395 _repository: &Repository,
396 _name: &str,
397 ) -> Result<AnySetting, Error> {
398 Ok(serde_json::from_slice(
399 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
400 )
401 .unwrap())
402 }
403 async fn write_setting(
404 &mut self,
405 _repository: &Repository,
406 _name: &str,
407 _setting: &Value,
408 ) -> Result<(), Error> {
409 Ok(())
410 }
411
412 async fn exists(&mut self, repository: &Repository) -> Result<bool, Error> {
413 // Ok(true)
414 Ok(repository
415 == &Repository::from_str(
416 "test_user:test.giterated.dev/[email protected]",
417 )
418 .unwrap())
419 }
420 }
421
422 fn test_backend() -> DatabaseBackend {
423 DatabaseBackend {
424 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
425 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
426 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
427 }
428 }
429
430 #[tokio::test]
431 async fn test_user_get() {
432 let backend = test_backend();
433
434 let mut user = backend
435 .get_object::<User>("test_user:test.giterated.dev")
436 .await
437 .expect("object should have been returned");
438
439 user.get::<DisplayName>()
440 .await
441 .expect("object value should have been returned");
442 }
443
444 #[tokio::test]
445 async fn test_user_get_setting() {
446 let backend = test_backend();
447
448 let mut user = backend
449 .get_object::<User>("test_user:test.giterated.dev")
450 .await
451 .expect("object should have been returned");
452
453 user.get_setting::<DisplayName>()
454 .await
455 .expect("object value should have been returned");
456 }
457
458 #[tokio::test]
459 async fn test_user_set_setting() {
460 let backend = test_backend();
461
462 let mut user = backend
463 .get_object::<User>("test_user:test.giterated.dev")
464 .await
465 .expect("object should have been returned");
466
467 user.set_setting::<DisplayName>(DisplayName(String::from("test")))
468 .await
469 .expect("object value should have been returned");
470 }
471
472 #[tokio::test]
473 async fn test_respository_get() {
474 let backend = test_backend();
475
476 let mut repository = backend
477 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
478 .await
479 .expect("object should have been returned");
480
481 repository
482 .get::<Description>()
483 .await
484 .expect("object value should have been returned");
485 }
486
487 #[tokio::test]
488 async fn test_repository_get_setting() {
489 let backend = test_backend();
490
491 let mut repository = backend
492 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
493 .await
494 .expect("object should have been returned");
495
496 repository
497 .get_setting::<Description>()
498 .await
499 .expect("object value should have been returned");
500 }
501
502 #[tokio::test]
503 async fn test_repository_set_setting() {
504 let backend = test_backend();
505
506 let mut repository = backend
507 .get_object::<Repository>("test_user:test.giterated.dev/[email protected]")
508 .await
509 .expect("object should have been returned");
510
511 repository
512 .set_setting::<Description>(Description(String::from("test")))
513 .await
514 .expect("object value should have been returned");
515 }
516 }
517