steamkit/steam/handlers/steam_master_server/
steam_master_server.rs1use std::net::IpAddr;
4use std::sync::{Arc, Weak};
5
6use async_trait::async_trait;
7use steamkit_protos::steam::CMsgClientGmsServerQuery;
8
9use crate::base::client_msg::{ClientMsgProtobuf, IClientMsg};
10use crate::base::generated::steam_language::{EMsg, ERegionCode};
11use crate::base::packet_base::IPacketMsg;
12use crate::error::{SteamError, SteamResult};
13use crate::steam::handlers::client_msg_handler::ClientMsgHandler;
14use crate::steam::steam_client::callback_mgr::callback_msg::CallbackMsg;
15use crate::steam::steam_client::steam_client::SteamClient;
16use crate::util::net_helpers::NetHelpers;
17
18use super::callbacks::QueryCallback;
19
20#[derive(Clone, Debug)]
22pub struct QueryDetails {
23 pub app_id: u32,
25
26 pub filter: Option<String>,
30
31 pub region: ERegionCode,
33
34 pub geo_located_ip: Option<IpAddr>,
36
37 pub max_servers: u32,
39}
40
41impl Default for QueryDetails {
42 fn default() -> Self {
43 Self {
44 app_id: 0,
45 filter: None,
46 region: ERegionCode::USEast,
48 geo_located_ip: None,
49 max_servers: 0,
50 }
51 }
52}
53
54pub struct SteamMasterServer {
56 client: Weak<SteamClient>,
57}
58
59impl std::fmt::Debug for SteamMasterServer {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("SteamMasterServer").finish()
62 }
63}
64
65impl SteamMasterServer {
66 pub fn new(client: &Arc<SteamClient>) -> Self {
68 Self {
69 client: Arc::downgrade(client),
70 }
71 }
72
73 fn client(&self) -> SteamResult<Arc<SteamClient>> {
75 self.client
76 .upgrade()
77 .ok_or_else(|| SteamError::Connection("SteamClient has been dropped".to_string()))
78 }
79
80 pub async fn server_query(&self, details: &QueryDetails) -> SteamResult<QueryCallback> {
82 let client = self.client()?;
83
84 let job_id = client.get_next_job_id();
85 let job = client.start_job::<QueryCallback>(job_id);
86
87 let mut query =
88 ClientMsgProtobuf::<CMsgClientGmsServerQuery>::new(EMsg::ClientGMSServerQuery);
89 query.set_source_job_id(job_id);
90
91 query.body.app_id = Some(details.app_id);
92
93 if let Some(geo_located_ip) = &details.geo_located_ip {
94 query.body.geo_location_ip = Some(NetHelpers::get_ip_address_as_uint(geo_located_ip)?);
95 }
96
97 query.body.filter_text = details.filter.clone();
98 query.body.region_code = Some(u32::from(details.region.value()));
99 query.body.max_servers = Some(details.max_servers);
100
101 client.send(&query)?;
102
103 job.wait().await
104 }
105}
106
107#[async_trait]
108impl ClientMsgHandler for SteamMasterServer {
109 async fn handle_msg(
110 &self,
111 client: &SteamClient,
112 packet_msg: &dyn IPacketMsg,
113 ) -> SteamResult<()> {
114 let callback: Option<Box<dyn CallbackMsg>> = match packet_msg.msg_type() {
115 EMsg::GMSClientServerQueryResponse => {
116 Some(Box::new(QueryCallback::from_packet(packet_msg)?))
117 }
118 _ => None,
120 };
121
122 if let Some(callback) = callback {
123 client.post_callback(callback);
124 }
125
126 Ok(())
127 }
128}