diff --git a/flutter/lib/models/user_model.dart b/flutter/lib/models/user_model.dart index 04b7ebb5b..6cf4cb152 100644 --- a/flutter/lib/models/user_model.dart +++ b/flutter/lib/models/user_model.dart @@ -9,6 +9,7 @@ import 'package:get/get.dart'; import 'package:http/http.dart' as http; import '../common.dart'; +import '../utils/http_service.dart'; import 'model.dart'; import 'platform_model.dart'; @@ -135,8 +136,8 @@ class UserModel { /// throw [RequestException] Future login(LoginRequest loginRequest) async { final url = await bind.mainGetApiServer(); - final resp = await http.post(Uri.parse('$url/api/login'), - headers: {'Content-Type': 'application/json'}, + final resp = await HttpService().sendRequest( + '$url/api/login', HttpMethod.post, body: jsonEncode(loginRequest.toJson())); final Map body; diff --git a/flutter/lib/utils/http_service.dart b/flutter/lib/utils/http_service.dart new file mode 100644 index 000000000..35bab842a --- /dev/null +++ b/flutter/lib/utils/http_service.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; + +import '../models/platform_model.dart'; + +enum HttpMethod { get, post, put, delete } + +class HttpService { + Future sendRequest( + String url, + HttpMethod method, { + Map? headers, + dynamic body, + }) async { + headers ??= {'Content-Type': 'application/json'}; + String headersJson = jsonEncode(headers); + String methodName = method.toString().split('.').last; + + await bind.mainHttpRequest(url: url, method: methodName.toLowerCase(), body: body, header: headersJson); + + var resJson = await _pollForResponse(); + return _parseHttpResponse(resJson); + } + + Future _pollForResponse() async { + String responseJson = await bind.mainGetAsyncStatus(); + while (responseJson == " ") { + await Future.delayed(const Duration(milliseconds: 100)); + responseJson = await bind.mainGetAsyncStatus(); + } + return responseJson; + } + + http.Response _parseHttpResponse(String responseJson) { + try { + var parsedJson = jsonDecode(responseJson); + String body = parsedJson['body']; + Map headers = {}; + for (var key in parsedJson['headers'].keys) { + headers[key] = parsedJson['headers'][key]; + } + int statusCode = parsedJson['status_code']; + return http.Response(body, statusCode, headers: headers); + } catch (e) { + throw Exception('Failed to parse response: $e'); + } + } +} \ No newline at end of file diff --git a/src/common.rs b/src/common.rs index 199c79834..b565dd5cb 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,3 +1,4 @@ +use serde_json::Value; use std::{ borrow::Cow, future::Future, @@ -1085,6 +1086,62 @@ pub async fn post_request_sync(url: String, body: String, header: &str) -> Resul post_request(url, body, header).await } +#[tokio::main(flavor = "current_thread")] +pub async fn http_request_sync( + url: String, + method: String, + body: String, + header: String, +) -> ResultType { + let http_client = create_http_client_async(); + let mut http_client = match method.as_str() { + "get" => http_client.get(url), + "post" => http_client.post(url), + "put" => http_client.put(url), + "delete" => http_client.delete(url), + _ => return Err(anyhow!("The HTTP request method is not supported!")), + }; + let v = serde_json::from_str(header.as_str())?; + + if let Value::Object(obj) = v { + for (key, value) in obj.iter() { + http_client = http_client.header(key, value.as_str().unwrap_or_default()); + println!("Key: {}, Value: {}", key, value); + } + } else { + return Err(anyhow!("HTTP header information parsing failed!")); + } + + let response = http_client + .body(body) + .timeout(std::time::Duration::from_secs(12)) + .send() + .await?; + + // Serialize response headers + let mut response_headers = serde_json::map::Map::new(); + for (key, value) in response.headers() { + response_headers.insert( + key.to_string(), + serde_json::json!(value.to_str().unwrap_or("")), + ); + } + + let status_code = response.status().as_u16(); + let response_body = response.text().await?; + + // Construct the JSON object + let mut result = serde_json::map::Map::new(); + result.insert("status_code".to_string(), serde_json::json!(status_code)); + result.insert( + "headers".to_string(), + serde_json::Value::Object(response_headers), + ); + result.insert("body".to_string(), serde_json::json!(response_body)); + + // Convert map to JSON string + serde_json::to_string(&result).map_err(|e| anyhow!("Failed to serialize response: {}", e)) +} #[inline] pub fn make_privacy_mode_msg_with_details( state: back_notification::PrivacyModeState, diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index b60be6bff..efc3c3f43 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -874,9 +874,8 @@ pub fn main_get_api_server() -> String { get_api_server() } -// This function doesn't seem to be used. -pub fn main_post_request(url: String, body: String, header: String) { - post_request(url, body, header) +pub fn main_http_request(url: String, method: String, body: String, header: String) { + http_request(url,method, body, header) } pub fn main_get_local_option(key: String) -> SyncReturn { diff --git a/src/ui.rs b/src/ui.rs index f00739a58..c5897b92a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -548,6 +548,10 @@ impl UI { change_id_shared(id, old_id); } + fn http_request(&self, url: String, method: String, body: String, header: String) { + http_request(url, method, body, header) + } + fn post_request(&self, url: String, body: String, header: String) { post_request(url, body, header) } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 152ea7581..87f8b4f7c 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -708,6 +708,18 @@ pub fn change_id(id: String) { }); } +#[inline] +pub fn http_request(url: String, method: String, body: String, header: String) { + *ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned(); + std::thread::spawn(move || { + *ASYNC_JOB_STATUS.lock().unwrap() = + match crate::http_request_sync(url, method, body, header) { + Err(err) => err.to_string(), + Ok(text) => text, + }; + }); +} + #[inline] pub fn post_request(url: String, body: String, header: String) { *ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned();