use std::env;
use reqwest::{
header::{self, HeaderMap, HeaderName, HeaderValue},
Method, StatusCode,
};
use tracing::error;
const REST_BASE: &str = "/rest/api/2";
use crate::{error::Error, Rujira};
pub mod issue;
pub mod myself;
pub mod project;
static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
#[derive(Default)]
pub struct Rq {
bot: Rujira,
uri: String,
payload: serde_json::Value,
method: Method,
headers: HeaderMap,
params: Vec<(String, String)>,
}
#[derive(Debug, Default, Clone)]
pub struct Rs {
pub data: serde_json::Value,
pub raw: String,
pub status: StatusCode,
}
impl Rq {
pub fn new(bot: Rujira) -> Self {
Self {
bot,
method: Method::GET,
..Default::default()
}
}
pub fn uri(self, uri: &str) -> Self {
let uri = uri.to_owned();
Self { uri, ..self }
}
pub fn method(self, method: Method) -> Self {
Self { method, ..self }
}
pub fn add_header(mut self, header: &[u8], value: &str) -> Self {
let Ok(hdr) = HeaderName::from_bytes(header) else {
tracing::error!(
header = ?String::from_utf8_lossy(header),
"Invalid header name"
);
return self;
};
let val = HeaderValue::from_str(value).unwrap();
self.headers.insert(hdr, val);
self
}
pub fn add_params(mut self, params: Vec<(&str, &str)>) -> Self {
let params = params
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
self.params = params;
self
}
pub fn load_payload(mut self, value: serde_json::Value) -> Self {
for (key, value) in value.as_object().unwrap() {
self.payload[key] = value.clone();
}
self
}
pub fn add_payload(mut self, key: &str, value: serde_json::Value) -> Self {
self.payload[key] = value;
self
}
pub fn apply_if<T, F>(self, val: Option<T>, fun: F) -> Self
where
Self: Sized,
F: FnOnce(Self, T) -> Self,
{
if let Some(val) = val {
fun(self, val)
} else {
self
}
}
pub async fn apply(self) -> Result<Rs, Error> {
let mut headers = header::HeaderMap::new();
let hdr = format!("Bearer {}", self.bot.token);
let mut auth_value = header::HeaderValue::from_str(&hdr).map_err(Error::InvalidHeader)?;
auth_value.set_sensitive(true);
headers.insert(header::AUTHORIZATION, auth_value);
let client = reqwest::Client::builder()
.user_agent(APP_USER_AGENT)
.default_headers(headers)
.build()
.map_err(Error::AnyReqwestError)?;
let url = format!("{}{}", self.bot.url.as_ref(), self.uri);
let req = match self.method {
Method::GET => client.get(url),
Method::POST => client.post(url),
Method::DELETE => client.delete(url),
Method::PUT => client.put(url),
_ => return Err(Error::UnsupportedMethod),
};
let req = req
.headers(self.headers)
.query(&self.params)
.json(&self.payload);
let res = req.send().await.map_err(Error::AnyReqwestError)?;
if !res.status().is_success() {
error!(?res, code = ?res.status());
let raw = res.text().await.map_err(Error::AnyReqwestError)?;
return Ok(Rs {
raw,
..Default::default()
});
}
let data = res.text().await.map_err(Error::AnyReqwestError)?;
let Ok(data) = serde_json::from_str(&data) else {
return Ok(Rs {
raw: data,
..Default::default()
});
};
Ok(Rs {
data,
..Default::default()
})
}
}