Skip to main content

storekit/
app_transaction.rs

1use core::ptr;
2
3use serde::Deserialize;
4
5use crate::app_store::{AppStoreEnvironment, AppStorePlatform};
6use crate::error::StoreKitError;
7use crate::ffi;
8use crate::private::{decode_base64, error_from_status, parse_json_ptr};
9use crate::verification_result::{VerificationResult, VerificationResultPayload};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12/// Wraps `StoreKit.AppTransaction`.
13pub struct AppTransaction {
14    /// App identifier reported by `StoreKit`.
15    pub app_id: Option<u64>,
16    /// App transaction identifier reported by `StoreKit`.
17    pub app_transaction_id: String,
18    /// App version reported by `StoreKit`.
19    pub app_version: String,
20    /// App version identifier reported by `StoreKit`.
21    pub app_version_id: Option<u64>,
22    /// Bundle identifier reported by `StoreKit`.
23    pub bundle_id: String,
24    /// Environment reported by `StoreKit`.
25    pub environment: AppStoreEnvironment,
26    /// Original app version reported by `StoreKit`.
27    pub original_app_version: String,
28    /// Original purchase date reported by `StoreKit`.
29    pub original_purchase_date: String,
30    /// Original platform reported by `StoreKit`.
31    pub original_platform: Option<AppStorePlatform>,
32    /// Preorder date reported by `StoreKit`.
33    pub preorder_date: Option<String>,
34    /// Decoded JSON representation returned by `StoreKit`.
35    pub json_representation: Vec<u8>,
36}
37
38impl AppTransaction {
39    /// Fetches `StoreKit.AppTransaction.shared`.
40    pub fn shared() -> Result<VerificationResult<Self>, StoreKitError> {
41        let mut result_json = ptr::null_mut();
42        let mut error_message = ptr::null_mut();
43        let status =
44            unsafe { ffi::sk_app_transaction_shared(&mut result_json, &mut error_message) };
45        if status != ffi::status::OK {
46            return Err(unsafe { error_from_status(status, error_message) });
47        }
48        let payload = unsafe {
49            parse_json_ptr::<VerificationResultPayload<AppTransactionPayload>>(
50                result_json,
51                "app transaction",
52            )
53        }?;
54        payload.into_result(AppTransactionPayload::into_app_transaction)
55    }
56
57    /// Fetches `StoreKit.AppTransaction.refresh()`.
58    pub fn refresh() -> Result<VerificationResult<Self>, StoreKitError> {
59        let mut result_json = ptr::null_mut();
60        let mut error_message = ptr::null_mut();
61        let status =
62            unsafe { ffi::sk_app_transaction_refresh(&mut result_json, &mut error_message) };
63        if status != ffi::status::OK {
64            return Err(unsafe { error_from_status(status, error_message) });
65        }
66        let payload = unsafe {
67            parse_json_ptr::<VerificationResultPayload<AppTransactionPayload>>(
68                result_json,
69                "refreshed app transaction",
70            )
71        }?;
72        payload.into_result(AppTransactionPayload::into_app_transaction)
73    }
74}
75
76#[derive(Debug, Deserialize)]
77pub(crate) struct AppTransactionPayload {
78    #[serde(rename = "appID")]
79    app_id: Option<u64>,
80    #[serde(rename = "appTransactionID")]
81    app_transaction_id: String,
82    #[serde(rename = "appVersion")]
83    app_version: String,
84    #[serde(rename = "appVersionID")]
85    app_version_id: Option<u64>,
86    #[serde(rename = "bundleID")]
87    bundle_id: String,
88    environment: String,
89    #[serde(rename = "originalAppVersion")]
90    original_app_version: String,
91    #[serde(rename = "originalPurchaseDate")]
92    original_purchase_date: String,
93    #[serde(rename = "originalPlatform")]
94    original_platform: Option<String>,
95    #[serde(rename = "preorderDate")]
96    preorder_date: Option<String>,
97    #[serde(rename = "jsonRepresentationBase64")]
98    json_representation_base64: String,
99}
100
101impl AppTransactionPayload {
102    pub(crate) fn into_app_transaction(self) -> Result<AppTransaction, StoreKitError> {
103        Ok(AppTransaction {
104            app_id: self.app_id,
105            app_transaction_id: self.app_transaction_id,
106            app_version: self.app_version,
107            app_version_id: self.app_version_id,
108            bundle_id: self.bundle_id,
109            environment: AppStoreEnvironment::from_raw(self.environment),
110            original_app_version: self.original_app_version,
111            original_purchase_date: self.original_purchase_date,
112            original_platform: self.original_platform.map(AppStorePlatform::from_raw),
113            preorder_date: self.preorder_date,
114            json_representation: decode_base64(
115                &self.json_representation_base64,
116                "app transaction JSON representation",
117            )?,
118        })
119    }
120}