use protobuf::RepeatedField;
use reqwest::Response;
pub struct HttpClient {
uri: reqwest::Url,
http_client: reqwest::Client,
}
impl Default for HttpClient {
fn default() -> Self {
use reqwest::header;
let mut headers = header::HeaderMap::new();
headers.insert(header::ACCEPT, header::HeaderValue::from_static("application/json"));
headers.insert(
header::HeaderName::from_static("gamelift-server-pid"),
header::HeaderValue::from_str(std::process::id().to_string().as_str())
.expect("Cannot parse a gamelift-server-pid header value"),
);
Self {
uri: reqwest::Url::parse("http://localhost:5758/")
.expect("Cannot parse GameLift Server URI"),
http_client: reqwest::ClientBuilder::new()
.default_headers(headers)
.build()
.expect("Cannot build HTTP client"),
}
}
}
impl HttpClient {
async fn send<T>(&self, message: T) -> Result<Response, crate::error::GameLiftErrorType>
where
T: protobuf::Message,
{
let message_as_bytes = message.write_to_bytes().unwrap();
let message_header =
get_message_type(&message).expect("Cannot extract the message header").to_string();
log::debug!("Message name: {}", message_header);
self.http_client
.post(self.uri.clone())
.header("gamelift-target", message_header)
.body(message_as_bytes)
.send()
.await
.map_err(|error| {
if error.status().is_some() && error.status().unwrap().is_server_error() {
crate::error::GameLiftErrorType::InternalServiceError
} else {
crate::error::GameLiftErrorType::BadRequest
}
})
}
pub async fn process_ready(
&self,
port: i32,
log_paths_to_upload: Vec<String>,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::ProcessReady {
port,
logPathsToUpload: RepeatedField::from_vec(log_paths_to_upload),
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn process_ending(&self) -> Result<(), crate::error::GameLiftErrorType> {
self.send(crate::protos::generated_with_pure::sdk::ProcessEnding::default())
.await
.map(|_| ())
}
pub async fn report_health(
&self,
health_status: bool,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::ReportHealth {
healthStatus: health_status,
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn activate_game_session(
&self,
game_session_id: crate::entity::GameSessionId,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::GameSessionActivate {
gameSessionId: game_session_id,
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn terminate_game_session(
&self,
game_session_id: crate::entity::GameSessionId,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::GameSessionTerminate {
gameSessionId: game_session_id,
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn update_player_session_creation_policy(
&self,
game_session_id: crate::entity::GameSessionId,
player_session_policy: crate::entity::PlayerSessionCreationPolicy,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::UpdatePlayerSessionCreationPolicy {
gameSessionId: game_session_id,
newPlayerSessionCreationPolicy: player_session_policy.to_string(),
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn accept_player_session(
&self,
player_session_id: crate::entity::PlayerSessionId,
game_session_id: crate::entity::GameSessionId,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::AcceptPlayerSession {
playerSessionId: player_session_id,
gameSessionId: game_session_id,
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn remove_player_session(
&self,
player_session_id: crate::entity::PlayerSessionId,
game_session_id: crate::entity::GameSessionId,
) -> Result<(), crate::error::GameLiftErrorType> {
let message = crate::protos::generated_with_pure::sdk::RemovePlayerSession {
playerSessionId: player_session_id,
gameSessionId: game_session_id,
..Default::default()
};
self.send(message).await.map(|_| ())
}
pub async fn describe_player_sessions(
&self,
request: crate::entity::DescribePlayerSessionsRequest,
) -> Result<crate::entity::DescribePlayerSessionsResult, crate::error::GameLiftErrorType> {
let response = self.send(crate::mapper::describe_player_sessions_mapper(request)).await;
match response {
Ok(response) => {
let proto_response: crate::protos::generated_with_pure::sdk::DescribePlayerSessionsResponse =
serde_json::from_str(response.text().await.unwrap().as_str()).unwrap();
Ok(crate::mapper::describe_player_session_request_mapper(proto_response))
}
Err(error) => Err(error),
}
}
pub async fn backfill_matchmaking(
&self,
request: crate::entity::StartMatchBackfillRequest,
) -> Result<crate::entity::StartMatchBackfillResult, crate::error::GameLiftErrorType> {
let response = self.send(crate::mapper::start_match_backfill_request_mapper(request)).await;
match response {
Ok(response) => {
let p: crate::protos::generated_with_pure::sdk::BackfillMatchmakingResponse =
serde_json::from_str(response.text().await.unwrap().as_str()).unwrap();
Ok(crate::mapper::start_matchmaking_result_mapper(p))
}
Err(error) => Err(error),
}
}
pub async fn stop_matchmaking(
&self,
request: crate::entity::StopMatchBackfillRequest,
) -> Result<(), crate::error::GameLiftErrorType> {
self.send(crate::mapper::stop_matchmaking_request_mapper(request)).await.map(|_| ())
}
pub async fn get_instance_certificate(
&self,
) -> Result<crate::entity::GetInstanceCertificateResult, crate::error::GameLiftErrorType> {
let response = self
.send(crate::protos::generated_with_pure::sdk::GetInstanceCertificate::default())
.await;
match response {
Ok(response) => {
let p: crate::protos::generated_with_pure::sdk::GetInstanceCertificateResponse =
serde_json::from_str(response.text().await.unwrap().as_str()).unwrap();
Ok(crate::mapper::get_instance_certificate_result_mapper(p))
}
Err(error) => Err(error),
}
}
}
fn get_message_type<T>(_: &T) -> Option<&str> {
let full_name = std::any::type_name::<T>();
Some(&full_name[full_name.rfind(':')? + 1..])
}
#[cfg(test)]
mod tests {
use crate::http_client::get_message_type;
#[test]
fn get_message_type_test() {
let process_ready = crate::protos::generated_with_pure::sdk::ProcessReady::default();
assert_eq!(get_message_type(&process_ready), Some("ProcessReady"));
}
}