#[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! get_result { ( () ) => ( |_| async Ok(()) ); ( $result:ty ) => { |response: Response| async { response .json::>() .await .map(|msg| msg.into_item()) .map_err(|e| UError::from(e)) } }; } #[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)?| { let request = ClientHandler::build_post( instance, &format!("{}/{}", stringify!($path), String::new() $(+ stringify!($url_param))? ) ); request $( .json::>(¶m.as_message()) )? } }; ( GET $path:tt, pname = $($param_name:literal)?, ptype = $($param_type:ty)?, urlparam = $($url_param:ty)? ) => { |instance: &ClientHandler $(, param: &$param_type)?| { let request = ClientHandler::build_get( instance, &format!("{}/{}", stringify!($path), String::new() $(+ stringify!($url_param))? ) ); 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( $($param_name:literal:)? $($param_type:ty)? $(; $url_param: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)? ); let response = request.send().await?; ($crate::get_result!($result)(response)).await } } impl Paths { pub const $path: &'static str = stringify!($path); } }; } pub struct ClientHandler { base_url: Url, client: Client, password: Option } impl ClientHandler { pub fn new(server: Option) -> 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 ls() -> ItemWrap>); // get jobs for client himself (A: id=client_id) build_handler!(GET get_jobs() -> ItemWrap>); // add client to server's db build_handler!(POST init(IAgent) -> RawMsg); // create and upload job (A) //build_handler!(POST upload_jobs) // ??? /*build_handler!(POST del() -> ()); // set jobs for client (A) // POST /set_jobs/Uuid json: JobMetaStorage build_handler!(POST set_jobs(JobMetaStorage; Uuid) -> ()); // get results (A) // GET /get_job_results?job_id=Uuid build_handler!(GET get_job_results("job_id":Uuid) -> Vec); // report job result build_handler!(POST report(Vec) -> ()); */