taler-rust

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

lib.rs (3493B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 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, fmt::Display, str::Utf8Error};
     18 
     19 use http_body_util::Full;
     20 use hyper::{Method, StatusCode, body::Bytes};
     21 use hyper_rustls::ConfigBuilderExt as _;
     22 use hyper_util::rt::TokioExecutor;
     23 use taler_common::error::FmtSource;
     24 use thiserror::Error;
     25 
     26 use crate::headers::HeaderError;
     27 
     28 pub mod builder;
     29 pub mod headers;
     30 pub mod sse;
     31 
     32 pub type Client = hyper_util::client::legacy::Client<
     33     hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>,
     34     Full<Bytes>,
     35 >;
     36 
     37 #[derive(Error, Debug)]
     38 /// API call errors
     39 pub enum ClientErr {
     40     #[error("request: {0}")]
     41     Http(#[from] http::Error),
     42     #[error("request query: {0}")]
     43     Query(#[from] serde_urlencoded::ser::Error),
     44     #[error("request JSON body: {0}")]
     45     ReqJson(serde_path_to_error::Error<serde_json::Error>),
     46     #[error("request: {0}")]
     47     ReqTransport(FmtSource<hyper_util::client::legacy::Error>),
     48     #[error("response JSON body: {0}")]
     49     ResJson(serde_path_to_error::Error<serde_json::Error>),
     50     #[error("response txt body: {0}")]
     51     Text(#[from] Utf8Error),
     52     #[error("response form body: {0}")]
     53     Form(#[from] serde_urlencoded::de::Error),
     54     #[error("response headers: {0}")]
     55     Headers(#[from] HeaderError),
     56     #[error("response: {0}")]
     57     ResTransport(FmtSource<hyper::Error>),
     58 }
     59 
     60 pub fn client() -> anyhow::Result<Client> {
     61     rustls::crypto::aws_lc_rs::default_provider()
     62         .install_default()
     63         .expect("failed to install the default TLS provider");
     64 
     65     // Prepare the TLS client config
     66     let tls = rustls::ClientConfig::builder()
     67         .with_native_roots()?
     68         .with_no_client_auth();
     69 
     70     // Prepare the HTTPS connector
     71     let https = hyper_rustls::HttpsConnectorBuilder::new()
     72         .with_tls_config(tls)
     73         .https_or_http()
     74         .enable_http1()
     75         .enable_http2()
     76         .build();
     77 
     78     // Build the hyper client from the HTTPS connector.
     79     let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(https);
     80     Ok(client)
     81 }
     82 
     83 #[derive(Debug, Clone)]
     84 pub struct Ctx {
     85     path: Cow<'static, str>,
     86     method: Method,
     87     status: Option<StatusCode>,
     88 }
     89 
     90 impl Ctx {
     91     pub fn wrap<E: std::error::Error>(self, err: E) -> ApiErr<E> {
     92         ApiErr { ctx: self, err }
     93     }
     94 }
     95 
     96 impl Display for Ctx {
     97     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     98         let Self {
     99             path,
    100             method,
    101             status,
    102         } = self;
    103         write!(f, "{path} {method}")?;
    104         if let Some(status) = status {
    105             write!(f, " {status}")?;
    106         }
    107         Ok(())
    108     }
    109 }
    110 
    111 #[derive(Debug, Error)]
    112 /// Error happening with api request context
    113 #[error("{ctx} {err}")]
    114 pub struct ApiErr<E: std::error::Error> {
    115     pub ctx: Ctx,
    116     pub err: E,
    117 }