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/handler.rs⁩ - ⁨13392⁩ bytes
Raw
1 use std::{collections::HashMap, error::Error, pin::Pin, sync::Arc};
2
3 use futures_util::{future::BoxFuture, Future, FutureExt};
4 use giterated_models::{
5 error::{GetValueError, OperationError, RepositoryError, UserError},
6 object::{AnyObject, GiteratedObject},
7 object_backend::ObjectBackend,
8 operation::{AnyOperation, GiteratedOperation},
9 repository::{
10 Commit, DefaultBranch, Description, LatestCommit, Repository,
11 RepositoryCommitBeforeRequest, RepositoryDiff, RepositoryDiffRequest, RepositoryFile,
12 RepositoryFileFromIdRequest, RepositoryFileInspectRequest, RepositoryInfoRequest,
13 RepositorySummary, RepositoryView, Visibility,
14 },
15 settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError},
16 user::{User, UserRepositoriesRequest},
17 value::{AnyValue, GetValue},
18 };
19
20 use super::DatabaseBackend;
21
22 #[async_trait::async_trait]
23 pub trait GiteratedOperationHandler<
24 O: GiteratedObject,
25 D: GiteratedOperation<O>,
26 S: Send + Sync + Clone,
27 >
28 {
29 fn operation_name(&self) -> &str;
30 fn object_name(&self) -> &str;
31
32 async fn handle(
33 &self,
34 object: &O,
35 operation: D,
36 state: S,
37 ) -> Result<D::Success, OperationError<D::Failure>>;
38 }
39
40 #[async_trait::async_trait]
41 impl<O, D, F, S> GiteratedOperationHandler<O, D, S> for F
42 where
43 F: FnMut(
44 &O,
45 D,
46 S,
47 ) -> Pin<
48 Box<dyn Future<Output = Result<D::Success, OperationError<D::Failure>>> + Send>,
49 > + Send
50 + Sync
51 + Clone,
52 O: GiteratedObject + Send + Sync,
53 D: GiteratedOperation<O> + 'static,
54 <D as GiteratedOperation<O>>::Failure: Send,
55 S: Send + Sync + Clone + 'static,
56 {
57 fn operation_name(&self) -> &str {
58 D::operation_name()
59 }
60
61 fn object_name(&self) -> &str {
62 O::object_name()
63 }
64
65 async fn handle(
66 &self,
67 object: &O,
68 operation: D,
69 state: S,
70 ) -> Result<D::Success, OperationError<D::Failure>> {
71 self.clone()(object, operation, state).await
72 }
73 }
74
75 pub struct OperationWrapper<S: Send + Sync + Clone>(
76 Box<
77 dyn Fn(
78 AnyObject,
79 AnyOperation,
80 S,
81 )
82 -> Pin<Box<dyn Future<Output = Result<Vec<u8>, OperationError<Vec<u8>>>> + Send>>
83 + Send
84 + Sync,
85 >,
86 );
87
88 impl<S: Send + Sync + Clone + 'static> OperationWrapper<S> {
89 pub fn new<
90 O: GiteratedObject + Send + Sync,
91 D: GiteratedOperation<O> + 'static,
92 F: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone,
93 >(
94 handler: F,
95 ) -> Self {
96 let handler = Arc::new(Box::pin(handler));
97 Self(Box::new(move |any_object, any_operation, state| {
98 let handler = handler.clone();
99 async move {
100 let handler = handler.clone();
101 let object: O = O::from_object_str(&any_object.0).unwrap();
102 let operation: D = serde_json::from_value(any_operation.0.clone()).unwrap();
103
104 let result = handler.handle(&object, operation, state).await;
105 result
106 .map(|success| serde_json::to_vec(&success).unwrap())
107 .map_err(|err| match err {
108 OperationError::Operation(err) => {
109 OperationError::Operation(serde_json::to_vec(&err).unwrap())
110 }
111 OperationError::Internal(internal) => OperationError::Internal(internal),
112 OperationError::Unhandled => OperationError::Unhandled,
113 })
114 }
115 .boxed()
116 }))
117 }
118
119 async fn handle(
120 &mut self,
121 object: AnyObject,
122 operation: AnyOperation,
123 state: S,
124 ) -> Result<Vec<u8>, OperationError<Vec<u8>>> {
125 self.0(object, operation, state).await
126 }
127 }
128
129 pub fn user_get_repositories(
130 object: &User,
131 _operation: UserRepositoriesRequest,
132 state: DatabaseBackend,
133 ) -> BoxFuture<'static, Result<Vec<RepositorySummary>, OperationError<UserError>>> {
134 let object = object.clone();
135
136 async move {
137 let mut user_backend = state.user_backend.lock().await;
138 let repositories = user_backend
139 .repositories_for_user(None, &object)
140 .await
141 .map_err(|e| OperationError::Internal(e.to_string()))?;
142
143 Ok(repositories)
144 }
145 .boxed()
146 }
147
148 pub fn user_get_value(
149 object: &User,
150 operation: GetValue<AnyValue<User>>,
151 state: DatabaseBackend,
152 ) -> BoxFuture<'static, Result<AnyValue<User>, OperationError<GetValueError>>> {
153 let object = object.clone();
154
155 async move {
156 let mut user_backend = state.user_backend.lock().await;
157 let value = user_backend
158 .get_value(&object, &operation.value_name)
159 .await
160 .map_err(|e| OperationError::Internal(e.to_string()))?;
161
162 Ok(value)
163 }
164 .boxed()
165 }
166
167 pub fn user_get_setting(
168 object: &User,
169 operation: GetSetting<AnySetting>,
170 state: DatabaseBackend,
171 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
172 let object = object.clone();
173
174 async move {
175 let mut user_backend = state.user_backend.lock().await;
176 let value = user_backend
177 .get_setting(&object, &operation.setting_name)
178 .await
179 .map_err(|e| OperationError::Internal(e.to_string()))?;
180
181 Ok(value)
182 }
183 .boxed()
184 }
185
186 pub fn user_set_setting(
187 object: &User,
188 operation: SetSetting<AnySetting>,
189 state: DatabaseBackend,
190 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
191 let object = object.clone();
192
193 async move {
194 let mut user_backend = state.user_backend.lock().await;
195 let value = user_backend
196 .write_setting(&object, &operation.setting_name, &operation.value.0)
197 .await
198 .map_err(|e| OperationError::Internal(e.to_string()))?;
199
200 Ok(value)
201 }
202 .boxed()
203 }
204
205 pub fn repository_info(
206 object: &Repository,
207 operation: RepositoryInfoRequest,
208 state: DatabaseBackend,
209 ) -> BoxFuture<'static, Result<RepositoryView, OperationError<RepositoryError>>> {
210 let object = object.clone();
211
212 async move {
213 let mut object = state
214 .get_object::<Repository>(&object.to_string())
215 .await
216 .unwrap();
217
218 let mut repository_backend = state.repository_backend.lock().await;
219 let tree = repository_backend
220 .repository_file_inspect(
221 None,
222 object.object(),
223 &RepositoryFileInspectRequest {
224 extra_metadata: operation.extra_metadata,
225 path: operation.path,
226 rev: operation.rev.clone(),
227 },
228 )
229 .await
230 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
231 drop(repository_backend);
232
233 let info = RepositoryView {
234 name: object.object().name.clone(),
235 owner: object.object().owner.clone(),
236 description: object.get::<Description>().await.ok(),
237 visibility: object
238 .get::<Visibility>()
239 .await
240 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
241 default_branch: object
242 .get::<DefaultBranch>()
243 .await
244 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
245 // TODO: Can't be a simple get function, this needs to be returned alongside the tree as this differs depending on the rev and path.
246 latest_commit: object.get::<LatestCommit>().await.ok(),
247 tree_rev: operation.rev,
248 tree,
249 };
250
251 Ok(info)
252 }
253 .boxed()
254 }
255
256 pub fn repository_file_from_id(
257 object: &Repository,
258 operation: RepositoryFileFromIdRequest,
259 state: DatabaseBackend,
260 ) -> BoxFuture<'static, Result<RepositoryFile, OperationError<RepositoryError>>> {
261 let object = object.clone();
262
263 async move {
264 let object = state
265 .get_object::<Repository>(&object.to_string())
266 .await
267 .unwrap();
268
269 let mut repository_backend = state.repository_backend.lock().await;
270 let file = repository_backend
271 .repository_file_from_id(
272 None,
273 object.object(),
274 &RepositoryFileFromIdRequest(operation.0),
275 )
276 .await
277 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
278 drop(repository_backend);
279
280 Ok(file)
281 }
282 .boxed()
283 }
284
285 pub fn repository_diff(
286 object: &Repository,
287 operation: RepositoryDiffRequest,
288 state: DatabaseBackend,
289 ) -> BoxFuture<'static, Result<RepositoryDiff, OperationError<RepositoryError>>> {
290 let object = object.clone();
291
292 async move {
293 let object = state
294 .get_object::<Repository>(&object.to_string())
295 .await
296 .unwrap();
297
298 let mut repository_backend = state.repository_backend.lock().await;
299 let file = repository_backend
300 .repository_diff(None, object.object(), &operation)
301 .await
302 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
303 drop(repository_backend);
304
305 Ok(file)
306 }
307 .boxed()
308 }
309
310 pub fn repository_commit_before(
311 object: &Repository,
312 operation: RepositoryCommitBeforeRequest,
313 state: DatabaseBackend,
314 ) -> BoxFuture<'static, Result<Commit, OperationError<RepositoryError>>> {
315 let object = object.clone();
316
317 async move {
318 let object = state
319 .get_object::<Repository>(&object.to_string())
320 .await
321 .unwrap();
322
323 let mut repository_backend = state.repository_backend.lock().await;
324 let file = repository_backend
325 .repository_commit_before(None, object.object(), &operation)
326 .await
327 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
328 drop(repository_backend);
329
330 Ok(file)
331 }
332 .boxed()
333 }
334
335 pub fn repository_get_value(
336 object: &Repository,
337 operation: GetValue<AnyValue<Repository>>,
338 state: DatabaseBackend,
339 ) -> BoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> {
340 let object = object.clone();
341
342 async move {
343 let mut repository_backend = state.repository_backend.lock().await;
344 let value = repository_backend
345 .get_value(&object, &operation.value_name)
346 .await
347 .map_err(|e| {
348 OperationError::Internal(format!("error getting value: {}", e.to_string()))
349 })?;
350
351 Ok(value)
352 }
353 .boxed()
354 }
355
356 pub fn repository_get_setting(
357 object: &Repository,
358 operation: GetSetting<AnySetting>,
359 state: DatabaseBackend,
360 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
361 let object = object.clone();
362
363 async move {
364 let mut repository_backend = state.repository_backend.lock().await;
365 let value = repository_backend
366 .get_setting(&object, &operation.setting_name)
367 .await
368 .map_err(|e| OperationError::Internal(e.to_string()))?;
369
370 Ok(value)
371 }
372 .boxed()
373 }
374
375 pub fn repository_set_setting(
376 object: &Repository,
377 operation: SetSetting<AnySetting>,
378 state: DatabaseBackend,
379 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
380 let object = object.clone();
381
382 async move {
383 let mut repository_backend = state.repository_backend.lock().await;
384 let value = repository_backend
385 .write_setting(&object, &operation.setting_name, &operation.value.0)
386 .await
387 .map_err(|e| OperationError::Internal(e.to_string()))?;
388
389 Ok(value)
390 }
391 .boxed()
392 }
393
394 pub struct OperationHandlers<S: Send + Sync + Clone> {
395 operations: HashMap<String, OperationWrapper<S>>,
396 }
397
398 impl<S: Send + Sync + Clone> Default for OperationHandlers<S> {
399 fn default() -> Self {
400 Self {
401 operations: HashMap::new(),
402 }
403 }
404 }
405
406 impl<S: Send + Sync + Clone + 'static> OperationHandlers<S> {
407 pub fn insert<
408 O: GiteratedObject + Send + Sync,
409 D: GiteratedOperation<O> + 'static,
410 H: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone,
411 >(
412 &mut self,
413 handler: H,
414 ) -> &mut Self {
415 let operation_name = handler.operation_name().to_string();
416
417 let wrapped = OperationWrapper::new(handler);
418
419 self.operations.insert(operation_name, wrapped);
420
421 self
422 }
423
424 pub async fn handle<O: GiteratedObject>(
425 &mut self,
426 object: &O,
427 operation_name: &str,
428 operation: AnyOperation,
429 state: S,
430 ) -> Result<Vec<u8>, OperationError<Vec<u8>>> {
431 if let Some(handler) = self.operations.get_mut(operation_name) {
432 handler
433 .handle(AnyObject(object.to_string()), operation, state)
434 .await
435 } else {
436 Err(OperationError::Internal(format!(
437 "unknown operation: {}",
438 operation_name
439 )))
440 }
441 }
442 }
443