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

ambee/giterated

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

Beginning of `stack-next` refactor

-Refactoring the protocol stack into something similar to a runtime. -Handles merging handler builders which is placing the ground work for plugins in. - Increased metadata generation during compilation enables less ser/de during execution. - Goal is to have an O(1) time from incoming operation to calling handlers. - Decreased penalty for using the statically typed API from within your code, now avoids some allocation. # Changes - Added `GiteratedRuntime` which is to replace the current unified stack - Added `RuntimeBuilder` which does what the current `OperationHandlers` struct does, but much better. - Added `RuntimeMetadata` to store type metadata for new `Any` based internals - Refactored serde_json out of the internal operation handling

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨708dea4

⁨giterated-daemon/src/database_backend/handler.rs⁩ - ⁨16722⁩ bytes
Raw
1 use std::error::Error;
2
3 use futures_util::{future::BoxFuture, FutureExt};
4 use giterated_models::{
5 authenticated::UserAuthenticationToken,
6 error::{GetValueError, InstanceError, OperationError, RepositoryError, UserError},
7 instance::{
8 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
9 },
10 object_backend::ObjectBackend,
11 repository::{
12 AccessList, Commit, DefaultBranch, Description, LatestCommit, Repository,
13 RepositoryCommitBeforeRequest, RepositoryDiff, RepositoryDiffPatchRequest,
14 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
15 RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryInfoRequest,
16 RepositorySummary, RepositoryView, Visibility,
17 },
18 settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError},
19 user::{Bio, DisplayName, User, UserRepositoriesRequest},
20 value::{AnyValue, GetValue},
21 };
22 use giterated_stack::{
23 AuthenticatedUser, AuthorizedInstance, AuthorizedUser, BackendWrapper, StackOperationState,
24 };
25
26 use super::DatabaseBackend;
27
28 pub fn user_get_repositories(
29 object: &User,
30 _operation: UserRepositoriesRequest,
31 state: DatabaseBackend,
32 operation_state: StackOperationState,
33 requester: Option<AuthenticatedUser>,
34 ) -> BoxFuture<'static, Result<Vec<RepositorySummary>, OperationError<UserError>>> {
35 let object = object.clone();
36
37 async move {
38 let mut user_backend = state.user_backend.lock().await;
39 let repositories_response = user_backend
40 .repositories_for_user(&requester, &object)
41 .await
42 .map_err(|e| OperationError::Internal(e.to_string()))?;
43 drop(user_backend);
44 let mut repositories_backend = state.repository_backend.lock().await;
45
46 let mut repositories = vec![];
47
48 for repository in repositories_response {
49 if repositories_backend
50 .exists(&requester, &repository.repository)
51 .await
52 .map_err(|e| OperationError::Internal(e.to_string()))?
53 {
54 repositories.push(repository);
55 }
56 }
57
58 Ok(repositories)
59 }
60 .boxed()
61 }
62
63 pub fn user_get_value(
64 object: &User,
65 operation: GetValue<AnyValue<User>>,
66 state: DatabaseBackend,
67 ) -> BoxFuture<'static, Result<AnyValue<User>, OperationError<GetValueError>>> {
68 let object = object.clone();
69
70 async move {
71 let mut user_backend = state.user_backend.lock().await;
72 let value = user_backend
73 .get_value(&object, &operation.value_name)
74 .await
75 .map_err(|e| OperationError::Internal(e.to_string()))?;
76
77 Ok(value)
78 }
79 .boxed()
80 }
81
82 pub fn user_get_setting(
83 object: &User,
84 operation: GetSetting<AnySetting>,
85 state: DatabaseBackend,
86 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
87 let object = object.clone();
88
89 async move {
90 let mut user_backend = state.user_backend.lock().await;
91 let value = user_backend
92 .get_setting(&object, &operation.setting_name)
93 .await
94 .map_err(|e| OperationError::Internal(e.to_string()))?;
95
96 Ok(value)
97 }
98 .boxed()
99 }
100
101 // pub fn user_set_setting(
102 // object: &User,
103 // operation: SetSetting<AnySetting>,
104 // state: DatabaseBackend,
105 // ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
106 // let object = object.clone();
107
108 // async move {
109 // let mut user_backend = state.user_backend.lock().await;
110 // let value = user_backend
111 // .write_setting(&object, &operation.setting_name, &operation.value.0)
112 // .await
113 // .map_err(|e| OperationError::Internal(e.to_string()))?;
114
115 // Ok(value)
116 // }
117 // .boxed()
118 // }
119
120 pub fn repository_info(
121 object: &Repository,
122 operation: RepositoryInfoRequest,
123 state: DatabaseBackend,
124 operation_state: StackOperationState,
125 backend: BackendWrapper,
126 requester: Option<AuthenticatedUser>,
127 ) -> BoxFuture<'static, Result<RepositoryView, OperationError<RepositoryError>>> {
128 let object = object.clone();
129
130 async move {
131 let mut object = backend
132 .get_object::<Repository>(&object.to_string(), &operation_state)
133 .await
134 .unwrap();
135
136 let mut repository_backend = state.repository_backend.lock().await;
137 let tree = repository_backend
138 .repository_file_inspect(
139 &requester,
140 object.object(),
141 &RepositoryFileInspectRequest {
142 extra_metadata: operation.extra_metadata,
143 path: operation.path,
144 rev: operation.rev.clone(),
145 },
146 )
147 .await
148 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
149 drop(repository_backend);
150
151 let info = RepositoryView {
152 name: object.object().name.clone(),
153 owner: object.object().owner.clone(),
154 description: object.get::<Description>(&operation_state).await.ok(),
155 visibility: object
156 .get::<Visibility>(&operation_state)
157 .await
158 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
159 default_branch: object
160 .get::<DefaultBranch>(&operation_state)
161 .await
162 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
163 // 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.
164 latest_commit: object.get::<LatestCommit>(&operation_state).await.ok(),
165 tree_rev: operation.rev,
166 tree,
167 };
168
169 Ok(info)
170 }
171 .boxed()
172 }
173
174 pub fn repository_file_from_id(
175 object: &Repository,
176 operation: RepositoryFileFromIdRequest,
177 state: DatabaseBackend,
178 operation_state: StackOperationState,
179 backend: BackendWrapper,
180 requester: Option<AuthenticatedUser>,
181 ) -> BoxFuture<'static, Result<RepositoryFile, OperationError<RepositoryError>>> {
182 let object = object.clone();
183
184 async move {
185 let object = backend
186 .get_object::<Repository>(&object.to_string(), &operation_state)
187 .await
188 .unwrap();
189
190 let mut repository_backend = state.repository_backend.lock().await;
191 let file = repository_backend
192 .repository_file_from_id(
193 &requester,
194 object.object(),
195 &RepositoryFileFromIdRequest(operation.0),
196 )
197 .await
198 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
199 drop(repository_backend);
200
201 Ok(file)
202 }
203 .boxed()
204 }
205
206 pub fn repository_file_from_path(
207 object: &Repository,
208 operation: RepositoryFileFromPathRequest,
209 state: DatabaseBackend,
210 operation_state: StackOperationState,
211 backend: BackendWrapper,
212 requester: Option<AuthenticatedUser>,
213 ) -> BoxFuture<'static, Result<RepositoryFile, OperationError<RepositoryError>>> {
214 let object = object.clone();
215
216 async move {
217 let object = backend
218 .get_object::<Repository>(&object.to_string(), &operation_state)
219 .await
220 .unwrap();
221
222 let mut repository_backend = state.repository_backend.lock().await;
223 let file = repository_backend
224 .repository_file_from_path(
225 &requester,
226 object.object(),
227 &RepositoryFileFromPathRequest {
228 rev: operation.rev,
229 path: operation.path,
230 },
231 )
232 .await
233 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
234 drop(repository_backend);
235
236 Ok(file)
237 }
238 .boxed()
239 }
240
241 pub fn repository_diff(
242 object: &Repository,
243 operation: RepositoryDiffRequest,
244 state: DatabaseBackend,
245 operation_state: StackOperationState,
246 backend: BackendWrapper,
247 requester: Option<AuthenticatedUser>,
248 ) -> BoxFuture<'static, Result<RepositoryDiff, OperationError<RepositoryError>>> {
249 let object = object.clone();
250
251 async move {
252 let object = backend
253 .get_object::<Repository>(&object.to_string(), &operation_state)
254 .await
255 .unwrap();
256
257 let mut repository_backend = state.repository_backend.lock().await;
258 let diff = repository_backend
259 .repository_diff(&requester, object.object(), &operation)
260 .await
261 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
262 drop(repository_backend);
263
264 Ok(diff)
265 }
266 .boxed()
267 }
268
269 pub fn repository_diff_patch(
270 object: &Repository,
271 operation: RepositoryDiffPatchRequest,
272 state: DatabaseBackend,
273 operation_state: StackOperationState,
274 backend: BackendWrapper,
275 requester: Option<AuthenticatedUser>,
276 ) -> BoxFuture<'static, Result<String, OperationError<RepositoryError>>> {
277 let object = object.clone();
278
279 async move {
280 let object = backend
281 .get_object::<Repository>(&object.to_string(), &operation_state)
282 .await
283 .unwrap();
284
285 let mut repository_backend = state.repository_backend.lock().await;
286 let patch = repository_backend
287 .repository_diff_patch(&requester, object.object(), &operation)
288 .await
289 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
290 drop(repository_backend);
291
292 Ok(patch)
293 }
294 .boxed()
295 }
296
297 pub fn repository_commit_before(
298 object: &Repository,
299 operation: RepositoryCommitBeforeRequest,
300 state: DatabaseBackend,
301 operation_state: StackOperationState,
302 backend: BackendWrapper,
303 requester: Option<AuthenticatedUser>,
304 ) -> BoxFuture<'static, Result<Commit, OperationError<RepositoryError>>> {
305 let object = object.clone();
306
307 async move {
308 let object = backend
309 .get_object::<Repository>(&object.to_string(), &operation_state)
310 .await
311 .unwrap();
312
313 let mut repository_backend = state.repository_backend.lock().await;
314 let file = repository_backend
315 .repository_commit_before(&requester, object.object(), &operation)
316 .await
317 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
318 drop(repository_backend);
319
320 Ok(file)
321 }
322 .boxed()
323 }
324
325 pub fn repository_get_value(
326 object: &Repository,
327 operation: GetValue<AnyValue<Repository>>,
328 state: DatabaseBackend,
329 ) -> BoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> {
330 let object = object.clone();
331
332 async move {
333 let mut repository_backend = state.repository_backend.lock().await;
334 let value = repository_backend
335 .get_value(&object, &operation.value_name)
336 .await
337 .map_err(|e| {
338 OperationError::Internal(format!("error getting value: {}", e.to_string()))
339 })?;
340
341 Ok(value)
342 }
343 .boxed()
344 }
345
346 pub fn repository_get_setting(
347 object: &Repository,
348 operation: GetSetting<AnySetting>,
349 state: DatabaseBackend,
350 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
351 let object = object.clone();
352
353 async move {
354 let mut repository_backend = state.repository_backend.lock().await;
355 let value = repository_backend
356 .get_setting(&object, &operation.setting_name)
357 .await
358 .map_err(|e| OperationError::Internal(e.to_string()))?;
359
360 Ok(value)
361 }
362 .boxed()
363 }
364
365 // pub fn repository_set_setting(
366 // object: &Repository,
367 // operation: SetSetting<AnySetting>,
368 // state: DatabaseBackend,
369 // ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
370 // let object = object.clone();
371
372 // async move {
373 // let mut repository_backend = state.repository_backend.lock().await;
374 // let value = repository_backend
375 // .write_setting(&object, &operation.setting_name, &operation.value.0)
376 // .await
377 // .map_err(|e| OperationError::Internal(e.to_string()))?;
378
379 // Ok(value)
380 // }
381 // .boxed()
382 // }
383
384 pub fn instance_authentication_request(
385 object: &Instance,
386 operation: AuthenticationTokenRequest,
387 state: DatabaseBackend,
388 // Authorizes the request for SAME-INSTANCE
389 _authorized_instance: AuthorizedInstance,
390 ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> {
391 let object = object.clone();
392 async move {
393 let mut backend = state.user_backend.lock().await;
394
395 backend
396 .login(&object, operation)
397 .await
398 .map_err(|e| OperationError::Internal(e.to_string()))
399 }
400 .boxed()
401 }
402
403 pub fn instance_registration_request(
404 _object: &Instance,
405 operation: RegisterAccountRequest,
406 state: DatabaseBackend,
407 // Authorizes the request for SAME-INSTANCE
408 _authorized_instance: AuthorizedInstance,
409 ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> {
410 async move {
411 let mut backend = state.user_backend.lock().await;
412
413 backend
414 .register(operation)
415 .await
416 .map_err(|e| OperationError::Internal(e.to_string()))
417 }
418 .boxed()
419 }
420
421 pub fn instance_create_repository_request(
422 _object: &Instance,
423 operation: RepositoryCreateRequest,
424 state: DatabaseBackend,
425 requester: AuthenticatedUser,
426 // Authorizes the request for SAME-INSTANCE
427 _authorized_instance: AuthorizedInstance,
428 ) -> BoxFuture<'static, Result<Repository, OperationError<InstanceError>>> {
429 async move {
430 let mut backend = state.repository_backend.lock().await;
431
432 backend
433 .create_repository(&requester, &operation)
434 .await
435 .map_err(|e| OperationError::Internal(e.to_string()))
436 }
437 .boxed()
438 }
439
440 pub fn user_get_value_display_name(
441 object: &User,
442 operation: GetValue<DisplayName>,
443 state: DatabaseBackend,
444 _requester: AuthorizedUser,
445 ) -> BoxFuture<'static, Result<DisplayName, OperationError<GetValueError>>> {
446 let object = object.clone();
447
448 async move {
449 let mut backend = state.user_backend.lock().await;
450
451 let raw_value = backend
452 .get_value(&object, &operation.value_name)
453 .await
454 .map_err(|e| OperationError::Internal(e.to_string()))?;
455
456 Ok(serde_json::from_value(raw_value.into_inner())
457 .map_err(|e| OperationError::Internal(e.to_string()))?)
458 }
459 .boxed()
460 }
461
462 pub fn user_get_value_bio(
463 object: &User,
464 operation: GetValue<Bio>,
465 state: DatabaseBackend,
466 ) -> BoxFuture<'static, Result<Bio, OperationError<GetValueError>>> {
467 let object = object.clone();
468
469 async move {
470 let mut backend = state.user_backend.lock().await;
471
472 let raw_value = backend
473 .get_value(&object, &operation.value_name)
474 .await
475 .map_err(|e| OperationError::Internal(e.to_string()))?;
476
477 Ok(serde_json::from_value(raw_value.into_inner())
478 .map_err(|e| OperationError::Internal(e.to_string()))?)
479 }
480 .boxed()
481 }
482
483 pub fn repository_get_value_description(
484 object: &Repository,
485 operation: GetValue<Description>,
486 state: DatabaseBackend,
487 ) -> BoxFuture<'static, Result<Description, OperationError<GetValueError>>> {
488 let object = object.clone();
489
490 async move {
491 let mut backend = state.repository_backend.lock().await;
492
493 let raw_value = backend
494 .get_value(&object, &operation.value_name)
495 .await
496 .map_err(|e| OperationError::Internal(e.to_string()))?;
497
498 Ok(serde_json::from_value(raw_value.into_inner())
499 .map_err(|e| OperationError::Internal(e.to_string()))?)
500 }
501 .boxed()
502 }
503
504 pub fn repository_get_value_visibility(
505 object: &Repository,
506 operation: GetValue<Visibility>,
507 state: DatabaseBackend,
508 ) -> BoxFuture<'static, Result<Visibility, OperationError<GetValueError>>> {
509 let object = object.clone();
510
511 async move {
512 let mut backend = state.repository_backend.lock().await;
513
514 let raw_value = backend
515 .get_value(&object, &operation.value_name)
516 .await
517 .map_err(|e| OperationError::Internal(e.to_string()))?;
518
519 Ok(serde_json::from_value(raw_value.into_inner())
520 .map_err(|e| OperationError::Internal(e.to_string()))?)
521 }
522 .boxed()
523 }
524