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

ambee/giterated

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

Fix handling stack

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨c53b026

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