diff options
| author | Steffen Ernst <steffen.ernst@mullvad.net> | 2025-02-24 10:25:13 +0100 |
|---|---|---|
| committer | Steffen Ernst <steffen.ernst@mullvad.net> | 2025-02-24 10:26:51 +0100 |
| commit | 9da84278bc001e189b837ab69e79f500b279f002 (patch) | |
| tree | 1483f1e6ae19c212f16949046de4784039692299 | |
| parent | fe84f5813e6bd8e2a3b870cd5cb8be8bc3bd2b34 (diff) | |
| download | mullvadvpn-mullvad-api-storekit2.tar.xz mullvadvpn-mullvad-api-storekit2.zip | |
Move storekit functions into separate modulemullvad-api-storekit2
| -rw-r--r-- | mullvad-ios/src/api_client/api.rs | 163 | ||||
| -rw-r--r-- | mullvad-ios/src/api_client/mod.rs | 1 | ||||
| -rw-r--r-- | mullvad-ios/src/api_client/storekit.rs | 179 |
3 files changed, 180 insertions, 163 deletions
diff --git a/mullvad-ios/src/api_client/api.rs b/mullvad-ios/src/api_client/api.rs index 1758a54300..79c1a1f744 100644 --- a/mullvad-ios/src/api_client/api.rs +++ b/mullvad-ios/src/api_client/api.rs @@ -70,166 +70,3 @@ async fn mullvad_api_get_addresses_inner( SwiftMullvadApiResponse::with_body(response).await } - -/// # Safety -/// -/// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created -/// by calling `mullvad_api_init_new`. -/// -/// `completion_cookie` must be pointing to a valid instance of `CompletionCookie`. `CompletionCookie` is -/// safe because the pointer in `MullvadApiCompletion` is valid for the lifetime of the process where this -/// type is intended to be used. -/// -/// `account` must be a pointer to a null terminated string to the account number -/// -/// This function is not safe to call multiple times with the same `CompletionCookie`. -#[no_mangle] -pub unsafe extern "C" fn mullvad_api_init_storekit_payment( - api_context: SwiftApiContext, - completion_cookie: *mut libc::c_void, - retry_strategy: SwiftRetryStrategy, - account: *const u8, -) -> SwiftCancelHandle { - let completion_handler = SwiftCompletionHandler::new(CompletionCookie(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.into_rust_context(); - let retry_strategy = unsafe { retry_strategy.into_rust() }; - - let completion = completion_handler.clone(); - - let account = unsafe { std::ffi::CStr::from_ptr(account.cast()) }; - let Ok(account) = account.to_str() else { - completion_handler.finish(SwiftMullvadApiResponse::invalid_input( - c"Invalid account string", - )); - return SwiftCancelHandle::empty(); - }; - let account = AccountNumber::from(account); - - let task = tokio_handle.clone().spawn(async move { - match mullvad_api_init_storekit_payment_inner( - api_context.rest_handle(), - retry_strategy, - account, - ) - .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_init_storekit_payment_inner( - rest_client: MullvadRestHandle, - retry_strategy: RetryStrategy, - account: AccountNumber, -) -> Result<SwiftMullvadApiResponse, rest::Error> { - let account_proxy = AccountsProxy::new(rest_client); - - let future_factory = || account_proxy.init_storekit_payment(account.clone()); - - 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 -} - -/// # Safety -/// -/// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created -/// by calling `mullvad_api_init_new`. -/// -/// `completion_cookie` must be pointing to a valid instance of `CompletionCookie`. `CompletionCookie` is -/// safe because the pointer in `MullvadApiCompletion` is valid for the lifetime of the process where this -/// type is intended to be used. -/// -/// `account` must be a pointer to a null terminated string to the account number -/// -/// `transaction` must be a pointer to a null terminated string to the jws representation of the transaction -/// -/// This function is not safe to call multiple times with the same `CompletionCookie`. -#[no_mangle] -pub unsafe extern "C" fn mullvad_api_check_storekit_payment( - api_context: SwiftApiContext, - completion_cookie: *mut libc::c_void, - retry_strategy: SwiftRetryStrategy, - account: *const u8, - body: *const u8, - body_size: usize, -) -> SwiftCancelHandle { - let completion_handler = SwiftCompletionHandler::new(CompletionCookie(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.into_rust_context(); - let retry_strategy = unsafe { retry_strategy.into_rust() }; - - let completion = completion_handler.clone(); - - let account = unsafe { std::ffi::CStr::from_ptr(account.cast()) }; - let Ok(account) = account.to_str() else { - completion_handler.finish(SwiftMullvadApiResponse::invalid_input( - c"Invalid account string", - )); - return SwiftCancelHandle::empty(); - }; - let account = AccountNumber::from(account); - - let body = unsafe { std::slice::from_raw_parts(body, body_size) }.to_vec(); - let task = tokio_handle.clone().spawn(async move { - match mullvad_api_check_storekit_payment_inner( - api_context.rest_handle(), - retry_strategy, - account, - body, - ) - .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_check_storekit_payment_inner( - rest_client: MullvadRestHandle, - retry_strategy: RetryStrategy, - account: AccountNumber, - body: Vec<u8>, -) -> Result<SwiftMullvadApiResponse, rest::Error> { - let account_proxy = AccountsProxy::new(rest_client); - - let future_factory = || account_proxy.check_storekit_payment(account.clone(), body.clone()); - - 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 -} diff --git a/mullvad-ios/src/api_client/mod.rs b/mullvad-ios/src/api_client/mod.rs index 98443fd0d9..7314af2fe1 100644 --- a/mullvad-ios/src/api_client/mod.rs +++ b/mullvad-ios/src/api_client/mod.rs @@ -11,6 +11,7 @@ mod cancellation; mod completion; mod response; mod retry_strategy; +mod storekit; #[repr(C)] pub struct SwiftApiContext(*const ApiContext); diff --git a/mullvad-ios/src/api_client/storekit.rs b/mullvad-ios/src/api_client/storekit.rs new file mode 100644 index 0000000000..9e91ed0398 --- /dev/null +++ b/mullvad-ios/src/api_client/storekit.rs @@ -0,0 +1,179 @@ +use mullvad_api::{ + rest::{self, MullvadRestHandle}, + AccountsProxy, +}; +use mullvad_types::account::AccountNumber; +use talpid_future::retry::retry_future; + +use super::{ + cancellation::{RequestCancelHandle, SwiftCancelHandle}, + completion::{CompletionCookie, SwiftCompletionHandler}, + response::SwiftMullvadApiResponse, + retry_strategy::{RetryStrategy, SwiftRetryStrategy}, + SwiftApiContext, +}; + +/// # Safety +/// +/// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created +/// by calling `mullvad_api_init_new`. +/// +/// `completion_cookie` must be pointing to a valid instance of `CompletionCookie`. `CompletionCookie` is +/// safe because the pointer in `MullvadApiCompletion` is valid for the lifetime of the process where this +/// type is intended to be used. +/// +/// `account` must be a pointer to a null terminated string to the account number +/// +/// This function is not safe to call multiple times with the same `CompletionCookie`. +#[no_mangle] +pub unsafe extern "C" fn mullvad_api_init_storekit_payment( + api_context: SwiftApiContext, + completion_cookie: *mut libc::c_void, + retry_strategy: SwiftRetryStrategy, + account: *const u8, +) -> SwiftCancelHandle { + let completion_handler = SwiftCompletionHandler::new(CompletionCookie(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.into_rust_context(); + let retry_strategy = unsafe { retry_strategy.into_rust() }; + + let completion = completion_handler.clone(); + + let account = unsafe { std::ffi::CStr::from_ptr(account.cast()) }; + let Ok(account) = account.to_str() else { + completion_handler.finish(SwiftMullvadApiResponse::invalid_input( + c"Invalid account string", + )); + return SwiftCancelHandle::empty(); + }; + let account = AccountNumber::from(account); + + let task = tokio_handle.clone().spawn(async move { + match mullvad_api_init_storekit_payment_inner( + api_context.rest_handle(), + retry_strategy, + account, + ) + .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_init_storekit_payment_inner( + rest_client: MullvadRestHandle, + retry_strategy: RetryStrategy, + account: AccountNumber, +) -> Result<SwiftMullvadApiResponse, rest::Error> { + let account_proxy = AccountsProxy::new(rest_client); + + let future_factory = || account_proxy.init_storekit_payment(account.clone()); + + 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 +} + +/// # Safety +/// +/// `api_context` must be pointing to a valid instance of `SwiftApiContext`. A `SwiftApiContext` is created +/// by calling `mullvad_api_init_new`. +/// +/// `completion_cookie` must be pointing to a valid instance of `CompletionCookie`. `CompletionCookie` is +/// safe because the pointer in `MullvadApiCompletion` is valid for the lifetime of the process where this +/// type is intended to be used. +/// +/// `account` must be a pointer to a null terminated string to the account number +/// +/// `body` must be a pointer to the body content +/// +/// `body_size` must be the size of the body +/// +/// This function is not safe to call multiple times with the same `CompletionCookie`. +#[no_mangle] +pub unsafe extern "C" fn mullvad_api_check_storekit_payment( + api_context: SwiftApiContext, + completion_cookie: *mut libc::c_void, + retry_strategy: SwiftRetryStrategy, + account: *const u8, + body: *const u8, + body_size: usize, +) -> SwiftCancelHandle { + let completion_handler = SwiftCompletionHandler::new(CompletionCookie(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.into_rust_context(); + let retry_strategy = unsafe { retry_strategy.into_rust() }; + + let completion = completion_handler.clone(); + + let account = unsafe { std::ffi::CStr::from_ptr(account.cast()) }; + let Ok(account) = account.to_str() else { + completion_handler.finish(SwiftMullvadApiResponse::invalid_input( + c"Invalid account string", + )); + return SwiftCancelHandle::empty(); + }; + let account = AccountNumber::from(account); + + let body = unsafe { std::slice::from_raw_parts(body, body_size) }.to_vec(); + let task = tokio_handle.clone().spawn(async move { + match mullvad_api_check_storekit_payment_inner( + api_context.rest_handle(), + retry_strategy, + account, + body, + ) + .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_check_storekit_payment_inner( + rest_client: MullvadRestHandle, + retry_strategy: RetryStrategy, + account: AccountNumber, + body: Vec<u8>, +) -> Result<SwiftMullvadApiResponse, rest::Error> { + let account_proxy = AccountsProxy::new(rest_client); + + let future_factory = || account_proxy.check_storekit_payment(account.clone(), body.clone()); + + 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 +} |
