use std::marker::PhantomData;
use std::sync::Arc;
use arc_swap::ArcSwap;
use async_trait::async_trait;
pub use pix_brcode::qr_dinamico::PixDinamicoSchema;
pub use reqwest::header;
use reqwest::header::HeaderMap;
use reqwest::{Client, Identity, Method, Request, StatusCode};
use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::errors::{ApiResult, PixError};
pub mod cob;
pub mod errors;
pub mod webhook;
pub mod extensions;
pub mod oauth;
#[derive(Debug)]
struct PixClientBuilder {
username: String,
secret: String,
certificate: Vec<u8>,
}
impl PixClientBuilder {}
#[derive(Debug)]
pub struct PixClient {
inner_client: Client,
headers: ArcSwap<HeaderMap>,
certificate: Vec<u8>,
base_endpoint: String,
}
impl PixClient {
pub fn new_with_custom_headers<F>(endpoint: &str, mut custom_headers: F, certificate: Vec<u8>) -> PixClient
where
F: FnMut(&mut HeaderMap),
{
let identity = Identity::from_pkcs12_der(&*certificate, "").expect("Invalid certificate");
let mut default_headers = HeaderMap::new();
custom_headers(&mut default_headers);
let client = Client::builder().identity(identity).https_only(true).build().unwrap();
Self {
inner_client: client,
headers: ArcSwap::from_pointee(default_headers),
certificate,
base_endpoint: endpoint.to_string(),
}
}
pub fn swap_authorization_token(&self, authorization_header_value: String) {
let mut stored_header = HeaderMap::new();
stored_header.insert(header::AUTHORIZATION, authorization_header_value.parse().unwrap());
self.headers.store(Arc::new(stored_header));
}
fn request_with_headers<Payload, Response>(
&self,
method: Method,
endpoint: &str,
payload: Payload,
) -> ApiRequest<Response>
where
Payload: Serialize,
Response: DeserializeOwned,
{
let inner_headers = &**self.headers.load();
let request = self
.inner_client
.request(method, endpoint)
.headers(inner_headers.clone())
.json(&payload)
.build()
.unwrap();
ApiRequest::new(self, request)
}
}
#[derive(Debug)]
pub struct ApiRequest<'a, Response> {
client: &'a PixClient,
request: Request,
response_type: PhantomData<Response>,
}
impl<'a, T> ApiRequest<'a, T> {
fn new(client: &'a PixClient, request: Request) -> ApiRequest<T> {
Self {
client,
request,
response_type: Default::default(),
}
}
}
#[async_trait]
impl<ResponseType> Executor<ResponseType> for ApiRequest<'_, ResponseType>
where
ResponseType: DeserializeOwned + Send,
{
async fn execute(self) -> ApiResult<ResponseType> {
let body = self
.request
.body()
.map(|x| x.as_bytes().map(|x| String::from_utf8(Vec::from(x)).unwrap()))
.flatten();
log::info!("{:?}", body);
let result = self.client.inner_client.execute(self.request).await?;
let status_code = result.status();
let text = result.text().await?;
log::info!("{}", text);
if !status_code.is_success() {
return match status_code {
StatusCode::UNAUTHORIZED => Err(PixError::InvalidCredentials),
StatusCode::BAD_REQUEST => Err(PixError::PayloadError),
_ => Err(PixError::Other(text)),
};
}
serde_json::from_str::<ResponseType>(&*text).map_err(|e| e.into())
}
}
#[async_trait]
pub trait Executor<T> {
async fn execute(self) -> ApiResult<T>;
}