taler-rust

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

params.rs (4555B)


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