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

ambee/giterated

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

Fixes and cleanup

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨555bd26

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