summaryrefslogtreecommitdiffhomepage
path: root/mullvad-ios/src/api_client/storekit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mullvad-ios/src/api_client/storekit.rs')
-rw-r--r--mullvad-ios/src/api_client/storekit.rs179
1 files changed, 179 insertions, 0 deletions
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
+}