client.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*************************************************************************
  2. *
  3. * Copyright (C) 2018-2025 Ruilin Peng (Nick) <[email protected]>.
  4. *
  5. * smartdns is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * smartdns is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. use http::uri;
  19. use reqwest;
  20. use smartdns_ui::http_api_msg;
  21. use std::{error::Error, net::TcpStream};
  22. use tungstenite::*;
  23. pub struct TestClient {
  24. url: String,
  25. token: Option<http_api_msg::TokenResponse>,
  26. client: reqwest::blocking::Client,
  27. no_auth_header: bool,
  28. }
  29. impl TestClient {
  30. pub fn new(url: &String) -> Self {
  31. let client = TestClient {
  32. url: url.clone(),
  33. token: None,
  34. client: reqwest::blocking::ClientBuilder::new()
  35. .danger_accept_invalid_certs(true)
  36. .build()
  37. .unwrap(),
  38. no_auth_header: false,
  39. };
  40. client
  41. }
  42. #[allow(dead_code)]
  43. pub fn set_with_auth_header(&mut self, with_auth_header: bool) {
  44. self.no_auth_header = with_auth_header;
  45. }
  46. #[allow(dead_code)]
  47. pub fn login(&mut self, username: &str, password: &str) -> Result<String, Box<dyn Error>> {
  48. let url = self.url.clone() + "/api/auth/login";
  49. let body = http_api_msg::api_msg_gen_auth_login(&http_api_msg::AuthUser {
  50. username: username.to_string(),
  51. password: password.to_string(),
  52. });
  53. let resp = self.client.post(&url).body(body).send()?;
  54. if resp.status().as_u16() != 200 {
  55. return Err(resp.text()?.into());
  56. }
  57. let text = resp.text()?;
  58. let token = http_api_msg::api_msg_parse_auth_token(&text)?;
  59. self.token = Some(token);
  60. Ok(text)
  61. }
  62. #[allow(dead_code)]
  63. pub fn logout(&mut self) -> Result<String, Box<dyn Error>> {
  64. let url = self.url.clone() + "/api/auth/logout";
  65. let resp = self.client.post(&url).send()?;
  66. let text = resp.text()?;
  67. self.token = None;
  68. Ok(text)
  69. }
  70. fn prep_request(
  71. &self,
  72. method: reqwest::Method,
  73. path: &str,
  74. ) -> Result<reqwest::blocking::RequestBuilder, Box<dyn Error>> {
  75. let url = self.url.clone() + path;
  76. let mut req = self.client.request(method, url);
  77. if let Some(token) = &self.token {
  78. if self.token.is_some() && !self.no_auth_header {
  79. req = req.header("Authorization", format!("Bearer {}", token.token));
  80. }
  81. }
  82. Ok(req)
  83. }
  84. pub fn get(&self, path: &str) -> Result<(i32, String), Box<dyn Error>> {
  85. let req = self.prep_request(reqwest::Method::GET, path)?;
  86. let resp = req.send()?;
  87. let status = resp.status().as_u16();
  88. let text = resp.text()?;
  89. Ok((status as i32, text))
  90. }
  91. #[allow(dead_code)]
  92. pub fn delete(&self, path: &str) -> Result<(i32, String), Box<dyn Error>> {
  93. let req = self.prep_request(reqwest::Method::DELETE, path)?;
  94. let resp = req.send()?;
  95. let status = resp.status().as_u16();
  96. let text = resp.text()?;
  97. Ok((status as i32, text))
  98. }
  99. #[allow(dead_code)]
  100. pub fn put(&self, path: &str, body: &str) -> Result<(i32, String), Box<dyn Error>> {
  101. let req = self.prep_request(reqwest::Method::PUT, path)?;
  102. let resp = req.body(body.to_string()).send()?;
  103. let status = resp.status().as_u16();
  104. let text = resp.text()?;
  105. Ok((status as i32, text))
  106. }
  107. #[allow(dead_code)]
  108. pub fn post(&self, path: &str, body: &str) -> Result<(i32, String), Box<dyn Error>> {
  109. let req = self.prep_request(reqwest::Method::POST, path)?;
  110. let resp = req.body(body.to_string()).send()?;
  111. let status = resp.status().as_u16();
  112. let text = resp.text()?;
  113. Ok((status as i32, text))
  114. }
  115. #[allow(dead_code)]
  116. pub fn websocket(
  117. &self,
  118. path: &str,
  119. ) -> Result<WebSocket<stream::MaybeTlsStream<TcpStream>>, Box<dyn Error>> {
  120. let url = self.url.clone() + path;
  121. let uri: http::Uri = url.parse()?;
  122. let mut parts = uri.into_parts();
  123. parts.scheme = Some("ws".parse().unwrap());
  124. let uri = uri::Uri::from_parts(parts).unwrap();
  125. let mut request_builder = tungstenite::ClientRequestBuilder::new(uri);
  126. if let Some(token) = &self.token {
  127. if self.token.is_some() {
  128. request_builder =
  129. request_builder.with_header("Authorization", format!("Bearer {}", token.token));
  130. }
  131. }
  132. request_builder = request_builder
  133. .with_header("Upgrade", "websocket")
  134. .with_header("Sec-WebSocket-Version", "13")
  135. .with_header("Connection", "keep-alive, Upgrade");
  136. let ret = tungstenite::connect(request_builder);
  137. if let Err(e) = ret {
  138. println!("websocket connect error: {:?}", e.to_string());
  139. return Err(Box::new(e));
  140. }
  141. let (socket, _) = ret.unwrap();
  142. Ok(socket)
  143. }
  144. }
  145. impl Drop for TestClient {
  146. fn drop(&mut self) {}
  147. }