use std::time::Duration;
use reqwest::Client;
use serde::{de::DeserializeOwned, Serialize};
use tracing::debug;
use crate::error::{Result, RointeError};
const DATABASE_URL: &str = "https://elife-prod.firebaseio.com";
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
pub struct RtdbClient {
client: Client,
base_url: String,
}
impl RtdbClient {
pub fn new(client: Client) -> Self {
Self {
client,
base_url: DATABASE_URL.to_string(),
}
}
pub async fn get<T: DeserializeOwned>(
&self,
path: &str,
token: &str,
extra_params: &[(&str, &str)],
) -> Result<T> {
let url = format!("{}{}", self.base_url, path);
debug!("GET {url}");
let mut all_params: Vec<(&str, &str)> = vec![("auth", token)];
all_params.extend_from_slice(extra_params);
let resp = self
.client
.get(&url)
.query(&all_params)
.timeout(REQUEST_TIMEOUT)
.send()
.await
.map_err(RointeError::Network)?;
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
return Err(RointeError::Firebase(format!(
"GET {path} failed ({status}): {body}"
)));
}
resp.json().await.map_err(RointeError::Network)
}
pub async fn patch<T: Serialize>(
&self,
path: &str,
token: &str,
body: &T,
) -> Result<()> {
let url = format!("{}{}", self.base_url, path);
debug!("PATCH {url}");
let resp = self
.client
.patch(&url)
.query(&[("auth", token)])
.json(body)
.timeout(REQUEST_TIMEOUT)
.send()
.await
.map_err(RointeError::Network)?;
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
return Err(RointeError::Firebase(format!(
"PATCH {path} failed ({status}): {body}"
)));
}
Ok(())
}
pub fn base_url(&self) -> &str {
&self.base_url
}
}