1use std::ffi::CString;
4use std::path::Path;
5
6use crate::error::{CloudSaveResult, Result, TapSdkError};
7use crate::sdk::is_initialized;
8
9pub struct CloudSave {
14 handle: *mut tapsdk_pc_sys::ITapCloudSave,
15}
16
17unsafe impl Send for CloudSave {}
19unsafe impl Sync for CloudSave {}
20
21impl CloudSave {
22 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 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 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 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 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 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 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#[derive(Debug, Clone)]
218pub struct CreateSaveRequest {
219 pub name: String,
221 pub summary: String,
223 pub extra: Option<String>,
225 pub playtime: u32,
227 pub data_file_path: Box<Path>,
229 pub cover_file_path: Option<Box<Path>>,
231}
232
233#[derive(Debug, Clone)]
235pub struct UpdateSaveRequest {
236 pub uuid: String,
238 pub name: String,
240 pub summary: String,
242 pub extra: Option<String>,
244 pub playtime: u32,
246 pub data_file_path: Box<Path>,
248 pub cover_file_path: Option<Box<Path>>,
250}
251
252fn 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}