taler-rust

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

client.rs (4204B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 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 std::borrow::Cow;
     18 
     19 use http_client::sse::SseClient;
     20 use hyper::Method;
     21 use jiff::Timestamp;
     22 use serde_json::json;
     23 use taler_common::types::amount::Decimal;
     24 use url::Url;
     25 
     26 use crate::cyclos_api::{
     27     api::{ApiResult, CyclosAuth, CyclosRequest},
     28     types::{
     29         Account, DataForTransaction, DataForUi, HistoryItem, OrderBy, Pagination, Transaction,
     30         Transfer, User,
     31     },
     32 };
     33 
     34 pub struct Client<'a> {
     35     pub client: &'a http_client::Client,
     36     pub api_url: &'a Url,
     37     pub auth: &'a CyclosAuth,
     38 }
     39 
     40 impl Client<'_> {
     41     fn request(&self, method: Method, path: impl Into<Cow<'static, str>>) -> CyclosRequest<'_> {
     42         CyclosRequest::new(self.client, method, self.api_url, path, self.auth)
     43     }
     44 
     45     pub async fn data_for_ui(&self) -> ApiResult<DataForUi> {
     46         self.request(Method::GET, "ui/data-for-ui")
     47             .parse_json()
     48             .await
     49     }
     50 
     51     pub async fn whoami(&self) -> ApiResult<User> {
     52         self.request(Method::GET, "users/self").parse_json().await
     53     }
     54 
     55     pub async fn accounts(&self) -> ApiResult<Vec<Account>> {
     56         self.request(Method::GET, "self/accounts")
     57             .parse_json()
     58             .await
     59     }
     60 
     61     pub async fn balance(&self, account_type_id: i64) -> ApiResult<Account> {
     62         self.request(Method::GET, format!("self/accounts/{account_type_id}"))
     63             .parse_json()
     64             .await
     65     }
     66 
     67     pub async fn payment_data(&self) -> ApiResult<DataForTransaction> {
     68         self.request(Method::GET, "self/payments/data-for-perform")
     69             .parse_json()
     70             .await
     71     }
     72 
     73     pub async fn direct_payment(
     74         &self,
     75         creditor: i64,
     76         payment_type_id: i64,
     77         amount: Decimal,
     78         description: &str,
     79     ) -> ApiResult<Transaction> {
     80         self.request(Method::POST, "self/payments")
     81             .json(&json!({
     82                 "description": description,
     83                 "scheduling": "direct",
     84                 "subject": creditor,
     85                 "type": payment_type_id,
     86                 "amount": amount
     87             }))
     88             .parse_json()
     89             .await
     90     }
     91 
     92     pub async fn chargeback(&self, transfer_id: i64) -> ApiResult<i64> {
     93         self.request(Method::POST, format!("transfers/{transfer_id}/chargeback"))
     94             .parse_json()
     95             .await
     96     }
     97 
     98     pub async fn history(
     99         &self,
    100         account_type_id: i64,
    101         order_by: OrderBy,
    102         page: u64,
    103         since: Option<Timestamp>,
    104     ) -> ApiResult<Pagination<Vec<HistoryItem>>> {
    105         let mut req = self
    106             .request(
    107                 Method::GET,
    108                 format!("self/accounts/{account_type_id}/history"),
    109             )
    110             .query("orderBy", order_by)
    111             .query("skipTotalCount", false)
    112             .query("page", page);
    113         if let Some(since) = since {
    114             req = req.query("datePeriod", since)
    115         }
    116         req.query("begin", since).parse_pagination().await
    117     }
    118 
    119     pub async fn transfer(&self, transfer_id: i64) -> ApiResult<Transfer> {
    120         self.request(Method::GET, format!("transfers/{transfer_id}"))
    121             .parse_json()
    122             .await
    123     }
    124 
    125     pub async fn push_notifications(
    126         &self,
    127         client_id: i64,
    128         sse_client: &mut SseClient,
    129     ) -> ApiResult<()> {
    130         self.request(Method::GET, "push/subscribe")
    131             .query("clientId", client_id)
    132             .query("kinds", "newNotification")
    133             .into_sse(sse_client)
    134             .await
    135     }
    136 }