forked from wickedwaifus/wicked-waifus-rs
210 lines
6.2 KiB
Rust
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;
|
|
}
|