use std::ffi::CStr; use std::os::raw::c_char; use mullvad_api::{ AccountsProxy, rest::{self, MullvadRestHandle}, }; use super::{ SwiftApiContext, cancellation::{RequestCancelHandle, SwiftCancelHandle}, completion::{CompletionCookie, SwiftCompletionHandler}, do_request, do_request_with_empty_body, response::SwiftMullvadApiResponse, retry_strategy::{RetryStrategy, SwiftRetryStrategy}, }; /// # Safety /// /// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created /// by calling `mullvad_api_init_new`. /// /// This function takes ownership of `completion_cookie`, which must be pointing to a valid instance of Swift /// object `MullvadApiCompletion`. The pointer will be freed by calling `mullvad_api_completion_finish` /// when completion finishes (in completion.finish). /// /// `account_number` must be a pointer to a null terminated string. /// /// `retry_strategy` must have been created by a call to either of the following functions /// `mullvad_api_retry_strategy_never`, `mullvad_api_retry_strategy_constant` or `mullvad_api_retry_strategy_exponential` /// /// This function is not safe to call multiple times with the same `CompletionCookie`. #[unsafe(no_mangle)] pub unsafe extern "C" fn mullvad_ios_get_account( api_context: SwiftApiContext, completion_cookie: *mut libc::c_void, retry_strategy: SwiftRetryStrategy, account_number: *const c_char, ) -> SwiftCancelHandle { let completion_handler = SwiftCompletionHandler::new(unsafe { CompletionCookie::new(completion_cookie) }); let Ok(tokio_handle) = crate::mullvad_ios_runtime() else { completion_handler.finish(SwiftMullvadApiResponse::no_tokio_runtime()); return SwiftCancelHandle::empty(); }; let api_context = api_context.rust_context(); // SAFETY: See documentation for `into_rust` let retry_strategy = unsafe { retry_strategy.into_rust() }; // SAFETY: See param documentation for `account_number`. let account_number = unsafe { CStr::from_ptr(account_number.cast()) } .to_str() .unwrap(); let account_number = String::from(account_number); let completion = completion_handler.clone(); let task = tokio_handle.clone().spawn(async move { match mullvad_ios_get_account_inner( api_context.rest_handle(), retry_strategy, account_number, ) .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() } /// # Safety /// /// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created /// by calling `mullvad_api_init_new`. /// /// This function takes ownership of `completion_cookie`, which must be pointing to a valid instance of Swift /// object `MullvadApiCompletion`. The pointer will be freed by calling `mullvad_api_completion_finish` /// when completion finishes (in completion.finish). /// /// `retry_strategy` must have been created by a call to either of the following functions /// `mullvad_api_retry_strategy_never`, `mullvad_api_retry_strategy_constant` or `mullvad_api_retry_strategy_exponential` /// /// This function is not safe to call multiple times with the same `CompletionCookie`. #[unsafe(no_mangle)] pub unsafe extern "C" fn mullvad_ios_create_account( api_context: SwiftApiContext, completion_cookie: *mut libc::c_void, retry_strategy: SwiftRetryStrategy, ) -> SwiftCancelHandle { let completion_handler = SwiftCompletionHandler::new(unsafe { CompletionCookie::new(completion_cookie) }); let Ok(tokio_handle) = crate::mullvad_ios_runtime() else { completion_handler.finish(SwiftMullvadApiResponse::no_tokio_runtime()); return SwiftCancelHandle::empty(); }; let api_context = api_context.rust_context(); // SAFETY: See notes for `into_rust` let retry_strategy = unsafe { retry_strategy.into_rust() }; let completion = completion_handler.clone(); let task = tokio_handle.clone().spawn(async move { match mullvad_ios_create_account_inner(api_context.rest_handle(), retry_strategy).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() } /// # Safety /// /// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created /// by calling `mullvad_api_init_new`. /// /// This function takes ownership of `completion_cookie`, which must be pointing to a valid instance of Swift /// object `MullvadApiCompletion`. The pointer will be freed by calling `mullvad_api_completion_finish` /// when completion finishes (in completion.finish). /// /// `account_number` must be a pointer to a null terminated string. /// /// `retry_strategy` must have been created by a call to either of the following functions /// `mullvad_api_retry_strategy_never`, `mullvad_api_retry_strategy_constant` or `mullvad_api_retry_strategy_exponential` /// /// This function is not safe to call multiple times with the same `CompletionCookie`. #[unsafe(no_mangle)] pub unsafe extern "C" fn mullvad_ios_delete_account( api_context: SwiftApiContext, completion_cookie: *mut libc::c_void, retry_strategy: SwiftRetryStrategy, account_number: *const c_char, ) -> SwiftCancelHandle { let completion_handler = SwiftCompletionHandler::new(unsafe { CompletionCookie::new(completion_cookie) }); let Ok(tokio_handle) = crate::mullvad_ios_runtime() else { completion_handler.finish(SwiftMullvadApiResponse::no_tokio_runtime()); return SwiftCancelHandle::empty(); }; let api_context = api_context.rust_context(); // SAFETY: See notes for `into_rust` let retry_strategy = unsafe { retry_strategy.into_rust() }; // SAFETY: See param documentation for `account_number`. let account_number = unsafe { CStr::from_ptr(account_number.cast()) } .to_str() .unwrap(); let account_number = String::from(account_number); let completion = completion_handler.clone(); let task = tokio_handle.clone().spawn(async move { match mullvad_ios_delete_account_inner( api_context.rest_handle(), retry_strategy, account_number, ) .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_ios_get_account_inner( rest_client: MullvadRestHandle, retry_strategy: RetryStrategy, account_number: String, ) -> Result { let api = AccountsProxy::new(rest_client); let future_factory = || api.get_data_response(account_number.clone()); do_request(retry_strategy, future_factory).await } async fn mullvad_ios_create_account_inner( rest_client: MullvadRestHandle, retry_strategy: RetryStrategy, ) -> Result { let api = AccountsProxy::new(rest_client); let future_factory = || api.create_account_response(); do_request(retry_strategy, future_factory).await } async fn mullvad_ios_delete_account_inner( rest_client: MullvadRestHandle, retry_strategy: RetryStrategy, account_number: String, ) -> Result { let api = AccountsProxy::new(rest_client); let future_factory = || api.delete_account(account_number.clone()); do_request_with_empty_body(retry_strategy, future_factory).await }