Skip to main content

steamkit/steam/handlers/steam_workshop/
steam_workshop.rs

1//! Requesting files published on the Steam Workshop.
2
3use std::sync::{Arc, Weak};
4
5use async_trait::async_trait;
6use steamkit_protos::steam::CMsgClientUcmEnumeratePublishedFilesByUserAction;
7
8use crate::base::client_msg::{ClientMsgProtobuf, IClientMsg};
9use crate::base::generated::steam_language::{EMsg, EWorkshopFileAction};
10use crate::base::packet_base::IPacketMsg;
11use crate::error::{SteamError, SteamResult};
12use crate::steam::handlers::client_msg_handler::ClientMsgHandler;
13use crate::steam::steam_client::callback_mgr::callback_msg::CallbackMsg;
14use crate::steam::steam_client::steam_client::SteamClient;
15
16use super::callbacks::UserActionPublishedFilesCallback;
17
18/// What to enumerate of the local user's workshop files.
19#[derive(Clone, Debug)]
20pub struct EnumerationUserDetails {
21    /// The app whose workshop to enumerate.
22    pub app_id: u32,
23
24    /// The start index.
25    pub start_index: u32,
26
27    /// The user action to filter by. Only used by
28    /// [`SteamWorkshop::enumerate_published_files_by_user_action`].
29    pub user_action: EWorkshopFileAction,
30}
31
32impl Default for EnumerationUserDetails {
33    fn default() -> Self {
34        Self {
35            app_id: 0,
36            start_index: 0,
37            // The first member of the enum.
38            user_action: EWorkshopFileAction::Played,
39        }
40    }
41}
42
43/// Requests files published on the Steam Workshop.
44pub struct SteamWorkshop {
45    client: Weak<SteamClient>,
46}
47
48impl SteamWorkshop {
49    /// Creates the handler and stores a weak back-reference to the client.
50    pub fn new(client: &Arc<SteamClient>) -> Self {
51        Self {
52            client: Arc::downgrade(client),
53        }
54    }
55
56    /// Upgrades the weak client reference.
57    fn client(&self) -> SteamResult<Arc<SteamClient>> {
58        self.client
59            .upgrade()
60            .ok_or_else(|| SteamError::Connection("SteamClient has been dropped".to_string()))
61    }
62
63    /// Lists the current user's published files, filtered by user action.
64    pub async fn enumerate_published_files_by_user_action(
65        &self,
66        details: &EnumerationUserDetails,
67    ) -> SteamResult<UserActionPublishedFilesCallback> {
68        let client = self.client()?;
69
70        let job_id = client.get_next_job_id();
71        let job = client.start_job::<UserActionPublishedFilesCallback>(job_id);
72
73        let mut enum_request =
74            ClientMsgProtobuf::<CMsgClientUcmEnumeratePublishedFilesByUserAction>::new(
75                EMsg::ClientUCMEnumeratePublishedFilesByUserAction,
76            );
77        enum_request.set_source_job_id(job_id);
78
79        enum_request.body.action = Some(details.user_action.value());
80        enum_request.body.app_id = Some(details.app_id);
81        enum_request.body.start_index = Some(details.start_index);
82
83        client.send(&enum_request)?;
84
85        job.wait().await
86    }
87}
88
89#[async_trait]
90impl ClientMsgHandler for SteamWorkshop {
91    async fn handle_msg(
92        &self,
93        client: &SteamClient,
94        packet_msg: &dyn IPacketMsg,
95    ) -> SteamResult<()> {
96        let callback: Option<Box<dyn CallbackMsg>> = match packet_msg.msg_type() {
97            EMsg::ClientUCMEnumeratePublishedFilesByUserActionResponse => Some(Box::new(
98                UserActionPublishedFilesCallback::from_packet(packet_msg)?,
99            )),
100            // Not a message we handle.
101            _ => None,
102        };
103
104        if let Some(callback) = callback {
105            client.post_callback(callback);
106        }
107
108        Ok(())
109    }
110}