summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authormojganii <mojgan.jelodar@codic.se>2025-03-18 17:05:17 +0100
committermojganii <mojgan.jelodar@codic.se>2025-04-15 15:38:45 +0200
commit59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9 (patch)
treea4acf78d94df4d9762d7713790122815e06a64ac
parenteffafb699b8f6831cbc6df0bcaa51766d9a44718 (diff)
downloadmullvadvpn-59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9.tar.xz
mullvadvpn-59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9.zip
Implement mullvad_api_send_problem_report in Rust
-rw-r--r--ios/MullvadRustRuntime/include/mullvad_rust_runtime.h14
-rw-r--r--mullvad-api/src/lib.rs18
-rw-r--r--mullvad-ios/src/api_client/mod.rs1
-rw-r--r--mullvad-ios/src/api_client/response.rs1
-rw-r--r--mullvad-ios/src/api_client/send_problem_report.rs124
5 files changed, 156 insertions, 2 deletions
diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h
index 12ce0fd4c0..77dac6b4da 100644
--- a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h
+++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h
@@ -54,6 +54,15 @@ typedef struct CompletionCookie {
void *inner;
} CompletionCookie;
+typedef struct SwiftProblemReportRequest {
+ const uint8_t *address;
+ uintptr_t address_len;
+ const uint8_t *message;
+ uintptr_t message_len;
+ const uint8_t *log;
+ uintptr_t log_len;
+} SwiftProblemReportRequest;
+
typedef struct ProxyHandle {
void *context;
uint16_t port;
@@ -258,6 +267,11 @@ struct SwiftRetryStrategy mullvad_api_retry_strategy_exponential(uintptr_t max_r
uint32_t factor,
uint64_t max_delay_sec);
+struct SwiftCancelHandle mullvad_api_send_problem_report(struct SwiftApiContext api_context,
+ void *completion_cookie,
+ struct SwiftRetryStrategy retry_strategy,
+ const struct SwiftProblemReportRequest *request);
+
/**
* Initializes a valid pointer to an instance of `EncryptedDnsProxyState`.
*
diff --git a/mullvad-api/src/lib.rs b/mullvad-api/src/lib.rs
index 2d2814d099..987098c591 100644
--- a/mullvad-api/src/lib.rs
+++ b/mullvad-api/src/lib.rs
@@ -687,6 +687,21 @@ impl ProblemReportProxy {
log: &str,
metadata: &BTreeMap<String, String>,
) -> impl Future<Output = Result<(), rest::Error>> {
+ let future = self.porblem_report_response(email, message, log, metadata);
+
+ async move {
+ future.await?;
+ Ok(())
+ }
+ }
+
+ pub fn porblem_report_response(
+ &self,
+ email: &str,
+ message: &str,
+ log: &str,
+ metadata: &BTreeMap<String, String>,
+ ) -> impl Future<Output = Result<rest::Response<Incoming>, rest::Error>> {
#[derive(serde::Serialize)]
struct ProblemReport {
address: String,
@@ -709,8 +724,7 @@ impl ProblemReportProxy {
let request = factory
.post_json(&format!("{APP_URL_PREFIX}/problem-report"), &report)?
.expected_status(&[StatusCode::NO_CONTENT]);
- service.request(request).await?;
- Ok(())
+ service.request(request).await
}
}
}
diff --git a/mullvad-ios/src/api_client/mod.rs b/mullvad-ios/src/api_client/mod.rs
index fd9fde7aa7..234724530e 100644
--- a/mullvad-ios/src/api_client/mod.rs
+++ b/mullvad-ios/src/api_client/mod.rs
@@ -15,6 +15,7 @@ mod cancellation;
mod completion;
mod response;
mod retry_strategy;
+mod send_problem_report;
#[repr(C)]
pub struct SwiftApiContext(*const ApiContext);
diff --git a/mullvad-ios/src/api_client/response.rs b/mullvad-ios/src/api_client/response.rs
index 3b017e37c6..90f1552ffd 100644
--- a/mullvad-ios/src/api_client/response.rs
+++ b/mullvad-ios/src/api_client/response.rs
@@ -8,6 +8,7 @@ use mullvad_api::{
RelayListProxy, StatusCode,
};
+
#[repr(C)]
pub struct SwiftMullvadApiResponse {
body: *mut u8,
diff --git a/mullvad-ios/src/api_client/send_problem_report.rs b/mullvad-ios/src/api_client/send_problem_report.rs
new file mode 100644
index 0000000000..f96f8926d2
--- /dev/null
+++ b/mullvad-ios/src/api_client/send_problem_report.rs
@@ -0,0 +1,124 @@
+use mullvad_api::{
+ rest::{self, MullvadRestHandle},
+ ProblemReportProxy,
+};
+use talpid_future::retry::retry_future;
+
+use super::{
+ cancellation::{RequestCancelHandle, SwiftCancelHandle},
+ completion::{CompletionCookie, SwiftCompletionHandler},
+ response::SwiftMullvadApiResponse,
+ retry_strategy::{RetryStrategy, SwiftRetryStrategy},
+ SwiftApiContext,
+};
+
+use mullvad_api::rest::Error;
+use std::{collections::BTreeMap};
+use std::slice;
+use tokio::task::JoinHandle;
+
+#[no_mangle]
+pub unsafe extern "C" fn mullvad_api_send_problem_report(
+ api_context: SwiftApiContext,
+ completion_cookie: *mut libc::c_void,
+ retry_strategy: SwiftRetryStrategy,
+ request: *const SwiftProblemReportRequest,
+) -> SwiftCancelHandle {
+ let completion_handler = SwiftCompletionHandler::new(CompletionCookie(completion_cookie));
+ let completion = completion_handler.clone();
+
+ let Ok(tokio_handle) = crate::mullvad_ios_runtime() else {
+ completion_handler.finish(SwiftMullvadApiResponse::no_tokio_runtime());
+ return SwiftCancelHandle::empty();
+ };
+
+ let api_context = api_context.into_rust_context();
+ let retry_strategy = unsafe { retry_strategy.into_rust() };
+
+ let problem_report_request = match unsafe { ProblemReportRequest::from_swift_parameters(request) } {
+ Some(req) => req,
+ None => {
+ let err = Error::ApiError(rest::StatusCode::BAD_REQUEST, "Failed to send problem report: invalid address, message, or log data.".to_string());
+ log::error!("{err:?}");
+ completion.finish(SwiftMullvadApiResponse::rest_error(err));
+ return SwiftCancelHandle::empty();
+ }
+ };
+
+ let task: JoinHandle<()> = tokio_handle.spawn(async move {
+ match mullvad_api_send_problem_report_inner(
+ api_context.rest_handle(),
+ retry_strategy,
+ problem_report_request,
+ )
+ .await
+ {
+ Ok(response) => completion.finish(response),
+ Err(err) => {
+ log::error!("{err:?}");
+ completion.finish(SwiftMullvadApiResponse::rest_error(err));
+ }
+ }
+ });
+
+ RequestCancelHandle::new(task, completion_handler.clone()).into_swift()
+}
+
+async fn mullvad_api_send_problem_report_inner(
+ rest_client: MullvadRestHandle,
+ retry_strategy: RetryStrategy,
+ problem_report_request: ProblemReportRequest,
+) -> Result<SwiftMullvadApiResponse, rest::Error> {
+ let api = ProblemReportProxy::new(rest_client);
+ let empty_metadata: BTreeMap<String, String> = BTreeMap::new();
+
+ let future_factory = || api.porblem_report_response(&problem_report_request.address, &problem_report_request.message, &(String::from_utf8_lossy(&problem_report_request.log)), &empty_metadata);
+
+ let should_retry = |result: &Result<_, rest::Error>| match result {
+ Err(err) => err.is_network_error(),
+ Ok(_) => false,
+ };
+
+ let response = retry_future(future_factory, should_retry, retry_strategy.delays()).await?;
+ SwiftMullvadApiResponse::with_body(response).await
+
+}
+
+#[repr(C)]
+pub struct SwiftProblemReportRequest {
+ address: *const u8,
+ address_len: usize,
+ message: *const u8,
+ message_len: usize,
+ log: *const u8,
+ log_len: usize,
+}
+
+struct ProblemReportRequest {
+ address: String,
+ message: String,
+ log: Vec<u8>,
+}
+
+
+unsafe impl Send for SwiftProblemReportRequest {}
+
+impl ProblemReportRequest {
+ unsafe fn from_swift_parameters(request: *const SwiftProblemReportRequest) -> Option<Self> {
+ if request.is_null() {
+ return None;
+ }
+
+ let request = &*request; // Dereference the pointer
+
+ let address_slice = slice::from_raw_parts(request.address, request.address_len);
+ let message_slice = slice::from_raw_parts(request.message, request.message_len);
+ let log_slice = slice::from_raw_parts(request.log, request.log_len);
+
+ let address = String::from_utf8(address_slice.to_vec()).ok()?;
+ let message = String::from_utf8(message_slice.to_vec()).ok()?;
+ let log = log_slice.to_vec();
+
+ Some(Self { address, message, log })
+ }
+} \ No newline at end of file