|
1 | 1 | use crate::{
|
2 | 2 | db,
|
3 |
| - swap_protocols::rfc003::{self, actions::ActionKind, state_store}, |
| 3 | + http_api::routes::rfc003::handlers::{ |
| 4 | + post_swap::{MalformedRequest, UnsupportedSwap}, |
| 5 | + InvalidAction, InvalidActionInvocation, |
| 6 | + }, |
4 | 7 | };
|
5 | 8 | use http::StatusCode;
|
6 | 9 | use http_api_problem::HttpApiProblem;
|
7 |
| -use libp2p_comit::frame::Response; |
8 |
| -use serde::Serialize; |
9 | 10 | use warp::{Rejection, Reply};
|
10 | 11 |
|
11 |
| -#[derive(Debug, Serialize)] |
| 12 | +#[derive(Debug, thiserror::Error)] |
| 13 | +#[error("Missing GET parameters for a {} action type. Expected: {:?}", action, parameters.iter().map(|parameter| parameter.name).collect::<Vec<&str>>())] |
| 14 | +pub struct MissingQueryParameters { |
| 15 | + pub action: &'static str, |
| 16 | + pub parameters: &'static [MissingQueryParameter], |
| 17 | +} |
| 18 | + |
| 19 | +#[derive(Debug, serde::Serialize)] |
12 | 20 | pub struct MissingQueryParameter {
|
13 | 21 | pub name: &'static str,
|
14 | 22 | pub data_type: &'static str,
|
15 | 23 | pub description: &'static str,
|
16 | 24 | }
|
17 | 25 |
|
| 26 | +#[derive(Debug, thiserror::Error)] |
| 27 | +#[error("unexpected GET parameters {parameters:?} for a {action} action type, expected: none")] |
| 28 | +pub struct UnexpectedQueryParameters { |
| 29 | + pub action: &'static str, |
| 30 | + pub parameters: &'static [&'static str], |
| 31 | +} |
| 32 | + |
18 | 33 | pub fn from_anyhow(e: anyhow::Error) -> HttpApiProblem {
|
| 34 | + let e = match e.downcast::<HttpApiProblem>() { |
| 35 | + Ok(problem) => return problem, |
| 36 | + Err(e) => e, |
| 37 | + }; |
| 38 | + |
19 | 39 | if let Some(db::Error::SwapNotFound) = e.downcast_ref::<db::Error>() {
|
20 |
| - return swap_not_found(); |
| 40 | + return HttpApiProblem::new("Swap not found.").set_status(StatusCode::NOT_FOUND); |
21 | 41 | }
|
22 | 42 |
|
23 |
| - internal_error(e) |
24 |
| -} |
| 43 | + if let Some(e) = e.downcast_ref::<UnexpectedQueryParameters>() { |
| 44 | + log::error!("{}", e); |
25 | 45 |
|
26 |
| -pub fn internal_error(e: anyhow::Error) -> HttpApiProblem { |
27 |
| - log::error!("internal error occurred: {:?}", e); |
28 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
29 |
| -} |
| 46 | + let mut problem = HttpApiProblem::new("Unexpected query parameter(s).") |
| 47 | + .set_status(StatusCode::BAD_REQUEST) |
| 48 | + .set_detail("This action does not take any query parameters."); |
30 | 49 |
|
31 |
| -pub fn missing_channel() -> HttpApiProblem { |
32 |
| - log::error!("Channel for swap was not found in hash map"); |
33 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
34 |
| -} |
| 50 | + problem |
| 51 | + .set_value("unexpected_parameters", &e.parameters) |
| 52 | + .expect("parameters will never fail to serialize"); |
35 | 53 |
|
36 |
| -pub fn send_over_channel(_e: Response) -> HttpApiProblem { |
37 |
| - log::error!("Sending response over channel failed"); |
38 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
39 |
| -} |
| 54 | + return problem; |
| 55 | + } |
40 | 56 |
|
41 |
| -pub fn state_store() -> HttpApiProblem { |
42 |
| - log::error!("State store didn't have state in it despite swap being in database"); |
43 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
44 |
| -} |
| 57 | + if let Some(e) = e.downcast_ref::<MissingQueryParameters>() { |
| 58 | + log::error!("{}", e); |
45 | 59 |
|
46 |
| -pub fn swap_not_found() -> HttpApiProblem { |
47 |
| - HttpApiProblem::new("Swap not found.").set_status(StatusCode::NOT_FOUND) |
48 |
| -} |
| 60 | + let mut problem = HttpApiProblem::new("Missing query parameter(s).") |
| 61 | + .set_status(StatusCode::BAD_REQUEST) |
| 62 | + .set_detail("This action requires additional query parameters."); |
49 | 63 |
|
50 |
| -pub fn unsupported() -> HttpApiProblem { |
51 |
| - HttpApiProblem::new("Swap not supported.") |
52 |
| - .set_status(StatusCode::BAD_REQUEST) |
53 |
| - .set_detail("The requested combination of ledgers and assets is not supported.") |
54 |
| -} |
| 64 | + problem |
| 65 | + .set_value("missing_parameters", &e.parameters) |
| 66 | + .expect("parameters will never fail to serialize"); |
55 | 67 |
|
56 |
| -pub fn deserialize(e: serde_json::Error) -> HttpApiProblem { |
57 |
| - log::error!("Failed to deserialize body: {:?}", e); |
58 |
| - HttpApiProblem::new("Invalid body.") |
59 |
| - .set_status(StatusCode::BAD_REQUEST) |
60 |
| - .set_detail("Failed to deserialize given body.") |
61 |
| -} |
| 68 | + return problem; |
| 69 | + } |
62 | 70 |
|
63 |
| -pub fn serialize(e: serde_json::Error) -> HttpApiProblem { |
64 |
| - log::error!("Failed to serialize body: {:?}", e); |
65 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
66 |
| -} |
| 71 | + if e.is::<serde_json::Error>() { |
| 72 | + log::error!("deserialization error: {:?}", e); |
67 | 73 |
|
68 |
| -pub fn not_yet_implemented(feature: &str) -> HttpApiProblem { |
69 |
| - log::error!("{} not yet implemented", feature); |
70 |
| - HttpApiProblem::new("Feature not yet implemented.") |
71 |
| - .set_status(StatusCode::INTERNAL_SERVER_ERROR) |
72 |
| - .set_detail(format!("{} is not yet implemented! Sorry :(", feature)) |
73 |
| -} |
| 74 | + return HttpApiProblem::new("Invalid body.") |
| 75 | + .set_status(StatusCode::BAD_REQUEST) |
| 76 | + .set_detail("Failed to deserialize given body."); |
| 77 | + } |
74 | 78 |
|
75 |
| -pub fn action_already_done(action: ActionKind) -> HttpApiProblem { |
76 |
| - log::error!("{} action has already been done", action); |
77 |
| - HttpApiProblem::new("Action already done.").set_status(StatusCode::GONE) |
78 |
| -} |
| 79 | + if e.is::<InvalidActionInvocation>() { |
| 80 | + log::warn!("{:?}", e); |
79 | 81 |
|
80 |
| -pub fn invalid_action(action: ActionKind) -> HttpApiProblem { |
81 |
| - log::error!("{} action is invalid for this swap", action); |
82 |
| - HttpApiProblem::new("Invalid action.") |
83 |
| - .set_status(StatusCode::CONFLICT) |
84 |
| - .set_detail("Cannot perform requested action for this swap.") |
85 |
| -} |
| 82 | + return HttpApiProblem::new("Invalid action invocation") |
| 83 | + .set_status(http::StatusCode::METHOD_NOT_ALLOWED); |
| 84 | + } |
86 | 85 |
|
87 |
| -pub fn unexpected_query_parameters(action: &str, parameters: Vec<String>) -> HttpApiProblem { |
88 |
| - log::error!( |
89 |
| - "Unexpected GET parameters {:?} for a {} action type. Expected: none", |
90 |
| - parameters, |
91 |
| - action |
92 |
| - ); |
93 |
| - let mut problem = HttpApiProblem::new("Unexpected query parameter(s).") |
94 |
| - .set_status(StatusCode::BAD_REQUEST) |
95 |
| - .set_detail("This action does not take any query parameters."); |
96 |
| - |
97 |
| - problem |
98 |
| - .set_value("unexpected_parameters", ¶meters) |
99 |
| - .expect("parameters will never fail to serialize"); |
100 |
| - |
101 |
| - problem |
102 |
| -} |
| 86 | + if e.is::<InvalidAction>() { |
| 87 | + log::warn!("{:?}", e); |
103 | 88 |
|
104 |
| -pub fn missing_query_parameters( |
105 |
| - action: &str, |
106 |
| - parameters: Vec<&MissingQueryParameter>, |
107 |
| -) -> HttpApiProblem { |
108 |
| - log::error!( |
109 |
| - "Missing GET parameters for a {} action type. Expected: {:?}", |
110 |
| - action, |
111 |
| - parameters |
112 |
| - .iter() |
113 |
| - .map(|parameter| parameter.name) |
114 |
| - .collect::<Vec<&str>>() |
115 |
| - ); |
116 |
| - |
117 |
| - let mut problem = HttpApiProblem::new("Missing query parameter(s).") |
118 |
| - .set_status(StatusCode::BAD_REQUEST) |
119 |
| - .set_detail("This action requires additional query parameters."); |
120 |
| - |
121 |
| - problem |
122 |
| - .set_value("missing_parameters", ¶meters) |
123 |
| - .expect("parameters will never fail to serialize"); |
124 |
| - |
125 |
| - problem |
126 |
| -} |
| 89 | + return HttpApiProblem::new("Invalid action.") |
| 90 | + .set_status(StatusCode::CONFLICT) |
| 91 | + .set_detail("Cannot perform requested action for this swap."); |
| 92 | + } |
| 93 | + |
| 94 | + if e.is::<UnsupportedSwap>() { |
| 95 | + log::warn!("{:?}", e); |
127 | 96 |
|
128 |
| -impl From<state_store::Error> for HttpApiProblem { |
129 |
| - fn from(e: state_store::Error) -> Self { |
130 |
| - log::error!("Storage layer failure: {:?}", e); |
131 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
| 97 | + return HttpApiProblem::new("Swap not supported.") |
| 98 | + .set_status(StatusCode::BAD_REQUEST) |
| 99 | + .set_detail("The requested combination of ledgers and assets is not supported."); |
132 | 100 | }
|
133 |
| -} |
134 | 101 |
|
135 |
| -impl From<rfc003::state_machine::Error> for HttpApiProblem { |
136 |
| - fn from(e: rfc003::state_machine::Error) -> Self { |
137 |
| - log::error!("Protocol execution error: {:?}", e); |
138 |
| - HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
139 |
| - .set_title("Protocol execution error.") |
| 102 | + if e.is::<MalformedRequest>() { |
| 103 | + log::warn!("{:?}", e); |
| 104 | + |
| 105 | + return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST) |
| 106 | + .set_detail("The request body was malformed."); |
140 | 107 | }
|
| 108 | + |
| 109 | + log::error!("internal error occurred: {:?}", e); |
| 110 | + |
| 111 | + HttpApiProblem::with_title_and_type_from_status(StatusCode::INTERNAL_SERVER_ERROR) |
141 | 112 | }
|
142 | 113 |
|
143 | 114 | pub fn unpack_problem(rejection: Rejection) -> Result<impl Reply, Rejection> {
|
144 | 115 | if let Some(problem) = rejection.find_cause::<HttpApiProblem>() {
|
145 |
| - log::debug!(target: "http-api", "HTTP request got rejected, returning HttpApiProblem response: {:?}", problem); |
146 |
| - |
147 | 116 | let code = problem.status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
|
148 | 117 |
|
149 | 118 | let reply = warp::reply::json(problem);
|
|
0 commit comments