1
+ use mullvad_api:: {
2
+ rest:: { self , MullvadRestHandle } ,
3
+ ProblemReportProxy ,
4
+ } ;
5
+ use talpid_future:: retry:: retry_future;
6
+
7
+ use super :: {
8
+ cancellation:: { RequestCancelHandle , SwiftCancelHandle } ,
9
+ completion:: { CompletionCookie , SwiftCompletionHandler } ,
10
+ response:: SwiftMullvadApiResponse ,
11
+ retry_strategy:: { RetryStrategy , SwiftRetryStrategy } ,
12
+ SwiftApiContext ,
13
+ } ;
14
+
15
+ use mullvad_api:: rest:: Error ;
16
+ use std:: { collections:: BTreeMap } ;
17
+ use std:: slice;
18
+ use tokio:: task:: JoinHandle ;
19
+
20
+ #[ no_mangle]
21
+ pub unsafe extern "C" fn mullvad_api_send_problem_report (
22
+ api_context : SwiftApiContext ,
23
+ completion_cookie : * mut libc:: c_void ,
24
+ retry_strategy : SwiftRetryStrategy ,
25
+ request : * const SwiftProblemReportRequest ,
26
+ ) -> SwiftCancelHandle {
27
+ let completion_handler = SwiftCompletionHandler :: new ( CompletionCookie ( completion_cookie) ) ;
28
+ let completion = completion_handler. clone ( ) ;
29
+
30
+ let Ok ( tokio_handle) = crate :: mullvad_ios_runtime ( ) else {
31
+ completion_handler. finish ( SwiftMullvadApiResponse :: no_tokio_runtime ( ) ) ;
32
+ return SwiftCancelHandle :: empty ( ) ;
33
+ } ;
34
+
35
+ let api_context = api_context. into_rust_context ( ) ;
36
+ let retry_strategy = unsafe { retry_strategy. into_rust ( ) } ;
37
+
38
+ let problem_report_request = match unsafe { ProblemReportRequest :: from_swift_parameters ( request) } {
39
+ Some ( req) => req,
40
+ None => {
41
+ let err = Error :: ApiError ( rest:: StatusCode :: BAD_REQUEST , "Failed to send problem report: invalid address, message, or log data." . to_string ( ) ) ;
42
+ log:: error!( "{err:?}" ) ;
43
+ completion. finish ( SwiftMullvadApiResponse :: rest_error ( err) ) ;
44
+ return SwiftCancelHandle :: empty ( ) ;
45
+ }
46
+ } ;
47
+
48
+ let task: JoinHandle < ( ) > = tokio_handle. spawn ( async move {
49
+ match mullvad_api_send_problem_report_inner (
50
+ api_context. rest_handle ( ) ,
51
+ retry_strategy,
52
+ problem_report_request,
53
+ )
54
+ . await
55
+ {
56
+ Ok ( response) => completion. finish ( response) ,
57
+ Err ( err) => {
58
+ log:: error!( "{err:?}" ) ;
59
+ completion. finish ( SwiftMullvadApiResponse :: rest_error ( err) ) ;
60
+ }
61
+ }
62
+ } ) ;
63
+
64
+ RequestCancelHandle :: new ( task, completion_handler. clone ( ) ) . into_swift ( )
65
+ }
66
+
67
+ async fn mullvad_api_send_problem_report_inner (
68
+ rest_client : MullvadRestHandle ,
69
+ retry_strategy : RetryStrategy ,
70
+ problem_report_request : ProblemReportRequest ,
71
+ ) -> Result < SwiftMullvadApiResponse , rest:: Error > {
72
+ let api = ProblemReportProxy :: new ( rest_client) ;
73
+ let empty_metadata: BTreeMap < String , String > = BTreeMap :: new ( ) ;
74
+
75
+ 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) ;
76
+
77
+ let should_retry = |result : & Result < _ , rest:: Error > | match result {
78
+ Err ( err) => err. is_network_error ( ) ,
79
+ Ok ( _) => false ,
80
+ } ;
81
+
82
+ let response = retry_future ( future_factory, should_retry, retry_strategy. delays ( ) ) . await ?;
83
+ SwiftMullvadApiResponse :: with_body ( response) . await
84
+
85
+ }
86
+
87
+ #[ repr( C ) ]
88
+ pub struct SwiftProblemReportRequest {
89
+ address : * const u8 ,
90
+ address_len : usize ,
91
+ message : * const u8 ,
92
+ message_len : usize ,
93
+ log : * const u8 ,
94
+ log_len : usize ,
95
+ }
96
+
97
+ struct ProblemReportRequest {
98
+ address : String ,
99
+ message : String ,
100
+ log : Vec < u8 > ,
101
+ }
102
+
103
+
104
+ unsafe impl Send for SwiftProblemReportRequest { }
105
+
106
+ impl ProblemReportRequest {
107
+ unsafe fn from_swift_parameters ( request : * const SwiftProblemReportRequest ) -> Option < Self > {
108
+ if request. is_null ( ) {
109
+ return None ;
110
+ }
111
+
112
+ let request = & * request; // Dereference the pointer
113
+
114
+ let address_slice = slice:: from_raw_parts ( request. address , request. address_len ) ;
115
+ let message_slice = slice:: from_raw_parts ( request. message , request. message_len ) ;
116
+ let log_slice = slice:: from_raw_parts ( request. log , request. log_len ) ;
117
+
118
+ let address = String :: from_utf8 ( address_slice. to_vec ( ) ) . ok ( ) ?;
119
+ let message = String :: from_utf8 ( message_slice. to_vec ( ) ) . ok ( ) ?;
120
+ let log = log_slice. to_vec ( ) ;
121
+
122
+ Some ( Self { address, message, log } )
123
+ }
124
+ }
0 commit comments