You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

175 lines
4.8 KiB

#[allow(non_upper_case_globals)]
use crate::{
MASTER_SERVER,
MASTER_PORT,
models::*,
UResult,
UError
};
use reqwest::{
Client,
Url,
Response,
RequestBuilder
};
use std::{
net::Ipv4Addr,
str::FromStr
};
use uuid::Uuid;
pub struct Paths;
#[macro_export]
macro_rules! build_url_by_method {
(
POST $path:tt,
pname = $($param_name:literal)?,
ptype = $($param_type:ty)?,
urlparam = $($url_param:ty)?
) => {
|
instance: &ClientHandler
$(, param: &$param_type)?
$(, url: &$url_param)?
| {
let request = ClientHandler::build_post(
instance,
&format!("{}/{}",
stringify!($path),
String::new() $(+ &(url as &$url_param).to_string())?
)
);
request
$( .json::<BaseMessage<'_, $param_type>>(&param.as_message()) )?
}
};
(
GET $path:tt,
pname = $($param_name:literal)?,
ptype = $($param_type:ty)?,
urlparam = $($url_param:ty)?
) => {
|
instance: &ClientHandler
$(, param: &$param_type)?
$(, url: &$url_param)?
| {
let request = ClientHandler::build_get(
instance,
&format!("{}/{}",
stringify!($path),
String::new() $(+ &(url as &$url_param).to_string())?
)
);
request
$( .query(&[(stringify!($param_name), param.to_string())]) )?
}
};
}
// param_type and result must impl ToMsg
#[macro_export]
macro_rules! build_handler {
(
$method:tt
$path:tt $( /$url_param:tt )? (
$( $param_name:literal: )?
$( $param_type:ty )?
) -> $result:ty
) => {
impl ClientHandler {
pub async fn $path(
&self
$(, param: &$param_type)?
$(, url_param: &$url_param)?
) -> UResult<$result> {
let request = $crate::build_url_by_method!(
$method $path,
pname = $($param_name)?, ptype = $($param_type)?, urlparam = $($url_param)?
)(self $(, param as &$param_type)? $(, url_param as &$url_param)?);
let response = request.send().await?;
match response.error_for_status() {
Ok(r) => r.json::<BaseMessage<$result>>()
.await
.map_err(|e| UError::from(e))
.map(|msg| msg.into_item()),
Err(e) => Err(UError::from(e))
}
}
}
impl Paths {
pub const $path: &'static str = stringify!($path);
}
};
}
pub struct ClientHandler {
base_url: Url,
client: Client,
password: Option<String>
}
impl ClientHandler {
pub fn new(server: Option<String>) -> Self {
let master_server = server
.map(|s| Ipv4Addr::from_str(&s).unwrap())
.unwrap_or(MASTER_SERVER);
Self {
client: Client::new(),
base_url: Url::parse(
&format!("http://{}:{}", master_server, MASTER_PORT)
).unwrap(),
password: None
}
}
pub fn password(mut self, password: String) -> ClientHandler {
self.password = Some(password);
self
}
fn set_pwd(&self, rb: RequestBuilder) -> RequestBuilder {
match &self.password {
Some(p) => rb.bearer_auth(p),
None => rb
}
}
fn build_get(&self, url: &str) -> RequestBuilder {
let rb = self.client.get(self.base_url.join(url).unwrap());
self.set_pwd(rb)
}
fn build_post(&self, url: &str) -> RequestBuilder {
let rb = self.client.post(self.base_url.join(url).unwrap());
self.set_pwd(rb)
}
}
//////////////////
// method basic_path(json/query param; additional_url_param) -> return value
// A - admin only
//////////////////
// client listing (A)
build_handler!(GET get_agents() -> Vec<Agent>);
// get jobs for client (agent_id=Uuid)
build_handler!(GET get_agent_jobs/Uuid() -> Vec<JobMeta>);
// get all available jobs (A)
build_handler!(GET get_jobs/Uuid() -> Vec<JobMeta>);
// add client to server's db
build_handler!(POST init(IAgent) -> String);
// create and upload job (A)
build_handler!(POST upload_jobs(Vec<JobMeta>) -> ());
// delete something (A)
build_handler!(GET del/Uuid() -> ());
// set jobs for client (A)
// POST /set_jobs/Uuid json: Vec<Uuid>
build_handler!(POST set_jobs/Uuid(Vec<Uuid>) -> ());
// get results (A)
// GET /get_job_results/Uuid
build_handler!(GET get_job_results/Uuid() -> Vec<JobResult>);
// report job result
build_handler!(POST report(Vec<JobResult>) -> ());