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

ambee/giterated

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

Fixes

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨b87f0a3

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