taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

api_params.rs (4465B)


      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 #[serde_as]
    100 #[derive(Debug, Clone, Deserialize)]
    101 /// <https://docs.taler.net/core/api-common.html#long-polling>
    102 pub struct PoolingParams {
    103     #[serde_as(as = "Option<DisplayFromStr>")]
    104     #[serde(alias = "long_poll_ms")]
    105     pub timeout_ms: Option<u64>,
    106 }
    107 
    108 #[derive(Debug, Default)]
    109 pub struct Pooling {
    110     pub timeout_ms: Option<u64>,
    111 }
    112 
    113 impl PoolingParams {
    114     pub const MAX_TIMEOUT_MS: u64 = 60 * 60 * 10; // 1H
    115 
    116     pub fn check(self) -> Result<Pooling, ParamsErr> {
    117         Self::check_custom(self, Self::MAX_TIMEOUT_MS)
    118     }
    119 
    120     pub fn check_custom(self, max_timeout_ms: u64) -> Result<Pooling, ParamsErr> {
    121         let timeout_ms = self.timeout_ms.map(|it| it.min(max_timeout_ms));
    122         Ok(Pooling { timeout_ms })
    123     }
    124 }
    125 
    126 #[derive(Debug, Clone, Deserialize)]
    127 pub struct HistoryParams {
    128     #[serde(flatten)]
    129     pub pagination: PageParams,
    130     #[serde(flatten)]
    131     pub pooling: PoolingParams,
    132 }
    133 
    134 impl HistoryParams {
    135     pub fn check(self) -> Result<History, ParamsErr> {
    136         Self::check_custom(
    137             self,
    138             PageParams::MAX_PAGE_SIZE,
    139             PoolingParams::MAX_TIMEOUT_MS,
    140         )
    141     }
    142 
    143     pub fn check_custom(
    144         self,
    145         max_page_size: i64,
    146         max_timeout_ms: u64,
    147     ) -> Result<History, ParamsErr> {
    148         Ok(History {
    149             page: self.pagination.check_custom(max_page_size)?,
    150             pooling: self.pooling.check_custom(max_timeout_ms)?,
    151         })
    152     }
    153 }
    154 
    155 #[derive(Debug, Default)]
    156 pub struct History {
    157     pub page: Page,
    158     pub pooling: Pooling,
    159 }
    160 
    161 #[derive(Debug, Clone, Deserialize)]
    162 pub struct TransferParams {
    163     #[serde(flatten)]
    164     pub pagination: PageParams,
    165     pub status: Option<TransferState>,
    166 }
    167 
    168 #[derive(Debug, Clone, Deserialize)]
    169 pub struct AccountParams {
    170     pub account: PaytoURI,
    171 }