wicked-waifus-rs/gateway-server/src/handler/service_message_handler.rs
2024-09-11 19:37:46 +03:00

210 lines
6.2 KiB
Rust

use std::sync::OnceLock;
use common::time_util;
use shorekeeper_network::{config::ServiceEndPoint, ServiceListener, ServiceMessage};
use shorekeeper_protocol::{
message::Message, CreateCharacterResponse, CreatePlayerDataResponse, EnterGameResponse,
ErrorCode, ForwardClientMessagePush, MessageID, Protobuf, StartPlayerSessionResponse,
};
use crate::session::SessionManager;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Failed to bind ServiceListener")]
BindFailed,
}
pub async fn start_task(
listen_end_point: &ServiceEndPoint,
session_mgr: &'static SessionManager,
) -> Result<(), Error> {
static IS_STARTED: OnceLock<()> = OnceLock::new();
if IS_STARTED.set(()).is_err() {
tracing::error!("service_message_handler: task already started");
return Ok(());
}
let listener = ServiceListener::bind(listen_end_point)
.await
.map_err(|_| Error::BindFailed)?;
tokio::spawn(async move { handler_task_fn(listener, session_mgr).await });
Ok(())
}
async fn handler_task_fn(mut listener: ServiceListener, session_mgr: &'static SessionManager) {
loop {
let Some(message) = listener.receive().await else {
continue;
};
tracing::debug!(
"received message from service: {}, rpc_id: {} message_id: {}",
message.src_service_id,
message.rpc_id,
message.message_id
);
match message.message_id {
CreatePlayerDataResponse::MESSAGE_ID => {
on_create_player_data_response(message, session_mgr).await
}
StartPlayerSessionResponse::MESSAGE_ID => {
on_start_player_session_response(message, session_mgr).await
}
ForwardClientMessagePush::MESSAGE_ID => {
on_forward_client_message_push(message, session_mgr).await
}
unhandled => tracing::warn!(
"unhandled service message id: {unhandled}, from service_id: {}",
message.src_service_id
),
}
}
}
async fn on_forward_client_message_push(
message: ServiceMessage,
session_mgr: &'static SessionManager,
) {
let Ok(push) = ForwardClientMessagePush::decode(message.data.as_ref()) else {
tracing::error!(
"failed to decode ForwardClientMessagePush, data: {}",
hex::encode(&message.data)
);
return;
};
let Ok(message) = Message::decode(&push.data) else {
tracing::error!(
"ForwardClientMessage: failed to decode underlying message data, session_id: {}",
push.gateway_session_id
);
return;
};
let Some(mut session) = session_mgr.get_mut(push.gateway_session_id) else {
tracing::error!(
"ForwardClientMessage: session not found, id: {}",
push.gateway_session_id
);
return;
};
tracing::debug!(
"forward message from game server to client, message_id: {}, session_id: {}",
message.get_message_id(),
push.gateway_session_id
);
let _ = session.send_message(message).await.inspect_err(|err| {
tracing::error!("ForwardClientMessage: failed to send message, error: {err}")
});
}
async fn on_start_player_session_response(
message: ServiceMessage,
session_mgr: &'static SessionManager,
) {
let Ok(response) = StartPlayerSessionResponse::decode(message.data.as_ref()) else {
tracing::error!(
"failed to decode StartPlayerSessionResponse, data: {}",
hex::encode(&message.data)
);
return;
};
let Some(mut session) = session_mgr.get_mut(response.gateway_session_id) else {
tracing::error!(
"StartPlayerSession: session not found, id: {}",
response.gateway_session_id
);
return;
};
if response.code != 0 {
tracing::debug!(
"StartPlayerSession failed, session_id: {}, player_id: {:?}, user_id: {:?}, error code: {}",
response.gateway_session_id,
&session.player_id,
&session.user_id,
response.code
);
let _ = session
.send_response(
EnterGameResponse {
error_code: response.code,
..Default::default()
},
message.rpc_id,
)
.await;
} else {
tracing::debug!(
"StartPlayerSession success, game server should forward subsequent messages now. player_id: {}",
session.player_id.unwrap_or_default()
);
}
}
async fn on_create_player_data_response(
message: ServiceMessage,
session_mgr: &'static SessionManager,
) {
let Ok(response) = CreatePlayerDataResponse::decode(message.data.as_ref()) else {
tracing::error!(
"failed to decode CreatePlayerDataResponse, data: {}",
hex::encode(&message.data)
);
return;
};
let Some(mut session) = session_mgr.get_mut(response.session_id) else {
tracing::debug!("session with id {} not found", response.session_id);
return;
};
if response.code != 0 {
tracing::warn!("CreatePlayerData failed, code: {}", response.code);
let _ = session
.send_response(
CreateCharacterResponse {
error_code: response.code,
..Default::default()
},
message.rpc_id,
)
.await;
return;
}
let Some(user_id) = session.user_id.as_ref() else {
tracing::debug!(
"session.user_id is None, session_id: {}",
response.session_id
);
return;
};
tracing::info!(
"CreateCharacter success, player_id: {}, user_id: {}",
response.player_id,
user_id
);
session.player_id = Some(response.player_id);
let _ = session
.send_response(
CreateCharacterResponse {
error_code: ErrorCode::Success.into(),
player_id: response.player_id,
name: response.name,
create_time: time_util::unix_timestamp() as i32,
},
message.rpc_id,
)
.await;
}