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

ambee/giterated

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

Progress on refactor

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨c9f076f

⁨giterated-daemon/src/database_backend/mod.rs⁩ - ⁨9701⁩ bytes
Raw
1 pub mod handler;
2
3 use std::{str::FromStr, sync::Arc};
4
5 use futures_util::TryFutureExt;
6 use giterated_models::{
7 error::OperationError,
8 model::{instance::Instance, repository::Repository, user::User},
9 operation::{GiteratedObject, GiteratedOperation, Object, ObjectBackend, ObjectRequestError},
10 };
11 use std::fmt::Debug;
12 use tokio::sync::Mutex;
13
14 use crate::backend::{RepositoryBackend, UserBackend};
15
16 use self::handler::{
17 repository_get_setting, repository_get_value, repository_set_setting, user_get_setting,
18 user_get_value, user_set_setting, OperationHandlers,
19 };
20
21 #[derive(Clone, Debug)]
22 pub struct Foobackend {}
23
24 #[async_trait::async_trait]
25 impl ObjectBackend for Foobackend {
26 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
27 &self,
28 _object: O,
29 _operation: D,
30 ) -> Result<D::Success, OperationError<D::Failure>> {
31 // We don't handle operations with this backend
32 Err(OperationError::Unhandled)
33 }
34
35 async fn get_object<O: GiteratedObject + Debug>(
36 &self,
37 _object_str: &str,
38 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
39 Err(OperationError::Unhandled)
40 }
41 }
42
43 /// A backend implementation which attempts to resolve data from the instance's database.
44 #[derive(Clone)]
45 pub struct DatabaseBackend {
46 pub(self) our_instance: Instance,
47 pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>,
48 pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
49 }
50
51 impl Debug for DatabaseBackend {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("DatabaseBackend").finish()
54 }
55 }
56
57 #[async_trait::async_trait]
58 impl ObjectBackend for DatabaseBackend {
59 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
60 &self,
61 object: O,
62 operation: D,
63 ) -> Result<D::Success, OperationError<D::Failure>> {
64 let serialized =
65 serde_json::to_value(operation).map_err(|e| OperationError::Internal(e.to_string()))?;
66 let object_name = object.to_string();
67
68 if let Ok(user) = User::from_str(&object_name) {
69 let mut handler = OperationHandlers::default();
70
71 handler
72 .insert(user_get_value)
73 .insert(user_get_setting)
74 .insert(user_set_setting);
75
76 match handler
77 .handle(
78 &user,
79 D::operation_name(),
80 serde_json::from_value(serialized.clone()).unwrap(),
81 self.clone(),
82 )
83 .await
84 {
85 Ok(result) => Ok(serde_json::from_slice(&result)
86 .map_err(|e| OperationError::Internal(e.to_string()))?),
87 Err(err) => match err {
88 OperationError::Internal(internal) => Err(OperationError::Internal(internal)),
89 OperationError::Unhandled => Err(OperationError::Unhandled),
90 OperationError::Operation(err) => Err(OperationError::Operation(
91 serde_json::from_slice(&err)
92 .map_err(|e| OperationError::Internal(e.to_string()))?,
93 )),
94 },
95 }
96 } else if let Ok(_repository) = Repository::from_str(&object_name) {
97 let mut handler = OperationHandlers::default();
98
99 handler
100 .insert(repository_get_value)
101 .insert(repository_get_setting)
102 .insert(repository_set_setting);
103
104 // handler.handle(&repository, D::operation_name(), bincode::deserialize(&serialized).unwrap(), DatabaseBackendState).await;
105 todo!()
106 } else if Instance::from_str(&object_name).is_ok() {
107 Err(OperationError::Unhandled)
108 } else {
109 Err(OperationError::Unhandled)
110 }
111 }
112
113 async fn get_object<O: GiteratedObject + Debug>(
114 &self,
115 object_str: &str,
116 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
117 if let Ok(user) = User::from_str(object_str) {
118 let mut user_backend = self.user_backend.lock().await;
119
120 if user_backend
121 .exists(&user)
122 .await
123 .map_err(|e| OperationError::Internal(e.to_string()))?
124 {
125 Ok(unsafe {
126 Object::new_unchecked(
127 O::from_object_str(object_str)
128 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
129 self.clone(),
130 )
131 })
132 } else {
133 return Err(OperationError::Unhandled);
134 }
135 } else if let Ok(repository) = Repository::from_str(object_str) {
136 let mut repository_backend = self.repository_backend.lock().await;
137
138 if repository_backend
139 .exists(&repository)
140 .await
141 .map_err(|e| OperationError::Internal(e.to_string()))?
142 {
143 Ok(unsafe {
144 Object::new_unchecked(
145 O::from_object_str(object_str)
146 .map_err(|e| ObjectRequestError::Deserialization(e.to_string()))?,
147 self.clone(),
148 )
149 })
150 } else {
151 return Err(OperationError::Unhandled);
152 }
153 } else if Instance::from_str(object_str).is_ok() {
154 return Err(OperationError::Unhandled);
155 } else {
156 // Invalid object type
157 return Err(OperationError::Unhandled);
158 }
159 }
160 }
161
162 mod test {
163 use std::{str::FromStr, sync::Arc};
164
165 use anyhow::Error;
166 use giterated_models::{
167 model::{
168 authenticated::UserAuthenticationToken,
169 instance::Instance,
170 repository::{Repository, RepositorySummary, RepositoryTreeEntry},
171 settings::AnySetting,
172 user::User,
173 },
174 operation::{
175 instance::{
176 AuthenticationTokenRequest, RegisterAccountRequest, RepositoryCreateRequest,
177 },
178 repository::RepositoryFileInspectRequest,
179 GiteratedObjectValue, ObjectBackend,
180 },
181 values::{user::DisplayName, AnyValue},
182 };
183 use serde_json::Value;
184 use tokio::sync::Mutex;
185
186 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
187
188 use super::DatabaseBackend;
189 pub struct TestUserDatabaseBackend;
190
191 #[async_trait::async_trait]
192 impl UserBackend for TestUserDatabaseBackend {
193 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
194 assert_eq!(name, DisplayName::value_name());
195
196 Ok(serde_json::from_slice(
197 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
198 )
199 .unwrap())
200 }
201 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
202 todo!()
203 }
204 async fn write_setting(
205 &mut self,
206 _user: &User,
207 _name: &str,
208 _setting: &Value,
209 ) -> Result<(), Error> {
210 todo!()
211 }
212 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
213 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
214 }
215 }
216
217 #[async_trait::async_trait]
218 impl AuthBackend for TestUserDatabaseBackend {
219 async fn register(
220 &mut self,
221 _request: RegisterAccountRequest,
222 ) -> Result<UserAuthenticationToken, Error> {
223 todo!()
224 }
225
226 async fn login(
227 &mut self,
228 _source: &Instance,
229 _request: AuthenticationTokenRequest,
230 ) -> Result<UserAuthenticationToken, Error> {
231 todo!()
232 }
233 }
234
235 pub struct TestUserRepositoryBackend;
236
237 #[async_trait::async_trait]
238 impl RepositoryBackend for TestUserRepositoryBackend {
239 async fn create_repository(
240 &mut self,
241 _user: &User,
242 _request: &RepositoryCreateRequest,
243 ) -> Result<Repository, GitBackendError> {
244 todo!()
245 }
246 async fn repository_file_inspect(
247 &mut self,
248 _requester: Option<&User>,
249 _request: &RepositoryFileInspectRequest,
250 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
251 todo!()
252 }
253 async fn repositories_for_user(
254 &mut self,
255 _requester: Option<&User>,
256 _user: &User,
257 ) -> Result<Vec<RepositorySummary>, Error> {
258 todo!()
259 }
260 async fn exists(&mut self, _repository: &Repository) -> Result<bool, Error> {
261 todo!()
262 }
263 }
264
265 fn test_backend() -> DatabaseBackend {
266 DatabaseBackend {
267 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
268 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
269 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
270 }
271 }
272
273 #[tokio::test]
274 async fn test_user_get() {
275 let backend = test_backend();
276
277 let mut user = backend
278 .get_object::<User>("test_user:test.giterated.dev")
279 .await
280 .expect("object should have been returned");
281
282 user.get::<DisplayName>()
283 .await
284 .expect("object value should have been returned");
285 }
286 }
287