api_params.rs (3847B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024, 2025, 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use serde::Deserialize; 18 use serde_with::{DisplayFromStr, serde_as}; 19 20 use crate::{api_wire::TransferState, types::payto::PaytoURI}; 21 22 #[derive(Debug, thiserror::Error)] 23 #[error("Param '{param}' {reason}")] 24 pub struct ParamsErr { 25 pub param: &'static str, 26 pub reason: String, 27 } 28 29 pub fn param_err(param: &'static str, reason: String) -> ParamsErr { 30 ParamsErr { param, reason } 31 } 32 33 #[serde_as] 34 #[derive(Debug, Clone, Deserialize)] 35 /// <https://docs.taler.net/core/api-common.html#row-id-pagination> 36 pub struct PageParams { 37 #[serde_as(as = "Option<DisplayFromStr>")] 38 #[serde(alias = "delta")] 39 pub limit: Option<i64>, 40 #[serde_as(as = "Option<DisplayFromStr>")] 41 #[serde(alias = "start")] 42 pub offset: Option<i64>, 43 } 44 45 impl PageParams { 46 const MAX_PAGE_SIZE: i64 = 1024; 47 48 pub fn check(self) -> Result<Page, ParamsErr> { 49 Self::check_custom(self, Self::MAX_PAGE_SIZE) 50 } 51 52 pub fn check_custom(self, max_page_size: i64) -> Result<Page, ParamsErr> { 53 let limit = self.limit.unwrap_or(-20); 54 if limit == 0 { 55 return Err(param_err("limit", format!("must be non-zero got {limit}"))); 56 } else if limit > max_page_size { 57 return Err(param_err( 58 "limit", 59 format!("must be <= {max_page_size} for {limit}"), 60 )); 61 } 62 if let Some(offset) = self.offset 63 && offset < 0 64 { 65 return Err(param_err( 66 "offset", 67 format!("must be positive got {offset}"), 68 )); 69 } 70 71 Ok(Page { 72 limit, 73 offset: self.offset, 74 }) 75 } 76 } 77 78 #[derive(Debug)] 79 pub struct Page { 80 pub limit: i64, 81 pub offset: Option<i64>, 82 } 83 84 impl Default for Page { 85 fn default() -> Self { 86 Self { 87 limit: 20, 88 offset: None, 89 } 90 } 91 } 92 93 impl Page { 94 pub fn backward(&self) -> bool { 95 self.limit < 0 96 } 97 } 98 99 #[derive(Debug, Clone, Deserialize)] 100 /// <https://docs.taler.net/core/api-common.html#long-polling> 101 pub struct HistoryParams { 102 #[serde(flatten)] 103 pub pagination: PageParams, 104 #[serde(alias = "long_poll_ms")] 105 pub timeout_ms: Option<u64>, 106 } 107 108 impl HistoryParams { 109 pub const MAX_TIMEOUT_MS: u64 = 60 * 60 * 10; // 1H 110 111 pub fn check(self) -> Result<History, ParamsErr> { 112 Self::check_custom(self, PageParams::MAX_PAGE_SIZE, Self::MAX_TIMEOUT_MS) 113 } 114 115 pub fn check_custom( 116 self, 117 max_page_size: i64, 118 max_timeout_ms: u64, 119 ) -> Result<History, ParamsErr> { 120 let timeout_ms = self.timeout_ms.map(|it| it.min(max_timeout_ms)); 121 Ok(History { 122 page: self.pagination.check_custom(max_page_size)?, 123 timeout_ms, 124 }) 125 } 126 } 127 128 #[derive(Debug, Default)] 129 pub struct History { 130 pub page: Page, 131 pub timeout_ms: Option<u64>, 132 } 133 134 #[derive(Debug, Clone, Deserialize)] 135 pub struct TransferParams { 136 #[serde(flatten)] 137 pub pagination: PageParams, 138 pub status: Option<TransferState>, 139 } 140 141 #[derive(Debug, Clone, Deserialize)] 142 pub struct AccountParams { 143 pub account: PaytoURI, 144 }