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

ambee/giterated

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

Fix rev

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨088af7f

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