steamkit/steam/webapi/
content_server_directory_service.rs1use steamkit_protos::steam::{
4 CContentServerDirectoryGetServersForSteamPipeRequest,
5 CContentServerDirectoryGetServersForSteamPipeResponse,
6};
7use tokio_util::sync::CancellationToken;
8
9use crate::error::SteamError;
10use crate::steam::cdn::server::{ConnectionProtocol, Server};
11use crate::steam::steam_client::configuration::steam_configuration::SteamConfiguration;
12
13use super::steam_configuration_web_api_extensions::get_async_web_api_interface;
14
15pub struct ContentServerDirectoryService;
17
18impl ContentServerDirectoryService {
19 pub async fn load(
21 configuration: &SteamConfiguration,
22 ) -> Result<Vec<Server>, SteamError> {
23 Self::load_core(configuration, None, None, CancellationToken::new()).await
24 }
25
26 pub async fn load_with_cancellation(
28 configuration: &SteamConfiguration,
29 cancellation: CancellationToken,
30 ) -> Result<Vec<Server>, SteamError> {
31 Self::load_core(configuration, None, None, cancellation).await
32 }
33
34 pub async fn load_with_cell_id(
36 configuration: &SteamConfiguration,
37 cell_id: u32,
38 cancellation: CancellationToken,
39 ) -> Result<Vec<Server>, SteamError> {
40 Self::load_core(configuration, Some(cell_id), None, cancellation).await
41 }
42
43 pub async fn load_with_cell_id_and_max_num_servers(
46 configuration: &SteamConfiguration,
47 cell_id: u32,
48 max_num_servers: u32,
49 cancellation: CancellationToken,
50 ) -> Result<Vec<Server>, SteamError> {
51 Self::load_core(
52 configuration,
53 Some(cell_id),
54 Some(max_num_servers),
55 cancellation,
56 )
57 .await
58 }
59
60 async fn load_core(
62 configuration: &SteamConfiguration,
63 cell_id: Option<u32>,
64 max_num_servers: Option<u32>,
65 cancellation: CancellationToken,
66 ) -> Result<Vec<Server>, SteamError> {
67 let directory = get_async_web_api_interface(configuration, "IContentServerDirectoryService");
68
69 let mut request = CContentServerDirectoryGetServersForSteamPipeRequest {
70 cell_id: Some(cell_id.unwrap_or_else(|| configuration.cell_id())),
71 ..Default::default()
72 };
73
74 if let Some(max_num_servers) = max_num_servers {
75 request.max_servers = Some(max_num_servers);
76 }
77
78 if cancellation.is_cancelled() {
79 return Err(SteamError::Cancelled);
80 }
81
82 let response = directory
83 .call_protobuf_with_request::<
84 CContentServerDirectoryGetServersForSteamPipeResponse,
85 CContentServerDirectoryGetServersForSteamPipeRequest,
86 >(
87 reqwest::Method::GET,
88 "GetServersForSteamPipe",
89 &request,
90 1,
91 &[],
92 )
93 .await?;
94
95 if cancellation.is_cancelled() {
96 return Err(SteamError::Cancelled);
97 }
98
99 Ok(Self::convert_server_list(&response.body))
100 }
101
102 pub fn convert_server_list(
104 response: &CContentServerDirectoryGetServersForSteamPipeResponse,
105 ) -> Vec<Server> {
106 let mut server_records = Vec::with_capacity(response.servers.len());
107
108 for child in &response.servers {
109 let https_support = child.https_support.as_deref();
110 let protocol = if https_support == Some("mandatory") {
111 ConnectionProtocol::Https
112 } else {
113 ConnectionProtocol::Http
114 };
115
116 server_records.push(Server {
117 protocol,
118 host: child.host.clone(),
119 v_host: child.vhost.clone(),
120 port: if protocol == ConnectionProtocol::Https {
121 443
122 } else {
123 80
124 },
125 server_type: child.r#type.clone(),
126 source_id: child.source_id.unwrap_or_default(),
127 cell_id: child.cell_id.unwrap_or_default() as u32,
128 load: child.load.unwrap_or_default(),
129 weighted_load: child.weighted_load.unwrap_or_default(),
130 num_entries: child.num_entries_in_client_list.unwrap_or_default(),
131 steam_china_only: child.steam_china_only.unwrap_or_default(),
132 use_as_proxy: child.use_as_proxy.unwrap_or_default(),
133 proxy_request_path_template: child.proxy_request_path_template.clone(),
134 allowed_app_ids: child.allowed_app_ids.clone(),
135 bypass_proxies_of_type: child.bypass_proxies_of_type.clone(),
136 });
137 }
138
139 server_records
140 }
141}