use std::future::Future;
use std::sync::Arc;
use tokio::runtime::{Builder, Runtime};
use crate::core::{
Config, CreditResponse, DeviceResponse, Error, ErrorKind, HttpClient, IntoBody, Json, Method,
RequestOptions, ResponseData, Result,
};
#[derive(Clone, Debug)]
pub struct ApiBrasil {
runtime: Arc<Runtime>,
api: crate::ApiBrasil,
}
impl ApiBrasil {
pub fn new(config: Config) -> Result<Self> {
let runtime = Builder::new_current_thread()
.enable_all()
.build()
.map_err(|error| {
Error::new(
ErrorKind::Api,
format!("Não foi possível iniciar o runtime do cliente síncrono: {error}"),
)
.with_source(error)
})?;
Ok(Self {
runtime: Arc::new(runtime),
api: crate::ApiBrasil::new(config),
})
}
pub fn from_env() -> Result<Self> {
Self::new(Config::default())
}
pub fn asynchronous(&self) -> &crate::ApiBrasil {
&self.api
}
pub fn runtime(&self) -> &Arc<Runtime> {
&self.runtime
}
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
self.runtime.block_on(future)
}
pub fn http(&self) -> &Arc<HttpClient> {
self.api.http()
}
pub fn config(&self) -> Config {
self.api.config()
}
pub fn set_bearer_token(&self, token: impl Into<String>) -> &Self {
self.api.set_bearer_token(token);
self
}
pub fn clear_bearer_token(&self) -> &Self {
self.api.clear_bearer_token();
self
}
pub fn set_device_token(&self, token: impl Into<String>) -> &Self {
self.api.set_device_token(token);
self
}
pub fn clear_device_token(&self) -> &Self {
self.api.clear_device_token();
self
}
pub fn with_options(&self, options: RequestOptions) -> Self {
Self {
runtime: self.runtime.clone(),
api: self.api.with_options(options),
}
}
pub fn with_device(&self, device_token: impl Into<String>) -> Self {
Self {
runtime: self.runtime.clone(),
api: self.api.with_device(device_token),
}
}
pub fn request(&self, method: Method, path: &str, body: impl IntoBody) -> Result<Json> {
self.block_on(self.api.request(method, path, body))
}
pub fn execute(&self, method: Method, path: &str, body: impl IntoBody) -> Result<ResponseData> {
self.block_on(self.api.execute(method, path, body))
}
pub fn download(&self, path: &str) -> Result<Vec<u8>> {
self.block_on(self.api.download(path))
}
}
pub fn login(credentials: impl IntoBody, config: Config) -> Result<(ApiBrasil, Json)> {
let api = ApiBrasil::new(config)?;
let session = api.block_on(crate::AuthService::login(
&api.asynchronous().auth(),
credentials,
))?;
if crate::requires_2fa(&session) {
return Err(Error::authentication(
"Esta conta exige autenticação em dois fatores. Use auth().login() + auth().verify_2fa().",
)
.with_response(session));
}
Ok((api, session))
}
macro_rules! sync_service {
(
$(#[$meta:meta])*
$name:ident = $accessor:ident : $async_ty:ident
) => {
$(#[$meta])*
#[derive(Clone, Debug)]
pub struct $name {
runtime: Arc<Runtime>,
inner: crate::$async_ty,
}
impl $name {
#[doc = concat!("Serviço assíncrono equivalente: [`", stringify!($async_ty), "`](crate::", stringify!($async_ty), ").")]
pub fn asynchronous(&self) -> &crate::$async_ty {
&self.inner
}
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
self.runtime.block_on(future)
}
pub fn with_options(&self, options: RequestOptions) -> Self {
Self {
runtime: self.runtime.clone(),
inner: self.inner.with_options(options),
}
}
}
impl ApiBrasil {
$(#[$meta])*
pub fn $accessor(&self) -> $name {
$name {
runtime: self.runtime.clone(),
inner: self.api.$accessor(),
}
}
}
};
}
macro_rules! sync_device {
($name:ident : $async_ty:ident [ $($method:ident),* $(,)? ]) => {
impl $name {
pub fn request(&self, action: &str, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.request(action, body))
}
pub fn queue(&self, action: &str, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.queue(action, body))
}
$(
#[doc = concat!("Versão síncrona de [`", stringify!($async_ty), "::", stringify!($method), "`](crate::", stringify!($async_ty), "::", stringify!($method), ").")]
pub fn $method(&self, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.$method(body))
}
)*
}
};
}
macro_rules! sync_json {
($name:ident : $async_ty:ident [ $($method:ident),* $(,)? ]) => {
impl $name {
$(
#[doc = concat!("Versão síncrona de [`", stringify!($async_ty), "::", stringify!($method), "`](crate::", stringify!($async_ty), "::", stringify!($method), ").")]
pub fn $method(&self) -> Result<Json> {
self.block_on(self.inner.$method())
}
)*
}
};
}
macro_rules! sync_json_body {
($name:ident : $async_ty:ident [ $($method:ident),* $(,)? ]) => {
impl $name {
$(
#[doc = concat!("Versão síncrona de [`", stringify!($async_ty), "::", stringify!($method), "`](crate::", stringify!($async_ty), "::", stringify!($method), ").")]
pub fn $method(&self, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.$method(body))
}
)*
}
};
}
macro_rules! sync_credit {
($name:ident : $async_ty:ident [ $($method:ident),* $(,)? ]) => {
impl $name {
$(
#[doc = concat!("Versão síncrona de [`", stringify!($async_ty), "::", stringify!($method), "`](crate::", stringify!($async_ty), "::", stringify!($method), ").")]
pub fn $method(&self, body: impl IntoBody) -> Result<CreditResponse> {
self.block_on(self.inner.$method(body))
}
)*
}
};
}
sync_service! {
WhatsApp = whatsapp: WhatsAppService
}
sync_device!(WhatsApp: WhatsAppService [
start, qrcode, logout, close, delete_session, restart_session, get_connection_status,
send_text, send_file, send_file64, send_audio, send_video, send_gif, send_link, send_location,
send_contact, send_sticker, send_list, send_buttons, send_poll_message, send_pix_key,
send_text_to_storie, send_image_to_storie, send_video_to_storie, check_number_status,
get_all_chats, get_all_contacts, get_all_groups, get_profile_pic,
]);
sync_service! {
WhatsMeow = whatsmeow: WhatsMeowService
}
sync_device!(WhatsMeow: WhatsMeowService [
send_text, send_media, instance_create, instance_connect, instance_qr,
]);
sync_service! {
Sms = sms: SmsService
}
sync_device!(Sms: SmsService [send]);
impl Sms {
pub fn send_with_credits(&self, body: impl IntoBody) -> Result<CreditResponse> {
self.block_on(self.inner.send_with_credits(body))
}
}
sync_service! {
Evolution = evolution: EvolutionService
}
impl Evolution {
pub fn request(
&self,
controller: &str,
action: &str,
body: impl IntoBody,
) -> Result<DeviceResponse> {
self.block_on(self.inner.request(controller, action, body))
}
pub fn call(&self, path: &str, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.call(path, body))
}
pub fn queue(
&self,
controller: &str,
action: &str,
body: impl IntoBody,
) -> Result<DeviceResponse> {
self.block_on(self.inner.queue(controller, action, body))
}
}
sync_service! {
Dados = dados: DadosService
}
sync_device!(Dados: DadosService [
cnpj, cpf, cep, lista_socios, lista_cnaes, capital_social, by_query,
]);
sync_service! {
Cep = cep: CepService
}
sync_device!(Cep: CepService [
cep, bairros, cidades, cidades_por_ddd, estados, calcular_distancia,
]);
sync_service! {
Correios = correios: CorreiosService
}
sync_device!(Correios: CorreiosService [rastreio]);
sync_service! {
Fipe = fipe: FipeService
}
sync_device!(Fipe: FipeService [
consultar_tabela_de_referencia, consultar_marcas, consultar_modelos, consultar_ano_modelo,
consultar_modelos_atraves_do_ano, consultar_valor_com_todos_parametros,
]);
sync_service! {
Vehicles = vehicles: VehiclesService
}
sync_device!(Vehicles: VehiclesService [dados, fipe, base_dados, base_fipe]);
impl Vehicles {
pub fn consulta_fipe(&self, placa: &str) -> Result<DeviceResponse> {
self.block_on(self.inner.consulta_fipe(placa))
}
}
sync_service! {
Geolocation = geolocation: GeolocationService
}
sync_device!(Geolocation: GeolocationService [geocode, forward_geocoding]);
sync_service! {
Geomatrix = geomatrix: GeomatrixService
}
sync_device!(Geomatrix: GeomatrixService [distance]);
sync_service! {
Recognize = recognize: RecognizeService
}
sync_device!(Recognize: RecognizeService [base64, uri]);
sync_service! {
Ddd = ddd: DddService
}
sync_device!(Ddd: DddService []);
sync_service! {
Holidays = holidays: HolidaysService
}
sync_device!(Holidays: HolidaysService [feriados]);
sync_service! {
Translate = translate: TranslateService
}
sync_device!(Translate: TranslateService [identify, models]);
sync_service! {
Weather = weather: WeatherService
}
sync_device!(Weather: WeatherService [city, coordenates]);
sync_service! {
Loterias = loterias: LoteriasService
}
impl Loterias {
pub fn resultado(
&self,
sorteio: &str,
concurso: u64,
body: impl IntoBody,
) -> Result<DeviceResponse> {
self.block_on(self.inner.resultado(sorteio, concurso, body))
}
pub fn latest(&self, sorteio: &str, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.latest(sorteio, body))
}
}
sync_service! {
DatabaseIp = database_ip: DatabaseIpService
}
impl DatabaseIp {
pub fn ip(&self, body: impl IntoBody) -> Result<DeviceResponse> {
self.block_on(self.inner.ip(body))
}
}
sync_service! {
Ura = ura: UraService
}
sync_json_body!(Ura: UraService [dialler, status]);
sync_service! {
ChipVirtual = chip_virtual: ChipVirtualService
}
sync_json_body!(ChipVirtual: ChipVirtualService [operators, buy, activation, services]);
sync_service! {
Bulk = bulk: BulkService
}
impl Bulk {
pub fn direct(&self, action: &str, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.direct(action, body))
}
pub fn queue(&self, action: &str, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.queue(action, body))
}
}
sync_service! {
Consulta = consulta: ConsultaService
}
sync_credit!(Consulta: ConsultaService [
cpf, cnpj, cnh, cep, veiculos, vehicles, telefone, ddd_anatel, geoip, rastreio, crm, crbm,
cro, weather, emissao_notas, frete_antt, api_rntrc, quod, cep_distancia, proxy_seller,
]);
impl Consulta {
pub fn generic(&self, service: &str, body: impl IntoBody) -> Result<CreditResponse> {
self.block_on(self.inner.generic(service, body))
}
pub fn credits(&self, service: &str) -> Result<CreditResponse> {
self.block_on(self.inner.credits(service))
}
pub fn veiculos_base(&self, base: &str, body: impl IntoBody) -> Result<CreditResponse> {
self.block_on(self.inner.veiculos_base(base, body))
}
}
sync_service! {
Auth = auth: AuthService
}
sync_json!(Auth: AuthService [
two_factor_methods, me, verify, profile, token_rotate, token_revoke,
]);
sync_json_body!(Auth: AuthService [
send_2fa, register, register_simple, verification_send, verification_verify, password_forgot,
password_verify_code, password_reset, password_resend, change_password, update_me,
]);
impl Auth {
pub fn login(&self, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.login(body))
}
pub fn verify_2fa(&self, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.verify_2fa(body))
}
pub fn refresh(&self) -> Result<Json> {
self.block_on(self.inner.refresh())
}
pub fn logout(&self) -> Result<Json> {
self.block_on(self.inner.logout())
}
}
sync_service! {
Devices = devices: DevicesService
}
sync_json_body!(Devices: DevicesService [update, requests]);
impl Devices {
pub fn list(&self, query: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.list(query))
}
pub fn store(&self, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.store(body))
}
pub fn show(&self, device_token: Option<&str>) -> Result<Json> {
self.block_on(self.inner.show(device_token))
}
pub fn destroy(&self, device_token: Option<&str>) -> Result<Json> {
self.block_on(self.inner.destroy(device_token))
}
}
sync_service! {
Catalog = catalog: CatalogService
}
sync_json!(Catalog: CatalogService [
api_categories, my_apis, plans, documentations, servers, status,
]);
sync_json_body!(Catalog: CatalogService [endpoint_url, endpoint_body]);
impl Catalog {
pub fn apis(&self, search: Option<&str>) -> Result<Json> {
self.block_on(self.inner.apis(search))
}
pub fn api(&self, identifier: &str) -> Result<Json> {
self.block_on(self.inner.api(identifier))
}
pub fn api_by_name(&self, name: &str) -> Result<Json> {
self.block_on(self.inner.api_by_name(name))
}
pub fn apis_by_device(&self, device_token: &str) -> Result<Json> {
self.block_on(self.inner.apis_by_device(device_token))
}
pub fn documentations_by_server(&self, server_search: &str) -> Result<Json> {
self.block_on(self.inner.documentations_by_server(server_search))
}
}
sync_service! {
Account = account: AccountService
}
sync_json!(Account: AccountService [
balance, plan, invoices, invoice_notes, jobs, credentials, indications, notifications, tickets,
mark_all_notifications_read,
]);
sync_json_body!(Account: AccountService [
pay_invoice, requests, api_requests, create_ticket,
]);
impl Account {
pub fn mark_notification_read(&self, id: impl std::fmt::Display) -> Result<Json> {
self.block_on(self.inner.mark_notification_read(id))
}
pub fn update_ticket(&self, id: impl std::fmt::Display, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.update_ticket(id, body))
}
pub fn ticket_messages(&self, id: impl std::fmt::Display) -> Result<Json> {
self.block_on(self.inner.ticket_messages(id))
}
pub fn add_ticket_message(
&self,
id: impl std::fmt::Display,
body: impl IntoBody,
) -> Result<Json> {
self.block_on(self.inner.add_ticket_message(id, body))
}
}
sync_service! {
Payments = payments: PaymentsService
}
sync_json!(Payments: PaymentsService [
recharges, checkout_payment_methods, checkout_periods,
]);
sync_json_body!(Payments: PaymentsService [
recharge, card_process, card_installments, validate_coupon, checkout_finalize,
]);
impl Payments {
pub fn recharge_show(&self, identifier: &str) -> Result<Json> {
self.block_on(self.inner.recharge_show(identifier))
}
pub fn pix_generate(&self, provider: &str, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.pix_generate(provider, body))
}
pub fn pix_status(&self, provider: &str, tx_id: &str) -> Result<Json> {
self.block_on(self.inner.pix_status(provider, tx_id))
}
pub fn boleto_generate(&self, provider: &str, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.boleto_generate(provider, body))
}
pub fn boleto_status(&self, provider: &str, id: &str) -> Result<Json> {
self.block_on(self.inner.boleto_status(provider, id))
}
pub fn boleto_pdf(&self, provider: &str, id: &str) -> Result<Vec<u8>> {
self.block_on(self.inner.boleto_pdf(provider, id))
}
pub fn card_status(&self, id: &str) -> Result<Json> {
self.block_on(self.inner.card_status(id))
}
}
sync_service! {
IpWhitelist = ip_whitelist: IpWhitelistService
}
sync_json!(IpWhitelist: IpWhitelistService [add_current, reset]);
impl IpWhitelist {
pub fn get(&self) -> Result<Json> {
self.block_on(self.inner.get())
}
pub fn set<I, S>(&self, entries: I) -> Result<Json>
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.block_on(self.inner.set(entries))
}
pub fn add(&self, entry: &str) -> Result<Json> {
self.block_on(self.inner.add(entry))
}
pub fn remove(&self, entry: &str) -> Result<Json> {
self.block_on(self.inner.remove(entry))
}
pub fn validate(&self, entry: &str) -> Result<Json> {
self.block_on(self.inner.validate(entry))
}
pub fn current_ip(&self) -> Result<Json> {
self.block_on(self.inner.current_ip())
}
}
sync_service! {
BearerRateLimit = bearer_rate_limit: BearerRateLimitService
}
impl BearerRateLimit {
pub fn get(&self) -> Result<Json> {
self.block_on(self.inner.get())
}
pub fn set(&self, body: impl IntoBody) -> Result<Json> {
self.block_on(self.inner.set(body))
}
}
sync_service! {
Reports = reports: ReportsService
}
sync_json!(Reports: ReportsService [
dashboard_stats, consumption, extract, dashboard, summary, daily_usage, monthly_summary,
error_analysis, device_analysis, recent_requests, quick_stats,
]);
sync_json_body!(Reports: ReportsService [generate_consumption_report]);