use std::collections::HashMap;
use regex::Regex;
use product_os_request::{BodyType, ProductOSResponse};
use crate::registry::Node;
pub async fn command(requester: &product_os_request::ProductOSRequester, url: url::Url, verify_key: Vec<u8>,
module: String, instruction: String, data: Option<serde_json::Value>) -> Result<ProductOSResponse, product_os_request::ProductOSRequestError> {
let endpoint = String::from(url.to_string().trim_end_matches("/")) +
"/command/" + module.as_str() + "/" + instruction.as_str();
let mut request = requester.new_request(product_os_request::Method::POST, endpoint);
request.set_json(&data);
request.add_header("x-product-os-verify".to_string(),
product_os_security::create_auth_request(None, false, data,
None, &[], Some(verify_key.as_slice())),
true);
match requester.request(request).await {
Ok(response) => {
tracing::trace!("Successfully sent {:?}/{:?} command to server {:?}", module, instruction, url);
Ok(response)
},
Err(e) => {
tracing::error!("Error encountered {:?} from {}", e, url);
Err(product_os_request::ProductOSRequestError {
error: product_os_request::ProductOSRequestErrorState::Error("No matching node found".to_string()),
generated_error: Some(e)
})
}
}
}
pub fn ask_node_sync(requester: &mut product_os_request::ProductOSRequester, node: &Node, verify_key: Vec<u8>,
path: String, data: Option<serde_json::Value>, headers: HashMap<String, String>,
params: HashMap<String, String>, method: product_os_request::Method) -> Result<ProductOSResponse, product_os_request::ProductOSRequestSyncError> {
let url = node.get_address();
ask_sync(requester, url, verify_key, path, data, headers, params, method)
}
pub async fn ask(requester: &product_os_request::ProductOSRequester, url: url::Url, verify_key: Vec<u8>,
path: String, data: Option<serde_json::Value>, headers: HashMap<String, String>,
params: HashMap<String, String>, method: product_os_request::Method) -> Result<ProductOSResponse, product_os_request::ProductOSRequestError> {
let path_clean = clean_path(path, false);
let endpoint = String::from(url.to_string().trim_end_matches("/")) +
path_clean.clone().as_str();
let mut request = requester.new_request(method, endpoint);
request.add_headers(headers, false);
request.add_params(params);
request.set_json(&data);
request.add_header("x-product-os-verify".to_string(),
product_os_security::create_auth_request(None, false, data,
None, &[], Some(verify_key.as_slice())),
true);
match requester.request(request).await {
Ok(response) => {
tracing::trace!("Successfully sent ask {:?} command to server {:?}", path_clean, url);
Ok(response)
},
Err(e) => {
tracing::error!("Error encountered {:?} from {}", e, url);
Err(product_os_request::ProductOSRequestError {
error: product_os_request::ProductOSRequestErrorState::Error("No matching node found".to_string()),
generated_error: Some(e)
})
}
}
}
pub fn ask_sync(requester: &mut product_os_request::ProductOSRequester, url: url::Url, verify_key: Vec<u8>,
path: String, data: Option<serde_json::Value>, headers: HashMap<String, String>,
params: HashMap<String, String>, method: product_os_request::Method) -> Result<ProductOSResponse, product_os_request::ProductOSRequestSyncError> {
let path_clean = clean_path(path, false);
let endpoint = String::from(url.to_string().trim_end_matches("/")) +
path_clean.clone().as_str();
let mut request = requester.new_request(method, endpoint);
request.add_headers(headers, false);
request.add_params(params);
request.add_header("x-product-os-verify".to_string(),
product_os_security::create_auth_request(None, false, data.clone(),
None, &[], Some(verify_key.as_slice())),
true);
match requester.request_sync(request, BodyType::Json, data) {
Ok(response) => {
tracing::trace!("Successfully sent ask {:?} command to server {:?}", path_clean, url);
Ok(response)
},
Err(e) => {
tracing::error!("Error encountered {:?} from {}", e, url);
Err(product_os_request::ProductOSRequestSyncError {
error: product_os_request::ProductOSRequestErrorState::Error("No matching node found".to_string()),
generated_error: Some(e)
})
}
}
}
fn clean_path(input: String, add_back_slash: bool) -> String {
let mut path = input;
if path != "/" {
path = Regex::new(r"//").unwrap().replace_all(path.as_str(), "").to_string();
path = Regex::new(r"/$").unwrap().replace_all(path.as_str(), "").to_string();
}
if !path.starts_with("/") {
path = "/".to_owned() + path.as_str();
}
if add_back_slash && !path.ends_with("/") {
path = path + "/";
}
Regex::new(r"[.][.]").unwrap().replace_all(path.as_str(), "").to_string()
}