gerencianet_api/
lib.rs

1use std::{
2    fs::File,
3    io::Read,
4    time::{Duration, Instant},
5};
6
7use reqwest::Error;
8use serde::{Deserialize, Serialize};
9use tokio::runtime::Runtime;
10
11#[derive(Deserialize, Serialize, Debug)]
12struct AuthPost {
13    grant_type: String,
14}
15
16#[derive(Deserialize, Serialize, Debug)]
17struct AuthResult {
18    access_token: String,
19    token_type: String,
20    expires_in: u32,
21    scope: String,
22}
23
24pub struct Gerencianet {
25    url: String,
26    cert: String,
27    client_id: String,
28    client_secret: String,
29    rt: Runtime,
30}
31
32#[derive(Debug)]
33pub struct Sessao {
34    access_token: String,
35    token_type: String,
36    expires_in: u32,
37    scope: String,
38}
39
40#[derive(Debug)]
41pub struct Cliente {
42    url: String,
43    cliente_req: reqwest::Client,
44    client_id: String,
45    client_secret: String,
46    expires_time: Instant,
47    rt: Runtime,
48    sessao: Sessao,
49}
50
51fn verificar_expiracao_token(cliente: &mut Cliente) {
52    if cliente.expires_time.elapsed() >= Duration::from_secs(cliente.sessao.expires_in.into()) {
53        cliente.refresh_token();
54    }
55}
56
57impl Cliente {
58    pub fn refresh_token(&mut self) -> &mut Self {
59        let resp = self.rt.block_on(async {
60            self.cliente_req
61                .post(format!("{}/oauth/token", self.url))
62                .basic_auth(
63                    self.client_id.to_owned(),
64                    Some(self.client_secret.to_owned()),
65                )
66                .json(&AuthPost {
67                    grant_type: "client_credentials".to_owned(),
68                })
69                .send()
70                .await
71                .unwrap()
72                .json::<AuthResult>()
73                .await
74                .unwrap()
75        });
76        self.expires_time = Instant::now();
77        self.sessao = Sessao {
78            access_token: resp.access_token,
79            token_type: resp.token_type,
80            expires_in: resp.expires_in,
81            scope: resp.scope,
82        };
83        self
84    }
85}
86
87impl Default for Gerencianet {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl Gerencianet {
94    pub fn new() -> Self {
95        Self {
96            cert: String::new(),
97            rt: tokio::runtime::Runtime::new().unwrap(),
98            client_id: String::new(),
99            client_secret: String::new(),
100            url: "https://api-pix-h.gerencianet.com.br".to_owned(),
101        }
102    }
103    pub fn producao(&mut self) -> &mut Self {
104        self.url = "https://api-pix.gerencianet.com.br".to_owned();
105        self
106    }
107    pub fn homologacao(&mut self) -> &mut Self {
108        self.url = "https://api-pix-h.gerencianet.com.br".to_owned();
109        self
110    }
111    pub fn certificado_p12(&mut self, cert: String) -> &mut Self {
112        self.cert = cert;
113        self
114    }
115    pub fn basic_auth(&mut self, client_id: String, client_secret: String) -> &mut Self {
116        self.client_id = client_id;
117        self.client_secret = client_secret;
118        self
119    }
120    pub fn build(&self) -> Result<Cliente, Error> {
121        let resp = self.rt.block_on(async {
122            let mut buf = Vec::new();
123            File::open(&self.cert)
124                .unwrap()
125                .read_to_end(&mut buf)
126                .unwrap();
127
128            let identity = reqwest::Identity::from_pkcs12_der(&buf, "").unwrap();
129
130            let cliente_req = reqwest::Client::builder()
131                .identity(identity)
132                .danger_accept_invalid_certs(true)
133                .build()
134                .unwrap();
135            let auth = cliente_req
136                .post(format!("{}/oauth/token", self.url))
137                .basic_auth(&self.client_id, Some(&self.client_secret))
138                .json(&AuthPost {
139                    grant_type: "client_credentials".to_owned(),
140                })
141                .send()
142                .await?
143                .json::<AuthResult>()
144                .await?;
145
146            Ok((cliente_req, auth))
147        });
148
149        match resp {
150            Ok(v) => {
151                let (cliente_req, sessao) = v;
152                Ok(Cliente {
153                    url: self.url.to_owned(),
154                    cliente_req,
155                    client_id: self.client_id.to_owned(),
156                    client_secret: self.client_secret.to_owned(),
157                    rt: tokio::runtime::Runtime::new().unwrap(),
158                    expires_time: Instant::now(),
159                    sessao: Sessao {
160                        access_token: sessao.access_token,
161                        token_type: sessao.token_type,
162                        expires_in: sessao.expires_in,
163                        scope: sessao.scope,
164                    },
165                })
166            }
167            Err(e) => Err(e),
168        }
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn teste() {
178        let result = "OK";
179        assert_eq!(result, "OK");
180    }
181}