#![cfg_attr(docsrs, doc(cfg(feature = "sync")))]
use std::{collections::HashMap, ops::FnOnce};
use crate::{
builders::*,
structs::{response::MyustResponse, *},
traits::*,
utils::*,
};
use reqwest::Method;
use serde_json::{json, Map, Value};
#[derive(Clone, Default)]
pub struct SyncClient {
inner: reqwest::blocking::Client,
token: Option<String>,
}
impl SyncClient {
fn check_token(client: reqwest::blocking::Client, token: String) -> u16 {
client
.get(SELF_ENDPOINT)
.header("Authorization", format!("Bearer {}", token))
.send()
.unwrap()
.status()
.as_u16()
}
pub fn new() -> Self {
SyncClient {
inner: reqwest::blocking::Client::new(),
..Default::default()
}
}
pub fn auth(mut self, token: impl Into<String>) -> Self {
let token_str = token.into();
let code = Self::check_token(self.inner.clone(), token_str.clone());
match code {
200 => {
self.token = Some(format!("Bearer {}", token_str));
self
}
_ => panic!("the provided token is invalid"),
}
}
fn request(&self, method: &str, url: &str, json: Value) -> MyustResponse {
let methods = HashMap::from([
("GET", Method::GET),
("PUT", Method::PUT),
("DELETE", Method::DELETE),
]);
let response = if let Some(token) = &self.token {
self.inner
.request(methods[method].clone(), url.clone())
.header("Authorization", token)
.json(&json)
.send()
.unwrap()
} else {
self.inner
.request(methods[method].clone(), url.clone())
.json(&json)
.send()
.unwrap()
};
let status_code = response.status().as_u16();
let json_value = response.json::<Value>().ok();
MyustResponse {
json: json_value,
status_code,
}
}
pub fn create_paste<F>(&self, paste: F) -> Result<PasteResult, MystbinError>
where
F: FnOnce(&mut PasteBuilder) -> &mut PasteBuilder,
{
let mut builder = PasteBuilder {
..Default::default()
};
let data = paste(&mut builder);
let files = vec![File {
filename: data.filename.to_string(),
content: data.content.to_string(),
}];
let mut map = Map::new();
map.insert("files".to_string(), json!(files));
map.insert("password".to_string(), json!(data.password));
if let Some(expiry) = &data.expires {
if expiry.valid() {
if expiry.is_default() {
map.insert("expires".to_string(), json!(None::<()>));
} else {
map.insert("expires".to_string(), json!(expiry.to_rfc3339()));
}
} else {
let invalid = expiry.invalid_field();
panic!("{} can not be negative, value: {}", invalid.0, invalid.1)
}
};
let json = Value::Object(map);
let response = self.request_create_paste(json);
match response.status_code {
200 | 201 | 204 => {
let paste_result = response.json.unwrap();
Ok(PasteResult {
created_at: paste_result["created_at"].as_str().unwrap().to_string(),
expires: paste_result["expires"].as_str().map(|d| d.to_string()),
files,
id: paste_result["id"].as_str().unwrap().to_string(),
})
}
_ => {
let json = response.json;
if let Some(data) = json {
Err(MystbinError {
code: response.status_code,
error: data["error"].as_str().map(|s| s.to_string()),
notice: data["notice"].as_str().map(|s| s.to_string()),
detail: data["detail"]
.as_object()
.map(|m| m.clone().into_iter().collect()),
})
} else {
Err(MystbinError {
code: response.status_code,
..Default::default()
})
}
}
}
}
pub fn create_multifile_paste<F>(&self, pastes: F) -> Result<PasteResult, MystbinError>
where
F: FnOnce(&mut PastesBuilder) -> &mut PastesBuilder,
{
let mut builder = PastesBuilder::default();
let data = &pastes(&mut builder).files;
let first_paste = &data[0];
let files = data
.iter()
.map(|file| File {
filename: file.filename.clone(),
content: file.content.clone(),
})
.collect();
let mut map = Map::new();
map.insert("files".to_string(), json!(files));
map.insert("password".to_string(), json!(first_paste.password));
if let Some(expiry) = &first_paste.expires {
if expiry.valid() {
if expiry.is_default() {
map.insert("expires".to_string(), json!(None::<()>));
} else {
map.insert("expires".to_string(), json!(expiry.to_rfc3339()));
}
} else {
let invalid = expiry.invalid_field();
panic!("{} can not be negative, value: {}", invalid.0, invalid.1)
}
};
let json = Value::Object(map);
let response = self.request_create_paste(json);
match response.status_code {
200 | 201 | 204 => {
let paste_result = response.json.unwrap();
Ok(PasteResult {
created_at: paste_result["created_at"].as_str().unwrap().to_string(),
expires: paste_result["expires"].as_str().map(|d| d.to_string()),
files,
id: paste_result["id"].as_str().unwrap().to_string(),
})
}
_ => {
let json = response.json;
if let Some(data) = json {
Err(MystbinError {
code: response.status_code,
error: data["error"].as_str().map(|s| s.to_string()),
notice: data["notice"].as_str().map(|s| s.to_string()),
detail: data["detail"]
.as_object()
.map(|m| m.clone().into_iter().collect()),
})
} else {
Err(MystbinError {
code: response.status_code,
..Default::default()
})
}
}
}
}
pub fn get_paste<F>(&self, paste: F) -> Result<PasteResult, MystbinError>
where
F: FnOnce(&mut GetPasteBuilder) -> &mut GetPasteBuilder,
{
let mut builder = GetPasteBuilder::default();
let data = paste(&mut builder);
let response = self.request_get_paste(data.id.clone(), data.password.clone());
match response.status_code {
200 => {
let paste_result = response.json.unwrap();
let files = paste_result["files"]
.as_array()
.unwrap()
.iter()
.map(|x| File {
filename: x.get("filename").unwrap().to_string(),
content: x.get("content").unwrap().to_string(),
})
.collect::<Vec<File>>();
Ok(PasteResult {
created_at: paste_result["created_at"].as_str().unwrap().to_string(),
expires: paste_result["expires"].as_str().map(|d| d.to_string()),
files,
id: data.id.clone(),
})
}
_ => {
let json = response.json;
if let Some(data) = json {
Err(MystbinError {
code: response.status_code,
error: data["error"].as_str().map(|s| s.to_string()),
notice: data["notice"].as_str().map(|s| s.to_string()),
detail: data["detail"]
.as_object()
.map(|m| m.clone().into_iter().collect()),
})
} else {
Err(MystbinError {
code: response.status_code,
..Default::default()
})
}
}
}
}
}
impl SyncClientPaste for SyncClient {
fn request_create_paste(&self, json: Value) -> MyustResponse {
self.request("PUT", PASTE_ENDPOINT, json)
}
fn request_delete_paste(&self, paste_id: &str) -> MyustResponse {
self.request(
"DELETE",
&format!("{}/{}", PASTE_ENDPOINT, paste_id),
json!({}),
)
}
fn request_delete_pastes(&self, json: Value) -> MyustResponse {
self.request("DELETE", PASTE_ENDPOINT, json)
}
fn request_get_paste(&self, paste_id: String, password: Option<String>) -> MyustResponse {
let url = if password.is_some() {
format!(
"{}/{}?password={}",
PASTE_ENDPOINT,
paste_id,
password.unwrap()
)
} else {
format!("{}/{}", PASTE_ENDPOINT, paste_id)
};
self.request("GET", &url, json!({}))
}
fn request_get_user_pastes(&self, json: Value) -> MyustResponse {
self.request("GET", USER_PASTES_ENDPOINT, json)
}
}
impl SyncClientBookmark for SyncClient {
fn request_create_bookmark(&self, json: Value) -> MyustResponse {
self.request("PUT", BOOKMARK_ENDPOINT, json)
}
fn request_delete_bookmark(&self, json: Value) -> MyustResponse {
self.request("DELETE", BOOKMARK_ENDPOINT, json)
}
fn request_get_user_bookmarks(&self) -> MyustResponse {
self.request("GET", BOOKMARK_ENDPOINT, json!({}))
}
}