Skip to main content

tapsdk_pc/
cloudsave.rs

1//! Cloud save functionality
2
3use std::ffi::CString;
4use std::path::Path;
5
6use crate::error::{CloudSaveResult, Result, TapSdkError};
7use crate::sdk::is_initialized;
8
9/// Cloud save API handle
10///
11/// This struct provides access to cloud save functionality.
12/// Get an instance via `CloudSave::get()`.
13pub struct CloudSave {
14    handle: *mut tapsdk_pc_sys::ITapCloudSave,
15}
16
17// The ITapCloudSave pointer is thread-safe according to the SDK documentation
18unsafe impl Send for CloudSave {}
19unsafe impl Sync for CloudSave {}
20
21impl CloudSave {
22    /// Get the cloud save singleton instance
23    ///
24    /// # Returns
25    /// A `CloudSave` instance, or `None` if the SDK is not initialized
26    pub fn get() -> Option<Self> {
27        if !is_initialized() {
28            return None;
29        }
30
31        let handle = unsafe { tapsdk_pc_sys::TapCloudSave() };
32
33        if handle.is_null() {
34            None
35        } else {
36            Some(CloudSave { handle })
37        }
38    }
39
40    /// Request the list of cloud saves
41    ///
42    /// The result will be delivered via the `CloudSaveList` event
43    /// when calling `TapSdk::run_callbacks()`.
44    ///
45    /// # Arguments
46    /// * `request_id` - A unique ID to identify this request in the callback
47    pub fn list(&self, request_id: i64) -> Result<()> {
48        let result = unsafe { tapsdk_pc_sys::TapCloudSave_AsyncList(self.handle, request_id) };
49
50        check_cloudsave_result(result)
51    }
52
53    /// Create a new cloud save
54    ///
55    /// The result will be delivered via the `CloudSaveCreate` event
56    /// when calling `TapSdk::run_callbacks()`.
57    ///
58    /// # Arguments
59    /// * `request_id` - A unique ID to identify this request in the callback
60    /// * `request` - The create request parameters
61    pub fn create(&self, request_id: i64, request: &CreateSaveRequest) -> Result<()> {
62        let name_c = CString::new(request.name.as_str())?;
63        let summary_c = CString::new(request.summary.as_str())?;
64        let extra_c = request
65            .extra
66            .as_ref()
67            .map(|s| CString::new(s.as_str()))
68            .transpose()?;
69        let data_path_c = CString::new(request.data_file_path.to_string_lossy().as_ref())?;
70        let cover_path_c = request
71            .cover_file_path
72            .as_ref()
73            .map(|p| CString::new(p.to_string_lossy().as_ref()))
74            .transpose()?;
75
76        let raw_request = tapsdk_pc_sys::TapCloudSaveCreateRequest {
77            name: name_c.as_ptr(),
78            summary: summary_c.as_ptr(),
79            extra: extra_c
80                .as_ref()
81                .map(|s| s.as_ptr())
82                .unwrap_or(std::ptr::null()),
83            playtime: request.playtime,
84            data_file_path: data_path_c.as_ptr(),
85            cover_file_path: cover_path_c
86                .as_ref()
87                .map(|s| s.as_ptr())
88                .unwrap_or(std::ptr::null()),
89            __bindgen_padding_0: Default::default(),
90        };
91
92        let result = unsafe {
93            tapsdk_pc_sys::TapCloudSave_AsyncCreate(self.handle, request_id, &raw_request)
94        };
95
96        check_cloudsave_result(result)
97    }
98
99    /// Update an existing cloud save
100    ///
101    /// The result will be delivered via the `CloudSaveUpdate` event
102    /// when calling `TapSdk::run_callbacks()`.
103    ///
104    /// # Arguments
105    /// * `request_id` - A unique ID to identify this request in the callback
106    /// * `request` - The update request parameters
107    pub fn update(&self, request_id: i64, request: &UpdateSaveRequest) -> Result<()> {
108        let uuid_c = CString::new(request.uuid.as_str())?;
109        let name_c = CString::new(request.name.as_str())?;
110        let summary_c = CString::new(request.summary.as_str())?;
111        let extra_c = request
112            .extra
113            .as_ref()
114            .map(|s| CString::new(s.as_str()))
115            .transpose()?;
116        let data_path_c = CString::new(request.data_file_path.to_string_lossy().as_ref())?;
117        let cover_path_c = request
118            .cover_file_path
119            .as_ref()
120            .map(|p| CString::new(p.to_string_lossy().as_ref()))
121            .transpose()?;
122
123        let raw_request = tapsdk_pc_sys::TapCloudSaveUpdateRequest {
124            uuid: uuid_c.as_ptr(),
125            name: name_c.as_ptr(),
126            summary: summary_c.as_ptr(),
127            extra: extra_c
128                .as_ref()
129                .map(|s| s.as_ptr())
130                .unwrap_or(std::ptr::null()),
131            playtime: request.playtime,
132            data_file_path: data_path_c.as_ptr(),
133            cover_file_path: cover_path_c
134                .as_ref()
135                .map(|s| s.as_ptr())
136                .unwrap_or(std::ptr::null()),
137            __bindgen_padding_0: Default::default(),
138        };
139
140        let result = unsafe {
141            tapsdk_pc_sys::TapCloudSave_AsyncUpdate(self.handle, request_id, &raw_request)
142        };
143
144        check_cloudsave_result(result)
145    }
146
147    /// Delete a cloud save
148    ///
149    /// The result will be delivered via the `CloudSaveDelete` event
150    /// when calling `TapSdk::run_callbacks()`.
151    ///
152    /// # Arguments
153    /// * `request_id` - A unique ID to identify this request in the callback
154    /// * `uuid` - The unique ID of the cloud save to delete
155    pub fn delete(&self, request_id: i64, uuid: &str) -> Result<()> {
156        let uuid_c = CString::new(uuid)?;
157
158        let result = unsafe {
159            tapsdk_pc_sys::TapCloudSave_AsyncDelete(self.handle, request_id, uuid_c.as_ptr())
160        };
161
162        check_cloudsave_result(result)
163    }
164
165    /// Get the data file for a cloud save
166    ///
167    /// The result will be delivered via the `CloudSaveGetData` event
168    /// when calling `TapSdk::run_callbacks()`.
169    ///
170    /// # Arguments
171    /// * `request_id` - A unique ID to identify this request in the callback
172    /// * `uuid` - The unique ID of the cloud save
173    /// * `file_id` - The file ID of the cloud save (from CloudSaveInfo)
174    pub fn get_data(&self, request_id: i64, uuid: &str, file_id: &str) -> Result<()> {
175        let uuid_c = CString::new(uuid)?;
176        let file_id_c = CString::new(file_id)?;
177
178        let raw_request = tapsdk_pc_sys::TapCloudSaveGetFileRequest {
179            uuid: uuid_c.as_ptr(),
180            file_id: file_id_c.as_ptr(),
181        };
182
183        let result = unsafe {
184            tapsdk_pc_sys::TapCloudSave_AsyncGetData(self.handle, request_id, &raw_request)
185        };
186
187        check_cloudsave_result(result)
188    }
189
190    /// Get the cover image for a cloud save
191    ///
192    /// The result will be delivered via the `CloudSaveGetCover` event
193    /// when calling `TapSdk::run_callbacks()`.
194    ///
195    /// # Arguments
196    /// * `request_id` - A unique ID to identify this request in the callback
197    /// * `uuid` - The unique ID of the cloud save
198    /// * `file_id` - The file ID of the cloud save (from CloudSaveInfo)
199    pub fn get_cover(&self, request_id: i64, uuid: &str, file_id: &str) -> Result<()> {
200        let uuid_c = CString::new(uuid)?;
201        let file_id_c = CString::new(file_id)?;
202
203        let raw_request = tapsdk_pc_sys::TapCloudSaveGetFileRequest {
204            uuid: uuid_c.as_ptr(),
205            file_id: file_id_c.as_ptr(),
206        };
207
208        let result = unsafe {
209            tapsdk_pc_sys::TapCloudSave_AsyncGetCover(self.handle, request_id, &raw_request)
210        };
211
212        check_cloudsave_result(result)
213    }
214}
215
216/// Request parameters for creating a cloud save
217#[derive(Debug, Clone)]
218pub struct CreateSaveRequest {
219    /// Save name (max 60 bytes, no Chinese characters)
220    pub name: String,
221    /// Save description (max 500 bytes)
222    pub summary: String,
223    /// Developer-defined extra data (max 1000 bytes, optional)
224    pub extra: Option<String>,
225    /// Game playtime in seconds
226    pub playtime: u32,
227    /// Path to the save data file (max 10MB)
228    pub data_file_path: Box<Path>,
229    /// Path to the cover image file (max 512KB, optional)
230    pub cover_file_path: Option<Box<Path>>,
231}
232
233/// Request parameters for updating a cloud save
234#[derive(Debug, Clone)]
235pub struct UpdateSaveRequest {
236    /// UUID of the cloud save to update
237    pub uuid: String,
238    /// Save name (max 60 bytes, no Chinese characters)
239    pub name: String,
240    /// Save description (max 500 bytes)
241    pub summary: String,
242    /// Developer-defined extra data (max 1000 bytes, optional)
243    pub extra: Option<String>,
244    /// Game playtime in seconds
245    pub playtime: u32,
246    /// Path to the save data file (max 10MB)
247    pub data_file_path: Box<Path>,
248    /// Path to the cover image file (max 512KB, optional)
249    pub cover_file_path: Option<Box<Path>>,
250}
251
252/// Convert a CloudSaveResult to a Result
253fn check_cloudsave_result(result: u32) -> Result<()> {
254    let cloud_result = CloudSaveResult::from(result);
255
256    match cloud_result {
257        CloudSaveResult::Ok => Ok(()),
258        _ => Err(TapSdkError::CloudSaveRequestFailed(cloud_result)),
259    }
260}