steamkit/steam/handlers/steam_cloud/
steam_cloud.rs1use std::fmt;
5use std::sync::{Arc, OnceLock, Weak};
6
7use async_trait::async_trait;
8use steamkit_protos::steam::{
9 CCloudGetFileDetailsRequest, CCloudGetFileDetailsResponse, CCloudGetSingleFileInfoRequest,
10 CCloudGetSingleFileInfoResponse, CCloudShareFileRequest, CCloudShareFileResponse,
11};
12
13use crate::base::packet_base::IPacketMsg;
14use crate::error::{SteamError, SteamResult};
15use crate::steam::handlers::client_msg_handler::ClientMsgHandler;
16use crate::steam::handlers::steam_unified_messages::steam_unified_messages::{
17 SteamUnifiedMessages, UnifiedService,
18};
19use crate::steam::steam_client::steam_client::SteamClient;
20use crate::types::global_id::UGCHandle;
21
22use super::callbacks::{ShareFileCallback, SingleFileInfoCallback, UGCDetailsCallback};
23
24const SERVICE_NAME: &str = "Cloud";
26
27pub struct SteamCloud {
29 client: Weak<SteamClient>,
30 service: OnceLock<Arc<UnifiedService>>,
31}
32
33impl fmt::Debug for SteamCloud {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.debug_struct("SteamCloud").finish_non_exhaustive()
36 }
37}
38
39impl SteamCloud {
40 pub fn new(client: &Arc<SteamClient>) -> Self {
42 Self {
43 client: Arc::downgrade(client),
44 service: OnceLock::new(),
45 }
46 }
47
48 fn client(&self) -> SteamResult<Arc<SteamClient>> {
50 self.client
51 .upgrade()
52 .ok_or_else(|| SteamError::Connection("SteamClient has been dropped".to_string()))
53 }
54
55 fn service(&self) -> SteamResult<Arc<UnifiedService>> {
57 if let Some(service) = self.service.get() {
58 return Ok(Arc::clone(service));
59 }
60
61 let client = self.client()?;
62 let unified_messages = client.get_required_handler::<SteamUnifiedMessages>()?;
63 let service = unified_messages.create_service(SERVICE_NAME)?;
64
65 service.set_response_type::<CCloudGetFileDetailsResponse>("GetFileDetails");
66 service.set_response_type::<CCloudGetSingleFileInfoResponse>("GetSingleFileInfo");
67 service.set_response_type::<CCloudShareFileResponse>("ShareFile");
68
69 let _ = self.service.set(Arc::clone(&service));
70
71 Ok(service)
72 }
73
74 pub async fn request_ugc_details(&self, ugc_id: UGCHandle) -> SteamResult<UGCDetailsCallback> {
76 let service = self.service()?;
77
78 let request = CCloudGetFileDetailsRequest {
79 ugcid: Some(ugc_id.value()),
80 ..Default::default()
81 };
82
83 let response = service
84 .send_message::<CCloudGetFileDetailsRequest, CCloudGetFileDetailsResponse>(
85 "GetFileDetails",
86 request,
87 )
88 .await?;
89
90 Ok(UGCDetailsCallback::from_response(
91 response.result(),
92 response.body().clone(),
93 ))
94 }
95
96 pub async fn get_single_file_info(
98 &self,
99 app_id: u32,
100 filename: &str,
101 ) -> SteamResult<SingleFileInfoCallback> {
102 let service = self.service()?;
103
104 let request = CCloudGetSingleFileInfoRequest {
105 app_id: Some(app_id),
106 file_name: Some(filename.to_string()),
107 ..Default::default()
108 };
109
110 let response = service
111 .send_message::<CCloudGetSingleFileInfoRequest, CCloudGetSingleFileInfoResponse>(
112 "GetSingleFileInfo",
113 request,
114 )
115 .await?;
116
117 Ok(SingleFileInfoCallback::from_response(
118 response.result(),
119 response.body().clone(),
120 ))
121 }
122
123 pub async fn share_file(&self, app_id: u32, filename: &str) -> SteamResult<ShareFileCallback> {
125 let service = self.service()?;
126
127 let request = CCloudShareFileRequest {
128 app_id: Some(app_id),
129 file_name: Some(filename.to_string()),
130 ..Default::default()
131 };
132
133 let response = service
134 .send_message::<CCloudShareFileRequest, CCloudShareFileResponse>("ShareFile", request)
135 .await?;
136
137 Ok(ShareFileCallback::from_response(
138 response.result(),
139 response.body().clone(),
140 ))
141 }
142}
143
144#[async_trait]
145impl ClientMsgHandler for SteamCloud {
146 async fn handle_msg(
147 &self,
148 _client: &SteamClient,
149 _packet_msg: &dyn IPacketMsg,
150 ) -> SteamResult<()> {
151 Ok(())
153 }
154}