router_handlers.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. use anyhow::Result;
  2. use axum::extract::{Json, Path, State};
  3. use axum::http::StatusCode;
  4. use axum::response::{IntoResponse, Response};
  5. use cdk::error::ErrorResponse;
  6. use cdk::nuts::{
  7. CheckStateRequest, CheckStateResponse, Id, KeysResponse, KeysetResponse, MeltBolt11Request,
  8. MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request, MintBolt11Response,
  9. MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, RestoreRequest, RestoreResponse,
  10. SwapRequest, SwapResponse,
  11. };
  12. use cdk::util::unix_time;
  13. use cdk::Error;
  14. use paste::paste;
  15. use crate::MintState;
  16. macro_rules! post_cache_wrapper {
  17. ($handler:ident, $request_type:ty, $response_type:ty) => {
  18. paste! {
  19. /// Cache wrapper function for $handler:
  20. /// Wrap $handler into a function that caches responses using the request as key
  21. pub async fn [<cache_ $handler>](
  22. state: State<MintState>,
  23. payload: Json<$request_type>
  24. ) -> Result<Json<$response_type>, Response> {
  25. let Json(json_extracted_payload) = payload.clone();
  26. let State(mint_state) = state.clone();
  27. let cache_key = serde_json::to_string(&json_extracted_payload).map_err(|err| {
  28. into_response(Error::from(err))
  29. })?;
  30. if let Some(cached_response) = mint_state.cache.get(&cache_key) {
  31. return Ok(Json(serde_json::from_str(&cached_response)
  32. .expect("Shouldn't panic: response is json-deserializable.")));
  33. }
  34. let Json(response) = $handler(state, payload).await?;
  35. mint_state.cache.insert(cache_key, serde_json::to_string(&response)
  36. .expect("Shouldn't panic: response is json-serializable.")
  37. ).await;
  38. Ok(Json(response))
  39. }
  40. }
  41. };
  42. }
  43. post_cache_wrapper!(post_swap, SwapRequest, SwapResponse);
  44. post_cache_wrapper!(post_mint_bolt11, MintBolt11Request, MintBolt11Response);
  45. post_cache_wrapper!(post_melt_bolt11, MeltBolt11Request, MeltQuoteBolt11Response);
  46. pub async fn get_keys(State(state): State<MintState>) -> Result<Json<KeysResponse>, Response> {
  47. let pubkeys = state.mint.pubkeys().await.map_err(|err| {
  48. tracing::error!("Could not get keys: {}", err);
  49. into_response(err)
  50. })?;
  51. Ok(Json(pubkeys))
  52. }
  53. pub async fn get_keyset_pubkeys(
  54. State(state): State<MintState>,
  55. Path(keyset_id): Path<Id>,
  56. ) -> Result<Json<KeysResponse>, Response> {
  57. let pubkeys = state.mint.keyset_pubkeys(&keyset_id).await.map_err(|err| {
  58. tracing::error!("Could not get keyset pubkeys: {}", err);
  59. into_response(err)
  60. })?;
  61. Ok(Json(pubkeys))
  62. }
  63. pub async fn get_keysets(State(state): State<MintState>) -> Result<Json<KeysetResponse>, Response> {
  64. let mint = state.mint.keysets().await.map_err(|err| {
  65. tracing::error!("Could not get keyset: {}", err);
  66. into_response(err)
  67. })?;
  68. Ok(Json(mint))
  69. }
  70. pub async fn get_mint_bolt11_quote(
  71. State(state): State<MintState>,
  72. Json(payload): Json<MintQuoteBolt11Request>,
  73. ) -> Result<Json<MintQuoteBolt11Response>, Response> {
  74. let quote = state
  75. .mint
  76. .get_mint_bolt11_quote(payload)
  77. .await
  78. .map_err(into_response)?;
  79. Ok(Json(quote))
  80. }
  81. pub async fn get_check_mint_bolt11_quote(
  82. State(state): State<MintState>,
  83. Path(quote_id): Path<String>,
  84. ) -> Result<Json<MintQuoteBolt11Response>, Response> {
  85. let quote = state
  86. .mint
  87. .check_mint_quote(&quote_id)
  88. .await
  89. .map_err(|err| {
  90. tracing::error!("Could not check mint quote {}: {}", quote_id, err);
  91. into_response(err)
  92. })?;
  93. Ok(Json(quote))
  94. }
  95. pub async fn post_mint_bolt11(
  96. State(state): State<MintState>,
  97. Json(payload): Json<MintBolt11Request>,
  98. ) -> Result<Json<MintBolt11Response>, Response> {
  99. let res = state
  100. .mint
  101. .process_mint_request(payload)
  102. .await
  103. .map_err(|err| {
  104. tracing::error!("Could not process mint: {}", err);
  105. into_response(err)
  106. })?;
  107. Ok(Json(res))
  108. }
  109. pub async fn get_melt_bolt11_quote(
  110. State(state): State<MintState>,
  111. Json(payload): Json<MeltQuoteBolt11Request>,
  112. ) -> Result<Json<MeltQuoteBolt11Response>, Response> {
  113. let quote = state
  114. .mint
  115. .get_melt_bolt11_quote(&payload)
  116. .await
  117. .map_err(into_response)?;
  118. Ok(Json(quote))
  119. }
  120. pub async fn get_check_melt_bolt11_quote(
  121. State(state): State<MintState>,
  122. Path(quote_id): Path<String>,
  123. ) -> Result<Json<MeltQuoteBolt11Response>, Response> {
  124. let quote = state
  125. .mint
  126. .check_melt_quote(&quote_id)
  127. .await
  128. .map_err(|err| {
  129. tracing::error!("Could not check melt quote: {}", err);
  130. into_response(err)
  131. })?;
  132. Ok(Json(quote))
  133. }
  134. pub async fn post_melt_bolt11(
  135. State(state): State<MintState>,
  136. Json(payload): Json<MeltBolt11Request>,
  137. ) -> Result<Json<MeltQuoteBolt11Response>, Response> {
  138. let res = state
  139. .mint
  140. .melt_bolt11(&payload)
  141. .await
  142. .map_err(into_response)?;
  143. Ok(Json(res))
  144. }
  145. pub async fn post_check(
  146. State(state): State<MintState>,
  147. Json(payload): Json<CheckStateRequest>,
  148. ) -> Result<Json<CheckStateResponse>, Response> {
  149. let state = state.mint.check_state(&payload).await.map_err(|err| {
  150. tracing::error!("Could not check state of proofs");
  151. into_response(err)
  152. })?;
  153. Ok(Json(state))
  154. }
  155. pub async fn get_mint_info(State(state): State<MintState>) -> Result<Json<MintInfo>, Response> {
  156. Ok(Json(state.mint.mint_info().clone().time(unix_time())))
  157. }
  158. pub async fn post_swap(
  159. State(state): State<MintState>,
  160. Json(payload): Json<SwapRequest>,
  161. ) -> Result<Json<SwapResponse>, Response> {
  162. let swap_response = state
  163. .mint
  164. .process_swap_request(payload)
  165. .await
  166. .map_err(|err| {
  167. tracing::error!("Could not process swap request: {}", err);
  168. into_response(err)
  169. })?;
  170. Ok(Json(swap_response))
  171. }
  172. pub async fn post_restore(
  173. State(state): State<MintState>,
  174. Json(payload): Json<RestoreRequest>,
  175. ) -> Result<Json<RestoreResponse>, Response> {
  176. let restore_response = state.mint.restore(payload).await.map_err(|err| {
  177. tracing::error!("Could not process restore: {}", err);
  178. into_response(err)
  179. })?;
  180. Ok(Json(restore_response))
  181. }
  182. pub fn into_response<T>(error: T) -> Response
  183. where
  184. T: Into<ErrorResponse>,
  185. {
  186. (
  187. StatusCode::INTERNAL_SERVER_ERROR,
  188. Json::<ErrorResponse>(error.into()),
  189. )
  190. .into_response()
  191. }