use crate::{ MASTER_SERVER, MASTER_PORT, contracts::*, UResult, UError }; use reqwest::{ Client, Url, Response, RequestBuilder }; use std::{ net::Ipv4Addr, str::FromStr }; pub struct Paths; impl Paths { pub const LIST: &'static str = "list"; pub const NEW: &'static str = "new"; //pub const DEL: &'static str = "del"; pub const JOB_REQ: &'static str = "job_req"; pub const JOB_ANS: &'static str = "job_ans"; } 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) } pub async fn init(&self, param: &ClientInfo) -> UResult { let response: Response = self.build_post(Paths::NEW) .json::>(¶m.as_message()) .send() .await?; let msg = response .json::>() .await?; Ok(msg.into_item().into_owned()) } pub async fn list(&self) -> UResult> { let response: Response = self.build_get(Paths::LIST) .send() .await?; let msg = response .json::>>() .await?; Ok(msg.into_item().into_owned()) } /* pub async fn del(&self) -> UResult<()> { self.build_post(Paths::DEL).send().await?; Ok(()) }*/ } #[macro_export] macro_rules! epilogue { ( () ) => ( |_| async Ok(()) ); ( $result:ty ) => { |response: Response| async { response .json::>() .await .map(|msg| msg.into_item().into_owned()) .map_err(|e| UError::from(e)) } }; } // build_handler![path = new, method = "post", param = ClientInfo, result = RawMsg] // param and result must impl ToMsg #[macro_export] macro_rules! build_handler { ( path = $path:tt, method = $method:literal, param = $($param:ty)?, result = $result:ty ) => { impl ClientHandler { pub async fn $path(&self $(, param: &$param)?) -> UResult<$result> { let builder = match $method { "post" => ClientHandler::build_post, "get" => ClientHandler::build_get, _ => panic!("Method '{}' is not allowed", $method) }; let mut request = builder(self, stringify!($path)); request = request $(.json::>(¶m.as_message()))?; let response = request.send().await?; ($crate::epilogue!($result)(response)).await } } impl Paths { pub const $path: &'static str = stringify!($path); } }; ( path = $path:tt, method = $method:literal ) => ( build_handler!(path = $path, method = $method, param = , result = ()); ); ( path = $path:tt, method = $method:literal, param = $param:ty ) => ( build_handler!(path = $path, method = $method, param = $param, result = ()); ); ( path = $path:tt, method = $method:literal, result = $result:ty ) => ( build_handler!(path = $path, method = $method, param = , result = $result); ); } build_handler!(path = del, method = "post");