Error handling refactor
This refactor aims to improve error handling throughout the project by refining the overarching error types and increasing usage of proper error handling. Replaced existing networked operation error with `NetworkOperationError`. `NetworkOperationError` does not forward any internal error details, which allows `OperationError` to grow into a better error type. `OperationError` now has support for storing real typed errors inside of it for better debugging. `IntoInternalError` is a trait which allows for easy conversion of error types into `OperationError::internal`.
parent: tbd commit: e02c03d
Showing 8 changed files with 279 insertions and 141 deletions
Cargo.lock
@@ -809,12 +809,14 @@ dependencies = [ | ||
809 | 809 | name = "giterated-stack" |
810 | 810 | version = "0.1.0" |
811 | 811 | dependencies = [ |
812 | "anyhow", | |
812 | 813 | "async-trait", |
813 | 814 | "bincode", |
814 | 815 | "futures-util", |
815 | 816 | "giterated-models", |
816 | 817 | "serde", |
817 | 818 | "serde_json", |
819 | "thiserror", | |
818 | 820 | "tokio", |
819 | 821 | "tracing", |
820 | 822 | ] |
giterated-daemon/src/authorization.rs
@@ -14,6 +14,11 @@ use giterated_models::user::User; | ||
14 | 14 | |
15 | 15 | use giterated_models::value::GetValueTyped; |
16 | 16 | use giterated_models::{object::ObjectRequest, settings::SetSetting, value::GiteratedObjectValue}; |
17 | ||
18 | #[derive(Debug, thiserror::Error)] | |
19 | #[error("unauthorized")] | |
20 | pub struct UnauthorizedError; | |
21 | ||
17 | 22 | #[async_trait::async_trait] |
18 | 23 | pub trait AuthorizedOperation<O: GiteratedObject, S> { |
19 | 24 | /// Authorizes the operation, returning whether the operation was |
@@ -23,7 +28,7 @@ pub trait AuthorizedOperation<O: GiteratedObject, S> { | ||
23 | 28 | authenticating_user: Option<&User>, |
24 | 29 | object: &O, |
25 | 30 | state: &mut S, |
26 | ) -> Result<bool, OperationError<()>>; | |
31 | ) -> Result<bool, OperationError<UnauthorizedError>>; | |
27 | 32 | } |
28 | 33 | |
29 | 34 | #[async_trait::async_trait] |
@@ -33,7 +38,7 @@ impl AuthorizedOperation<User, ConnectionState> for SetSetting { | ||
33 | 38 | _authenticating_user: Option<&User>, |
34 | 39 | _object: &User, |
35 | 40 | _state: &mut ConnectionState, |
36 | ) -> Result<bool, OperationError<()>> { | |
41 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
37 | 42 | // TODO |
38 | 43 | Ok(true) |
39 | 44 | } |
@@ -46,7 +51,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for SetSetting { | ||
46 | 51 | _authenticating_user: Option<&User>, |
47 | 52 | _object: &Repository, |
48 | 53 | _state: &mut ConnectionState, |
49 | ) -> Result<bool, OperationError<()>> { | |
54 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
50 | 55 | // TODO |
51 | 56 | Ok(true) |
52 | 57 | } |
@@ -61,7 +66,7 @@ impl<V: GiteratedObjectValue + Send + Sync + Debug + Clone> | ||
61 | 66 | _authenticating_user: Option<&User>, |
62 | 67 | _object: &Repository, |
63 | 68 | _state: &mut ConnectionState, |
64 | ) -> Result<bool, OperationError<()>> { | |
69 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
65 | 70 | // TODO |
66 | 71 | Ok(true) |
67 | 72 | } |
@@ -74,7 +79,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for ObjectRequest { | ||
74 | 79 | _authenticating_user: Option<&User>, |
75 | 80 | _object: &Repository, |
76 | 81 | _state: &mut ConnectionState, |
77 | ) -> Result<bool, OperationError<()>> { | |
82 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
78 | 83 | // TODO |
79 | 84 | Ok(true) |
80 | 85 | } |
@@ -87,7 +92,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for RepositoryFileInspectR | ||
87 | 92 | _authenticating_user: Option<&User>, |
88 | 93 | _object: &Repository, |
89 | 94 | _state: &mut ConnectionState, |
90 | ) -> Result<bool, OperationError<()>> { | |
95 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
91 | 96 | // TODO |
92 | 97 | Ok(true) |
93 | 98 | } |
@@ -100,7 +105,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for RepositoryIssuesReques | ||
100 | 105 | _authenticating_user: Option<&User>, |
101 | 106 | _object: &Repository, |
102 | 107 | _state: &mut ConnectionState, |
103 | ) -> Result<bool, OperationError<()>> { | |
108 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
104 | 109 | // TODO |
105 | 110 | Ok(true) |
106 | 111 | } |
@@ -113,7 +118,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for RepositoryIssueLabelsR | ||
113 | 118 | _authenticating_user: Option<&User>, |
114 | 119 | _object: &Repository, |
115 | 120 | _state: &mut ConnectionState, |
116 | ) -> Result<bool, OperationError<()>> { | |
121 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
117 | 122 | // TODO |
118 | 123 | Ok(true) |
119 | 124 | } |
@@ -126,7 +131,7 @@ impl AuthorizedOperation<Repository, ConnectionState> for RepositoryIssuesCountR | ||
126 | 131 | _authenticating_user: Option<&User>, |
127 | 132 | _object: &Repository, |
128 | 133 | _state: &mut ConnectionState, |
129 | ) -> Result<bool, OperationError<()>> { | |
134 | ) -> Result<bool, OperationError<UnauthorizedError>> { | |
130 | 135 | // TODO |
131 | 136 | Ok(true) |
132 | 137 | } |
giterated-daemon/src/connection/wrapper.rs
@@ -170,9 +170,12 @@ pub async fn connection_wrapper( | ||
170 | 170 | operation_state.instance = None; |
171 | 171 | |
172 | 172 | if let Err(OperationError::Internal(internal_error)) = &result { |
173 | error!("An internal error has occured: {}", internal_error); | |
173 | error!("An internal error has occurred:\n{:?}", internal_error); | |
174 | 174 | } |
175 | 175 | |
176 | // Map error to the network variant | |
177 | let result = result.map_err(|e| e.into_network()); | |
178 | ||
176 | 179 | let mut socket = connection_state.socket.lock().await; |
177 | 180 | let _ = socket |
178 | 181 | .send(Message::Binary(bincode::serialize(&result).unwrap())) |
giterated-daemon/src/database_backend/handler.rs
@@ -1,9 +1,11 @@ | ||
1 | use std::{error::Error, sync::Arc}; | |
1 | use std::sync::Arc; | |
2 | 2 | |
3 | 3 | use futures_util::{future::LocalBoxFuture, FutureExt}; |
4 | 4 | use giterated_models::{ |
5 | 5 | authenticated::UserAuthenticationToken, |
6 | error::{GetValueError, InstanceError, OperationError, RepositoryError, UserError}, | |
6 | error::{ | |
7 | GetValueError, InstanceError, IntoInternalError, OperationError, RepositoryError, UserError, | |
8 | }, | |
7 | 9 | instance::{ |
8 | 10 | AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, |
9 | 11 | }, |
@@ -39,7 +41,7 @@ pub fn user_get_repositories( | ||
39 | 41 | let repositories_response = user_backend |
40 | 42 | .repositories_for_user(&requester, &object) |
41 | 43 | .await |
42 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
44 | .as_internal_error()?; | |
43 | 45 | drop(user_backend); |
44 | 46 | let mut repositories_backend = state.repository_backend.lock().await; |
45 | 47 | |
@@ -49,7 +51,7 @@ pub fn user_get_repositories( | ||
49 | 51 | if repositories_backend |
50 | 52 | .exists(&requester, &repository.repository) |
51 | 53 | .await |
52 | .map_err(|e| OperationError::Internal(e.to_string()))? | |
54 | .as_internal_error()? | |
53 | 55 | { |
54 | 56 | repositories.push(repository); |
55 | 57 | } |
@@ -72,7 +74,7 @@ pub fn user_get_value( | ||
72 | 74 | let value = user_backend |
73 | 75 | .get_value(&object, &operation.value_name) |
74 | 76 | .await |
75 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
77 | .as_internal_error()?; | |
76 | 78 | |
77 | 79 | Ok(value) |
78 | 80 | } |
@@ -91,7 +93,7 @@ pub fn user_get_setting( | ||
91 | 93 | let value = user_backend |
92 | 94 | .get_setting(&object, &operation.setting_name) |
93 | 95 | .await |
94 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
96 | .as_internal_error()?; | |
95 | 97 | |
96 | 98 | Ok(value.0) |
97 | 99 | } |
@@ -125,7 +127,7 @@ pub fn repository_info( | ||
125 | 127 | }, |
126 | 128 | ) |
127 | 129 | .await |
128 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
130 | .as_internal_error()?; | |
129 | 131 | |
130 | 132 | let statistics = repository_backend |
131 | 133 | .repository_get_statistics( |
@@ -136,7 +138,7 @@ pub fn repository_info( | ||
136 | 138 | }, |
137 | 139 | ) |
138 | 140 | .await |
139 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
141 | .as_internal_error()?; | |
140 | 142 | drop(repository_backend); |
141 | 143 | |
142 | 144 | let info = RepositoryView { |
@@ -146,11 +148,11 @@ pub fn repository_info( | ||
146 | 148 | visibility: object |
147 | 149 | .get::<Visibility>(&operation_state) |
148 | 150 | .await |
149 | .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?, | |
151 | .as_internal_error()?, | |
150 | 152 | default_branch: object |
151 | 153 | .get::<DefaultBranch>(&operation_state) |
152 | 154 | .await |
153 | .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?, | |
155 | .as_internal_error()?, | |
154 | 156 | // 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. |
155 | 157 | latest_commit: object.get::<LatestCommit>(&operation_state).await.ok(), |
156 | 158 | stats: statistics, |
@@ -187,7 +189,7 @@ pub fn repository_get_statistics( | ||
187 | 189 | &RepositoryStatisticsRequest { rev: operation.rev }, |
188 | 190 | ) |
189 | 191 | .await |
190 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
192 | .as_internal_error()?; | |
191 | 193 | drop(repository_backend); |
192 | 194 | |
193 | 195 | Ok(statistics) |
@@ -215,7 +217,7 @@ pub fn repository_get_branches( | ||
215 | 217 | let branches = repository_backend |
216 | 218 | .repository_get_branches(&requester, object.object(), &operation) |
217 | 219 | .await |
218 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
220 | .as_internal_error()?; | |
219 | 221 | drop(repository_backend); |
220 | 222 | |
221 | 223 | Ok(branches) |
@@ -248,7 +250,7 @@ pub fn repository_file_from_id( | ||
248 | 250 | &RepositoryFileFromIdRequest(operation.0), |
249 | 251 | ) |
250 | 252 | .await |
251 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
253 | .as_internal_error()?; | |
252 | 254 | drop(repository_backend); |
253 | 255 | |
254 | 256 | Ok(file) |
@@ -283,7 +285,7 @@ pub fn repository_file_from_path( | ||
283 | 285 | }, |
284 | 286 | ) |
285 | 287 | .await |
286 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
288 | .as_internal_error()?; | |
287 | 289 | drop(repository_backend); |
288 | 290 | |
289 | 291 | Ok(file) |
@@ -318,7 +320,7 @@ pub fn repository_last_commit_of_file( | ||
318 | 320 | }, |
319 | 321 | ) |
320 | 322 | .await |
321 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
323 | .as_internal_error()?; | |
322 | 324 | drop(repository_backend); |
323 | 325 | |
324 | 326 | Ok(commit) |
@@ -350,7 +352,7 @@ pub fn repository_commit_by_id( | ||
350 | 352 | &RepositoryCommitFromIdRequest(operation.0), |
351 | 353 | ) |
352 | 354 | .await |
353 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
355 | .as_internal_error()?; | |
354 | 356 | drop(repository_backend); |
355 | 357 | |
356 | 358 | Ok(commit) |
@@ -378,7 +380,7 @@ pub fn repository_diff( | ||
378 | 380 | let diff = repository_backend |
379 | 381 | .repository_diff(&requester, object.object(), &operation) |
380 | 382 | .await |
381 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
383 | .as_internal_error()?; | |
382 | 384 | drop(repository_backend); |
383 | 385 | |
384 | 386 | Ok(diff) |
@@ -406,7 +408,7 @@ pub fn repository_diff_patch( | ||
406 | 408 | let patch = repository_backend |
407 | 409 | .repository_diff_patch(&requester, object.object(), &operation) |
408 | 410 | .await |
409 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
411 | .as_internal_error()?; | |
410 | 412 | drop(repository_backend); |
411 | 413 | |
412 | 414 | Ok(patch) |
@@ -434,7 +436,7 @@ pub fn repository_commit_before( | ||
434 | 436 | let file = repository_backend |
435 | 437 | .repository_commit_before(&requester, object.object(), &operation) |
436 | 438 | .await |
437 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
439 | .as_internal_error()?; | |
438 | 440 | drop(repository_backend); |
439 | 441 | |
440 | 442 | Ok(file) |
@@ -454,9 +456,7 @@ pub fn repository_get_value( | ||
454 | 456 | let value = repository_backend |
455 | 457 | .get_value(&object, &operation.value_name) |
456 | 458 | .await |
457 | .map_err(|e| { | |
458 | OperationError::Internal(format!("error getting value: {}", e.to_string())) | |
459 | })?; | |
459 | .as_internal_error()?; | |
460 | 460 | |
461 | 461 | Ok(value) |
462 | 462 | } |
@@ -475,7 +475,7 @@ pub fn repository_get_setting( | ||
475 | 475 | let value = repository_backend |
476 | 476 | .get_setting(&object, &operation.setting_name) |
477 | 477 | .await |
478 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
478 | .as_internal_error()?; | |
479 | 479 | |
480 | 480 | Ok(value.0) |
481 | 481 | } |
@@ -493,10 +493,7 @@ pub fn instance_authentication_request( | ||
493 | 493 | async move { |
494 | 494 | let mut backend = state.user_backend.lock().await; |
495 | 495 | |
496 | backend | |
497 | .login(&object, operation) | |
498 | .await | |
499 | .map_err(|e| OperationError::Internal(e.to_string())) | |
496 | backend.login(&object, operation).await.as_internal_error() | |
500 | 497 | } |
501 | 498 | .boxed_local() |
502 | 499 | } |
@@ -511,10 +508,7 @@ pub fn instance_registration_request( | ||
511 | 508 | async move { |
512 | 509 | let mut backend = state.user_backend.lock().await; |
513 | 510 | |
514 | backend | |
515 | .register(operation) | |
516 | .await | |
517 | .map_err(|e| OperationError::Internal(e.to_string())) | |
511 | backend.register(operation).await.as_internal_error() | |
518 | 512 | } |
519 | 513 | .boxed_local() |
520 | 514 | } |
@@ -533,7 +527,7 @@ pub fn instance_create_repository_request( | ||
533 | 527 | backend |
534 | 528 | .create_repository(&requester, &operation) |
535 | 529 | .await |
536 | .map_err(|e| OperationError::Internal(e.to_string())) | |
530 | .as_internal_error() | |
537 | 531 | } |
538 | 532 | .boxed_local() |
539 | 533 | } |
@@ -552,10 +546,9 @@ pub fn user_get_value_display_name( | ||
552 | 546 | let raw_value = backend |
553 | 547 | .get_value(&object, &operation.value_name) |
554 | 548 | .await |
555 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
549 | .as_internal_error()?; | |
556 | 550 | |
557 | Ok(serde_json::from_value(raw_value.into_inner()) | |
558 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
551 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
559 | 552 | } |
560 | 553 | .boxed_local() |
561 | 554 | } |
@@ -573,10 +566,9 @@ pub fn user_get_value_bio( | ||
573 | 566 | let raw_value = backend |
574 | 567 | .get_value(&object, &operation.value_name) |
575 | 568 | .await |
576 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
569 | .as_internal_error()?; | |
577 | 570 | |
578 | Ok(serde_json::from_value(raw_value.into_inner()) | |
579 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
571 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
580 | 572 | } |
581 | 573 | .boxed_local() |
582 | 574 | } |
@@ -594,10 +586,9 @@ pub fn repository_get_value_description( | ||
594 | 586 | let raw_value = backend |
595 | 587 | .get_value(&object, &operation.value_name) |
596 | 588 | .await |
597 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
589 | .as_internal_error()?; | |
598 | 590 | |
599 | Ok(serde_json::from_value(raw_value.into_inner()) | |
600 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
591 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
601 | 592 | } |
602 | 593 | .boxed_local() |
603 | 594 | } |
@@ -615,10 +606,9 @@ pub fn repository_get_value_visibility( | ||
615 | 606 | let raw_value = backend |
616 | 607 | .get_value(&object, &operation.value_name) |
617 | 608 | .await |
618 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
609 | .as_internal_error()?; | |
619 | 610 | |
620 | Ok(serde_json::from_value(raw_value.into_inner()) | |
621 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
611 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
622 | 612 | } |
623 | 613 | .boxed_local() |
624 | 614 | } |
@@ -636,10 +626,9 @@ pub fn repository_get_default_branch( | ||
636 | 626 | let raw_value = backend |
637 | 627 | .get_value(&object, &operation.value_name) |
638 | 628 | .await |
639 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
629 | .as_internal_error()?; | |
640 | 630 | |
641 | Ok(serde_json::from_value(raw_value.into_inner()) | |
642 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
631 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
643 | 632 | } |
644 | 633 | .boxed_local() |
645 | 634 | } |
@@ -657,10 +646,9 @@ pub fn repository_get_latest_commit( | ||
657 | 646 | let raw_value = backend |
658 | 647 | .get_value(&object, &operation.value_name) |
659 | 648 | .await |
660 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
649 | .as_internal_error()?; | |
661 | 650 | |
662 | Ok(serde_json::from_value(raw_value.into_inner()) | |
663 | .map_err(|e| OperationError::Internal(e.to_string()))?) | |
651 | Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) | |
664 | 652 | } |
665 | 653 | .boxed_local() |
666 | 654 | } |
giterated-models/src/error.rs
@@ -1,3 +1,5 @@ | ||
1 | use std::fmt::Display; | |
2 | ||
1 | 3 | use serde::{Deserialize, Serialize}; |
2 | 4 | |
3 | 5 | #[derive(Debug, thiserror::Error, Deserialize, Serialize)] |
@@ -20,12 +22,76 @@ pub enum GetValueError { | ||
20 | 22 | InvalidObject, |
21 | 23 | } |
22 | 24 | |
23 | #[derive(Serialize, Deserialize, Debug, thiserror::Error)] | |
25 | #[derive(Debug, thiserror::Error)] | |
26 | #[error("unauthorized")] | |
27 | pub struct UnauthorizedError; | |
28 | ||
29 | #[derive(Debug, thiserror::Error)] | |
24 | 30 | pub enum OperationError<B> { |
25 | #[error("the operation was handled but an error occured")] | |
31 | #[error("the operation was handled but an error occurred")] | |
32 | Operation(#[from] B), | |
33 | #[error("an internal error occurred: {0:?}")] | |
34 | Internal(anyhow::Error), | |
35 | #[error("the operation was unhandled or unrecognized")] | |
36 | Unhandled, | |
37 | } | |
38 | ||
39 | pub trait IntoInternalError<T>: Sized { | |
40 | fn as_internal_error<B>(self) -> Result<T, OperationError<B>>; | |
41 | ||
42 | fn as_internal_error_with_context<B, C>(self, context: C) -> Result<T, OperationError<B>> | |
43 | where | |
44 | C: Display + Send + Sync + 'static, | |
45 | { | |
46 | let internal_error = self.as_internal_error::<B>(); | |
47 | ||
48 | match internal_error { | |
49 | Ok(success) => Ok(success), | |
50 | Err(OperationError::Internal(internal)) => { | |
51 | Err(OperationError::Internal(internal.context(context))) | |
52 | } | |
53 | _ => unreachable!(), | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
58 | impl<E: Into<anyhow::Error>, T> IntoInternalError<T> for Result<T, E> { | |
59 | fn as_internal_error<B>(self) -> Result<T, OperationError<B>> { | |
60 | match self { | |
61 | Ok(success) => Ok(success), | |
62 | Err(err) => Err(OperationError::Internal(err.into())), | |
63 | } | |
64 | } | |
65 | } | |
66 | ||
67 | impl<B> OperationError<B> { | |
68 | pub fn into_network(self) -> NetworkOperationError<B> { | |
69 | match self { | |
70 | OperationError::Operation(operation_error) => { | |
71 | NetworkOperationError::Operation(operation_error) | |
72 | } | |
73 | OperationError::Internal(_) => NetworkOperationError::Internal, | |
74 | OperationError::Unhandled => NetworkOperationError::Unhandled, | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | #[derive(Debug, thiserror::Error)] | |
80 | #[error("an extractor failed with an error {0}")] | |
81 | pub struct ExtractorError<E: Into<anyhow::Error>>(#[from] pub E); | |
82 | ||
83 | impl<T, E: Into<anyhow::Error>> IntoInternalError<T> for ExtractorError<E> { | |
84 | fn as_internal_error<B>(self) -> Result<T, OperationError<B>> { | |
85 | todo!() | |
86 | } | |
87 | } | |
88 | ||
89 | #[derive(Serialize, Deserialize, Debug, thiserror::Error)] | |
90 | pub enum NetworkOperationError<B> { | |
91 | #[error("the operation was handled but an error occurred")] | |
26 | 92 | Operation(#[from] B), |
27 | #[error("an internal error occured: {0}")] | |
28 | Internal(String), | |
93 | #[error("internal error")] | |
94 | Internal, | |
29 | 95 | #[error("the operation was unhandled or unrecognized")] |
30 | 96 | Unhandled, |
31 | 97 | } |
giterated-stack/Cargo.toml
@@ -13,4 +13,6 @@ serde_json = "1.0" | ||
13 | 13 | bincode = "1.3" |
14 | 14 | futures-util = "0.3" |
15 | 15 | tracing = "0.1" |
16 | tokio = { version = "1.32", features = [ "full" ] } | |
16 | \ No newline at end of file | |
16 | tokio = { version = "1.32", features = [ "full" ] } | |
17 | anyhow = "1" | |
18 | thiserror = "1" | |
18 | \ No newline at end of file |
giterated-stack/src/handler.rs
@@ -1,9 +1,10 @@ | ||
1 | 1 | use std::{any::Any, collections::HashMap, sync::Arc}; |
2 | 2 | |
3 | use anyhow::Context; | |
3 | 4 | use futures_util::FutureExt; |
4 | 5 | use giterated_models::{ |
5 | 6 | authenticated::AuthenticatedPayload, |
6 | error::{GetValueError, OperationError}, | |
7 | error::{GetValueError, IntoInternalError, OperationError}, | |
7 | 8 | instance::Instance, |
8 | 9 | message::GiteratedMessage, |
9 | 10 | object::{ |
@@ -451,9 +452,28 @@ impl GiteratedStack { | ||
451 | 452 | // Special case |
452 | 453 | let operation: GetValue = serde_json::from_slice(&message.payload.0).unwrap(); |
453 | 454 | |
454 | return self | |
455 | .network_get_value(object, object_type.clone(), operation, operation_state) | |
455 | let result = self | |
456 | .network_get_value( | |
457 | object, | |
458 | object_type.clone(), | |
459 | operation.clone(), | |
460 | operation_state, | |
461 | ) | |
456 | 462 | .await; |
463 | ||
464 | // In the case of internal errors, attach context | |
465 | let result = result.map_err(|err| match err { | |
466 | OperationError::Operation(operation) => OperationError::Operation(operation), | |
467 | OperationError::Internal(internal) => { | |
468 | OperationError::Internal(internal.context(format!( | |
469 | "{}::get_value::<{}> outcome", | |
470 | object_type, operation.value_name | |
471 | ))) | |
472 | } | |
473 | OperationError::Unhandled => OperationError::Unhandled, | |
474 | }); | |
475 | ||
476 | return result; | |
457 | 477 | } else if message.operation == "get_setting" { |
458 | 478 | let operation: GetSetting = serde_json::from_slice(&message.payload.0).unwrap(); |
459 | 479 | let setting_meta = self |
@@ -478,7 +498,12 @@ impl GiteratedStack { | ||
478 | 498 | |
479 | 499 | OperationError::Operation(serde_json::to_vec(&failure).unwrap()) |
480 | 500 | } |
481 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
501 | OperationError::Internal(internal) => { | |
502 | OperationError::Internal(internal.context(format!( | |
503 | "{}::get_setting::<{}> handler outcome", | |
504 | object_type, setting_meta.name | |
505 | ))) | |
506 | } | |
482 | 507 | OperationError::Unhandled => OperationError::Unhandled, |
483 | 508 | }), |
484 | 509 | }; |
@@ -508,8 +533,11 @@ impl GiteratedStack { | ||
508 | 533 | .get(&target) |
509 | 534 | .ok_or_else(|| OperationError::Unhandled)?; |
510 | 535 | |
511 | let operation = (meta.deserialize)(&message.payload.0) | |
512 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
536 | let operation = | |
537 | (meta.deserialize)(&message.payload.0).as_internal_error_with_context(format!( | |
538 | "deserializing operation {}::{}", | |
539 | target.object_name, target.operation_name | |
540 | ))?; | |
513 | 541 | |
514 | 542 | trace!( |
515 | 543 | "Deserialized operation for network message {}::<{}>", |
@@ -534,14 +562,17 @@ impl GiteratedStack { | ||
534 | 562 | |
535 | 563 | // Deserialize the raw result for the network |
536 | 564 | match raw_result { |
537 | Ok(success) => Ok((meta.serialize_success)(success) | |
538 | .map_err(|e| OperationError::Internal(e.to_string()))?), | |
565 | Ok(success) => Ok((meta.serialize_success)(success).as_internal_error()?), | |
539 | 566 | Err(err) => Err(match err { |
540 | OperationError::Operation(failure) => OperationError::Operation( | |
541 | (meta.serialize_error)(failure) | |
542 | .map_err(|e| OperationError::Internal(e.to_string()))?, | |
543 | ), | |
544 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
567 | OperationError::Operation(failure) => { | |
568 | OperationError::Operation((meta.serialize_error)(failure).as_internal_error()?) | |
569 | } | |
570 | OperationError::Internal(internal) => { | |
571 | OperationError::Internal(internal.context(format!( | |
572 | "operation {}::{} handler outcome", | |
573 | target.object_name, target.operation_name | |
574 | ))) | |
575 | } | |
545 | 576 | OperationError::Unhandled => OperationError::Unhandled, |
546 | 577 | }), |
547 | 578 | } |
@@ -580,8 +611,7 @@ impl GiteratedStack { | ||
580 | 611 | { |
581 | 612 | Ok(success) => { |
582 | 613 | // Serialize success, which is the value type itself |
583 | let serialized = (value_meta.serialize)(success) | |
584 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
614 | let serialized = (value_meta.serialize)(success).as_internal_error()?; | |
585 | 615 | |
586 | 616 | Ok(serialized) |
587 | 617 | } |
@@ -590,10 +620,7 @@ impl GiteratedStack { | ||
590 | 620 | // Failure is sourced from GetValue operation, but this is hardcoded for now |
591 | 621 | let failure: GetValueError = *failure.downcast().unwrap(); |
592 | 622 | |
593 | OperationError::Operation( | |
594 | serde_json::to_vec(&failure) | |
595 | .map_err(|e| OperationError::Internal(e.to_string()))?, | |
596 | ) | |
623 | OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?) | |
597 | 624 | } |
598 | 625 | OperationError::Internal(internal) => OperationError::Internal(internal), |
599 | 626 | OperationError::Unhandled => OperationError::Unhandled, |
@@ -693,7 +720,13 @@ impl ObjectBackend<StackOperationState> for Arc<GiteratedStack> { | ||
693 | 720 | OperationError::Operation(failure) => { |
694 | 721 | OperationError::Operation(*failure.downcast::<D::Failure>().unwrap()) |
695 | 722 | } |
696 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
723 | OperationError::Internal(internal) => { | |
724 | OperationError::Internal(internal.context(format!( | |
725 | "{}::get_value::<{}> handler outcome", | |
726 | O::object_name(), | |
727 | value_name | |
728 | ))) | |
729 | } | |
697 | 730 | OperationError::Unhandled => OperationError::Unhandled, |
698 | 731 | }), |
699 | 732 | }; |
@@ -702,6 +735,7 @@ impl ObjectBackend<StackOperationState> for Arc<GiteratedStack> { | ||
702 | 735 | return Err(OperationError::Unhandled); |
703 | 736 | } else if operation.is::<GetSetting>() { |
704 | 737 | let get_setting: Box<GetSetting> = operation.downcast().unwrap(); |
738 | let setting_name = get_setting.setting_name.clone(); | |
705 | 739 | |
706 | 740 | let raw_result = self |
707 | 741 | .get_setting( |
@@ -725,7 +759,13 @@ impl ObjectBackend<StackOperationState> for Arc<GiteratedStack> { | ||
725 | 759 | // We know this is the right type |
726 | 760 | OperationError::Operation(*failure.downcast().unwrap()) |
727 | 761 | } |
728 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
762 | OperationError::Internal(internal) => { | |
763 | OperationError::Internal(internal.context(format!( | |
764 | "{}::get_setting::<{}> handler outcome", | |
765 | O::object_name(), | |
766 | setting_name | |
767 | ))) | |
768 | } | |
729 | 769 | OperationError::Unhandled => OperationError::Unhandled, |
730 | 770 | }), |
731 | 771 | }; |
@@ -773,7 +813,12 @@ impl ObjectBackend<StackOperationState> for Arc<GiteratedStack> { | ||
773 | 813 | match raw_result { |
774 | 814 | Ok(result) => Ok(*result.downcast::<D::Success>().unwrap()), |
775 | 815 | Err(err) => Err(match err { |
776 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
816 | OperationError::Internal(internal) => { | |
817 | OperationError::Internal(internal.context(format!( | |
818 | "operation {}::{} handler outcome", | |
819 | operation_type.object_name, operation_type.operation_name | |
820 | ))) | |
821 | } | |
777 | 822 | OperationError::Operation(boxed_error) => { |
778 | 823 | OperationError::Operation(*boxed_error.downcast::<D::Failure>().unwrap()) |
779 | 824 | } |
giterated-stack/src/lib.rs
@@ -5,12 +5,12 @@ pub use meta::*; | ||
5 | 5 | pub mod state; |
6 | 6 | pub mod update; |
7 | 7 | |
8 | use std::{any::Any, future::Future, ops::Deref, pin::Pin, sync::Arc}; | |
8 | use std::{any::Any, convert::Infallible, future::Future, ops::Deref, pin::Pin, sync::Arc}; | |
9 | 9 | |
10 | 10 | use core::fmt::Debug; |
11 | 11 | use futures_util::FutureExt; |
12 | 12 | use giterated_models::{ |
13 | error::OperationError, | |
13 | error::{ExtractorError, IntoInternalError, OperationError, UnauthorizedError}, | |
14 | 14 | instance::{ |
15 | 15 | AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, |
16 | 16 | }, |
@@ -22,7 +22,6 @@ use giterated_models::{ | ||
22 | 22 | user::User, |
23 | 23 | value::GetValue, |
24 | 24 | }; |
25 | use serde::{de::DeserializeOwned, Serialize}; | |
26 | 25 | |
27 | 26 | #[derive(Clone, Debug, Hash, Eq, PartialEq)] |
28 | 27 | struct ObjectOperationPair { |
@@ -110,6 +109,7 @@ where | ||
110 | 109 | <D as GiteratedOperation<O>>::Failure: Send, |
111 | 110 | S: Send + Sync + Clone + 'static, |
112 | 111 | O1: FromOperationState<O, D>, |
112 | ExtractorError<<O1 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
113 | 113 | { |
114 | 114 | fn operation_name(&self) -> &str { |
115 | 115 | D::operation_name() |
@@ -128,7 +128,7 @@ where | ||
128 | 128 | ) -> Result<D::Success, OperationError<D::Failure>> { |
129 | 129 | let o1 = O1::from_state(object, &operation, operation_state) |
130 | 130 | .await |
131 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
131 | .as_internal_error()?; | |
132 | 132 | self.clone()(object, operation, state, o1).await |
133 | 133 | } |
134 | 134 | } |
@@ -152,7 +152,9 @@ where | ||
152 | 152 | <D as GiteratedOperation<O>>::Failure: Send, |
153 | 153 | S: Send + Sync + Clone + 'static, |
154 | 154 | O1: FromOperationState<O, D>, |
155 | ExtractorError<<O1 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
155 | 156 | O2: FromOperationState<O, D>, |
157 | ExtractorError<<O2 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
156 | 158 | { |
157 | 159 | fn operation_name(&self) -> &str { |
158 | 160 | D::operation_name() |
@@ -171,10 +173,10 @@ where | ||
171 | 173 | ) -> Result<D::Success, OperationError<D::Failure>> { |
172 | 174 | let o1 = O1::from_state(object, &operation, operation_state) |
173 | 175 | .await |
174 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
176 | .as_internal_error()?; | |
175 | 177 | let o2 = O2::from_state(object, &operation, operation_state) |
176 | 178 | .await |
177 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
179 | .as_internal_error()?; | |
178 | 180 | self.clone()(object, operation, state, o1, o2).await |
179 | 181 | } |
180 | 182 | } |
@@ -199,8 +201,11 @@ where | ||
199 | 201 | <D as GiteratedOperation<O>>::Failure: Send, |
200 | 202 | S: Send + Sync + Clone + 'static, |
201 | 203 | O1: FromOperationState<O, D>, |
204 | ExtractorError<<O1 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
202 | 205 | O2: FromOperationState<O, D>, |
206 | ExtractorError<<O2 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
203 | 207 | O3: FromOperationState<O, D>, |
208 | ExtractorError<<O3 as FromOperationState<O, D>>::Error>: Into<anyhow::Error>, | |
204 | 209 | { |
205 | 210 | fn operation_name(&self) -> &str { |
206 | 211 | D::operation_name() |
@@ -219,13 +224,13 @@ where | ||
219 | 224 | ) -> Result<D::Success, OperationError<D::Failure>> { |
220 | 225 | let o1 = O1::from_state(object, &operation, operation_state) |
221 | 226 | .await |
222 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
227 | .as_internal_error()?; | |
223 | 228 | let o2 = O2::from_state(object, &operation, operation_state) |
224 | 229 | .await |
225 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
230 | .as_internal_error()?; | |
226 | 231 | let o3 = O3::from_state(object, &operation, operation_state) |
227 | 232 | .await |
228 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
233 | .as_internal_error()?; | |
229 | 234 | self.clone()(object, operation, state, o1, o2, o3).await |
230 | 235 | } |
231 | 236 | } |
@@ -315,26 +320,26 @@ impl OperationWrapper { | ||
315 | 320 | |
316 | 321 | #[async_trait::async_trait(?Send)] |
317 | 322 | pub trait FromOperationState<O: GiteratedObject, D: GiteratedOperation<O>>: Sized + Clone { |
318 | type Error: Serialize + DeserializeOwned; | |
323 | type Error: Into<anyhow::Error>; | |
319 | 324 | |
320 | 325 | async fn from_state( |
321 | 326 | object: &O, |
322 | 327 | operation: &D, |
323 | 328 | state: &StackOperationState, |
324 | ) -> Result<Self, OperationError<Self::Error>>; | |
329 | ) -> Result<Self, ExtractorError<Self::Error>>; | |
325 | 330 | } |
326 | 331 | |
327 | 332 | #[async_trait::async_trait(?Send)] |
328 | 333 | impl<O: GiteratedObject, D: GiteratedOperation<O>> FromOperationState<O, D> |
329 | 334 | for Arc<GiteratedStack> |
330 | 335 | { |
331 | type Error = (); | |
336 | type Error = Infallible; | |
332 | 337 | |
333 | 338 | async fn from_state( |
334 | 339 | _object: &O, |
335 | 340 | _operation: &D, |
336 | 341 | state: &StackOperationState, |
337 | ) -> Result<Self, OperationError<()>> { | |
342 | ) -> Result<Self, ExtractorError<Infallible>> { | |
338 | 343 | Ok(state.runtime.clone()) |
339 | 344 | } |
340 | 345 | } |
@@ -343,32 +348,36 @@ impl<O: GiteratedObject, D: GiteratedOperation<O>> FromOperationState<O, D> | ||
343 | 348 | impl<O: GiteratedObject, D: GiteratedOperation<O>> FromOperationState<O, D> |
344 | 349 | for StackOperationState |
345 | 350 | { |
346 | type Error = (); | |
351 | type Error = Infallible; | |
347 | 352 | |
348 | 353 | async fn from_state( |
349 | 354 | _object: &O, |
350 | 355 | _operation: &D, |
351 | 356 | state: &StackOperationState, |
352 | ) -> Result<StackOperationState, OperationError<()>> { | |
357 | ) -> Result<StackOperationState, ExtractorError<Infallible>> { | |
353 | 358 | Ok(state.clone()) |
354 | 359 | } |
355 | 360 | } |
356 | 361 | |
362 | #[derive(Debug, thiserror::Error)] | |
363 | #[error("missing value")] | |
364 | pub struct MissingValue; | |
365 | ||
357 | 366 | #[async_trait::async_trait(?Send)] |
358 | 367 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> |
359 | 368 | for AuthenticatedUser |
360 | 369 | { |
361 | type Error = (); | |
370 | type Error = MissingValue; | |
362 | 371 | |
363 | 372 | async fn from_state( |
364 | 373 | _object: &O, |
365 | 374 | _operation: &D, |
366 | 375 | state: &StackOperationState, |
367 | ) -> Result<AuthenticatedUser, OperationError<()>> { | |
376 | ) -> Result<AuthenticatedUser, ExtractorError<MissingValue>> { | |
368 | 377 | state |
369 | 378 | .user |
370 | 379 | .clone() |
371 | .ok_or_else(|| OperationError::Operation(())) | |
380 | .ok_or_else(|| ExtractorError(MissingValue)) | |
372 | 381 | } |
373 | 382 | } |
374 | 383 | |
@@ -376,17 +385,17 @@ impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationSt | ||
376 | 385 | impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationState<O, D> |
377 | 386 | for AuthenticatedInstance |
378 | 387 | { |
379 | type Error = (); | |
388 | type Error = MissingValue; | |
380 | 389 | |
381 | 390 | async fn from_state( |
382 | 391 | _object: &O, |
383 | 392 | _operation: &D, |
384 | 393 | state: &StackOperationState, |
385 | ) -> Result<AuthenticatedInstance, OperationError<()>> { | |
394 | ) -> Result<AuthenticatedInstance, ExtractorError<MissingValue>> { | |
386 | 395 | state |
387 | 396 | .instance |
388 | 397 | .clone() |
389 | .ok_or_else(|| OperationError::Operation(())) | |
398 | .ok_or_else(|| ExtractorError(MissingValue)) | |
390 | 399 | } |
391 | 400 | } |
392 | 401 | |
@@ -397,13 +406,13 @@ impl< | ||
397 | 406 | D: GiteratedOperation<O> + Send + Sync, |
398 | 407 | > FromOperationState<O, D> for Option<T> |
399 | 408 | { |
400 | type Error = (); | |
409 | type Error = Infallible; | |
401 | 410 | |
402 | 411 | async fn from_state( |
403 | 412 | object: &O, |
404 | 413 | operation: &D, |
405 | 414 | state: &StackOperationState, |
406 | ) -> Result<Option<T>, OperationError<()>> { | |
415 | ) -> Result<Option<T>, ExtractorError<Infallible>> { | |
407 | 416 | Ok(T::from_state(object, operation, state).await.ok()) |
408 | 417 | } |
409 | 418 | } |
@@ -416,20 +425,24 @@ pub struct AuthorizedInstance(AuthenticatedInstance); | ||
416 | 425 | |
417 | 426 | #[async_trait::async_trait(?Send)] |
418 | 427 | pub trait AuthorizedOperation<O: GiteratedObject>: GiteratedOperation<O> { |
428 | type Error: Into<anyhow::Error>; | |
429 | ||
419 | 430 | async fn authorize( |
420 | 431 | &self, |
421 | 432 | authorize_for: &O, |
422 | 433 | state: &StackOperationState, |
423 | ) -> Result<bool, OperationError<()>>; | |
434 | ) -> Result<bool, ExtractorError<Self::Error>>; | |
424 | 435 | } |
425 | 436 | |
426 | 437 | #[async_trait::async_trait(?Send)] |
427 | 438 | impl<O: GiteratedObject + Send + Sync + Debug + 'static> AuthorizedOperation<O> for GetValue { |
439 | type Error = anyhow::Error; | |
440 | ||
428 | 441 | async fn authorize( |
429 | 442 | &self, |
430 | 443 | authorize_for: &O, |
431 | 444 | operation_state: &StackOperationState, |
432 | ) -> Result<bool, OperationError<()>> { | |
445 | ) -> Result<bool, ExtractorError<anyhow::Error>> { | |
433 | 446 | Ok(operation_state |
434 | 447 | .runtime |
435 | 448 | .get_object::<O>(&authorize_for.to_string(), operation_state) |
@@ -440,15 +453,14 @@ impl<O: GiteratedObject + Send + Sync + Debug + 'static> AuthorizedOperation<O> | ||
440 | 453 | |
441 | 454 | #[async_trait::async_trait(?Send)] |
442 | 455 | impl AuthorizedOperation<User> for SetSetting { |
456 | type Error = MissingValue; | |
457 | ||
443 | 458 | async fn authorize( |
444 | 459 | &self, |
445 | 460 | authorize_for: &User, |
446 | 461 | operation_state: &StackOperationState, |
447 | ) -> Result<bool, OperationError<()>> { | |
448 | let authenticated_user = operation_state | |
449 | .user | |
450 | .as_ref() | |
451 | .ok_or_else(|| OperationError::Operation(()))?; | |
462 | ) -> Result<bool, ExtractorError<MissingValue>> { | |
463 | let authenticated_user = operation_state.user.as_ref().ok_or_else(|| MissingValue)?; | |
452 | 464 | |
453 | 465 | Ok(authorize_for == authenticated_user.deref()) |
454 | 466 | } |
@@ -456,15 +468,14 @@ impl AuthorizedOperation<User> for SetSetting { | ||
456 | 468 | |
457 | 469 | #[async_trait::async_trait(?Send)] |
458 | 470 | impl AuthorizedOperation<User> for GetSetting { |
471 | type Error = MissingValue; | |
472 | ||
459 | 473 | async fn authorize( |
460 | 474 | &self, |
461 | 475 | authorize_for: &User, |
462 | 476 | operation_state: &StackOperationState, |
463 | ) -> Result<bool, OperationError<()>> { | |
464 | let authenticated_user = operation_state | |
465 | .user | |
466 | .as_ref() | |
467 | .ok_or_else(|| OperationError::Operation(()))?; | |
477 | ) -> Result<bool, ExtractorError<MissingValue>> { | |
478 | let authenticated_user = operation_state.user.as_ref().ok_or_else(|| MissingValue)?; | |
468 | 479 | |
469 | 480 | Ok(authorize_for == authenticated_user.deref()) |
470 | 481 | } |
@@ -472,26 +483,28 @@ impl AuthorizedOperation<User> for GetSetting { | ||
472 | 483 | |
473 | 484 | #[async_trait::async_trait(?Send)] |
474 | 485 | impl AuthorizedOperation<Repository> for SetSetting { |
486 | type Error = anyhow::Error; | |
487 | ||
475 | 488 | async fn authorize( |
476 | 489 | &self, |
477 | 490 | authorize_for: &Repository, |
478 | 491 | operation_state: &StackOperationState, |
479 | ) -> Result<bool, OperationError<()>> { | |
492 | ) -> Result<bool, ExtractorError<anyhow::Error>> { | |
480 | 493 | let authenticated_user = operation_state |
481 | 494 | .user |
482 | 495 | .as_ref() |
483 | .ok_or_else(|| OperationError::Operation(()))?; | |
496 | .ok_or_else(|| anyhow::Error::from(MissingValue))?; | |
484 | 497 | |
485 | 498 | let mut object = operation_state |
486 | 499 | .runtime |
487 | 500 | .get_object::<Repository>(&authorize_for.to_string(), operation_state) |
488 | 501 | .await |
489 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
502 | .map_err(|err| anyhow::Error::from(err))?; | |
490 | 503 | |
491 | 504 | let access_list = object |
492 | 505 | .get_setting::<AccessList>(operation_state) |
493 | 506 | .await |
494 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
507 | .map_err(|err| anyhow::Error::from(err))?; | |
495 | 508 | |
496 | 509 | if access_list |
497 | 510 | .0 |
@@ -508,26 +521,28 @@ impl AuthorizedOperation<Repository> for SetSetting { | ||
508 | 521 | |
509 | 522 | #[async_trait::async_trait(?Send)] |
510 | 523 | impl AuthorizedOperation<Repository> for GetSetting { |
524 | type Error = anyhow::Error; | |
525 | ||
511 | 526 | async fn authorize( |
512 | 527 | &self, |
513 | 528 | authorize_for: &Repository, |
514 | 529 | operation_state: &StackOperationState, |
515 | ) -> Result<bool, OperationError<()>> { | |
530 | ) -> Result<bool, ExtractorError<anyhow::Error>> { | |
516 | 531 | let authenticated_user = operation_state |
517 | 532 | .user |
518 | 533 | .as_ref() |
519 | .ok_or_else(|| OperationError::Operation(()))?; | |
534 | .ok_or_else(|| anyhow::Error::from(MissingValue))?; | |
520 | 535 | |
521 | 536 | let mut object = operation_state |
522 | 537 | .runtime |
523 | 538 | .get_object::<Repository>(&authorize_for.to_string(), operation_state) |
524 | 539 | .await |
525 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
540 | .map_err(|err| anyhow::Error::from(err))?; | |
526 | 541 | |
527 | 542 | let access_list = object |
528 | 543 | .get_setting::<AccessList>(operation_state) |
529 | 544 | .await |
530 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
545 | .map_err(|err| anyhow::Error::from(err))?; | |
531 | 546 | |
532 | 547 | if access_list |
533 | 548 | .0 |
@@ -544,11 +559,13 @@ impl AuthorizedOperation<Repository> for GetSetting { | ||
544 | 559 | |
545 | 560 | #[async_trait::async_trait(?Send)] |
546 | 561 | impl AuthorizedOperation<Instance> for RegisterAccountRequest { |
562 | type Error = Infallible; | |
563 | ||
547 | 564 | async fn authorize( |
548 | 565 | &self, |
549 | 566 | authorize_for: &Instance, |
550 | 567 | state: &StackOperationState, |
551 | ) -> Result<bool, OperationError<()>> { | |
568 | ) -> Result<bool, ExtractorError<Infallible>> { | |
552 | 569 | if state.our_instance == *authorize_for { |
553 | 570 | Ok(true) |
554 | 571 | } else { |
@@ -559,11 +576,13 @@ impl AuthorizedOperation<Instance> for RegisterAccountRequest { | ||
559 | 576 | |
560 | 577 | #[async_trait::async_trait(?Send)] |
561 | 578 | impl AuthorizedOperation<Instance> for AuthenticationTokenRequest { |
579 | type Error = Infallible; | |
580 | ||
562 | 581 | async fn authorize( |
563 | 582 | &self, |
564 | 583 | authorize_for: &Instance, |
565 | 584 | state: &StackOperationState, |
566 | ) -> Result<bool, OperationError<()>> { | |
585 | ) -> Result<bool, ExtractorError<Infallible>> { | |
567 | 586 | if state.our_instance == *authorize_for { |
568 | 587 | Ok(true) |
569 | 588 | } else { |
@@ -574,11 +593,13 @@ impl AuthorizedOperation<Instance> for AuthenticationTokenRequest { | ||
574 | 593 | |
575 | 594 | #[async_trait::async_trait(?Send)] |
576 | 595 | impl AuthorizedOperation<Instance> for RepositoryCreateRequest { |
596 | type Error = Infallible; | |
597 | ||
577 | 598 | async fn authorize( |
578 | 599 | &self, |
579 | 600 | authorize_for: &Instance, |
580 | 601 | state: &StackOperationState, |
581 | ) -> Result<bool, OperationError<()>> { | |
602 | ) -> Result<bool, ExtractorError<Infallible>> { | |
582 | 603 | if state.our_instance == *authorize_for { |
583 | 604 | Ok(true) |
584 | 605 | } else { |
@@ -589,20 +610,23 @@ impl AuthorizedOperation<Instance> for RepositoryCreateRequest { | ||
589 | 610 | |
590 | 611 | #[async_trait::async_trait(?Send)] |
591 | 612 | impl<A: AuthorizedOperation<User> + Send + Sync> FromOperationState<User, A> for AuthorizedUser { |
592 | type Error = (); | |
613 | type Error = UnauthorizedError; | |
593 | 614 | |
594 | 615 | async fn from_state( |
595 | 616 | object: &User, |
596 | 617 | operation: &A, |
597 | 618 | state: &StackOperationState, |
598 | ) -> Result<AuthorizedUser, OperationError<()>> { | |
599 | let authenticated = AuthenticatedUser::from_state(object, operation, state).await?; | |
619 | ) -> Result<AuthorizedUser, ExtractorError<UnauthorizedError>> { | |
620 | // TODO | |
621 | let authenticated = AuthenticatedUser::from_state(object, operation, state) | |
622 | .await | |
623 | .map_err(|_| ExtractorError(UnauthorizedError))?; | |
600 | 624 | |
601 | 625 | match operation.authorize(object, state).await { |
602 | 626 | Ok(authorized) => { |
603 | 627 | assert!(authorized); |
604 | 628 | } |
605 | Err(err) => return Err(OperationError::Internal(err.to_string())), | |
629 | Err(_err) => return Err(ExtractorError(UnauthorizedError)), | |
606 | 630 | }; |
607 | 631 | |
608 | 632 | Ok(AuthorizedUser(authenticated)) |
@@ -613,20 +637,23 @@ impl<A: AuthorizedOperation<User> + Send + Sync> FromOperationState<User, A> for | ||
613 | 637 | impl<A: AuthorizedOperation<Instance> + Send + Sync> FromOperationState<Instance, A> |
614 | 638 | for AuthorizedInstance |
615 | 639 | { |
616 | type Error = (); | |
640 | type Error = UnauthorizedError; | |
617 | 641 | |
618 | 642 | async fn from_state( |
619 | 643 | object: &Instance, |
620 | 644 | operation: &A, |
621 | 645 | state: &StackOperationState, |
622 | ) -> Result<AuthorizedInstance, OperationError<()>> { | |
623 | let authenticated = AuthenticatedInstance::from_state(object, operation, state).await?; | |
646 | ) -> Result<AuthorizedInstance, ExtractorError<UnauthorizedError>> { | |
647 | //TODO | |
648 | let authenticated = AuthenticatedInstance::from_state(object, operation, state) | |
649 | .await | |
650 | .map_err(|_| ExtractorError(UnauthorizedError))?; | |
624 | 651 | |
625 | 652 | match operation.authorize(object, state).await { |
626 | 653 | Ok(authorized) => { |
627 | 654 | assert!(authorized); |
628 | 655 | } |
629 | Err(err) => return Err(OperationError::Internal(err.to_string())), | |
656 | Err(_err) => return Err(ExtractorError(UnauthorizedError)), | |
630 | 657 | }; |
631 | 658 | |
632 | 659 | Ok(AuthorizedInstance(authenticated)) |