Add comprehensive documentation and unit tests
Documentation: - Add detailed README files for all services (auth, character, database, launcher, packet, utils, world) - Create API documentation for the database service with detailed endpoint specifications - Document database schema and relationships - Add service architecture overviews and configuration instructions Unit Tests: - Implement comprehensive test suite for database repositories (user, character, session) - Add gRPC service tests for database interactions - Create tests for packet service components (bufferpool, connection, packets) - Add utility service tests (health check, logging, load balancer, redis cache, service discovery) - Implement auth service user tests - Add character service tests Code Structure: - Reorganize test files into a more consistent structure - Create a dedicated tests crate for integration testing - Add test helpers and mock implementations for easier testing
This commit is contained in:
@@ -69,10 +69,7 @@ impl AuthClient {
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub async fn logout(
|
||||
&mut self,
|
||||
session_id: &str,
|
||||
) -> Result<Empty, Box<dyn std::error::Error + Send + Sync>> {
|
||||
pub async fn logout(&mut self, session_id: &str) -> Result<Empty, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let request = LogoutRequest {
|
||||
session_id: session_id.to_string(),
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::character::character_service_client::CharacterServiceClient;
|
||||
use crate::character::{
|
||||
CreateCharacterRequest, CreateCharacterResponse, DeleteCharacterRequest,
|
||||
DeleteCharacterResponse, GetCharacterListRequest, GetCharacterListResponse,
|
||||
GetCharacterRequest, GetCharacterResponse,
|
||||
CreateCharacterRequest, CreateCharacterResponse, DeleteCharacterRequest, DeleteCharacterResponse,
|
||||
GetCharacterListRequest, GetCharacterListResponse, GetCharacterRequest, GetCharacterResponse,
|
||||
};
|
||||
use tonic::transport::Channel;
|
||||
use utils::null_string::NullTerminatedString;
|
||||
|
||||
@@ -17,15 +17,12 @@ impl ConnectionService {
|
||||
|
||||
pub fn add_connection(&self) -> String {
|
||||
let connection_id = Uuid::new_v4().to_string();
|
||||
self.connections
|
||||
.insert(connection_id.clone(), ConnectionState::new());
|
||||
self.connections.insert(connection_id.clone(), ConnectionState::new());
|
||||
connection_id
|
||||
}
|
||||
|
||||
pub fn get_connection(&self, connection_id: &str) -> Option<ConnectionState> {
|
||||
self.connections
|
||||
.get(connection_id)
|
||||
.map(|entry| entry.clone())
|
||||
self.connections.get(connection_id).map(|entry| entry.clone())
|
||||
}
|
||||
|
||||
pub fn get_connection_mut(
|
||||
|
||||
@@ -133,10 +133,7 @@ pub(crate) async fn handle_login_req(
|
||||
connection_id: String,
|
||||
addr: SocketAddr,
|
||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
debug!(
|
||||
"decoding packet payload of size {}",
|
||||
packet.payload.as_slice().len()
|
||||
);
|
||||
debug!("decoding packet payload of size {}", packet.payload.as_slice().len());
|
||||
let data = CliLoginTokenReq::decode(packet.payload.as_slice())?;
|
||||
debug!("{:?}", data);
|
||||
|
||||
@@ -175,9 +172,7 @@ pub(crate) async fn handle_login_req(
|
||||
"name" => {
|
||||
server_name = value;
|
||||
}
|
||||
"tags" => {
|
||||
|
||||
}
|
||||
"tags" => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,15 @@ use crate::enums::ItemType;
|
||||
use crate::packet::{send_packet, Packet, PacketPayload};
|
||||
use crate::packet_type::PacketType;
|
||||
use crate::packets::*;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::error::Error;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::Mutex;
|
||||
use tonic::{Code, Status};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use utils::null_string::NullTerminatedString;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
|
||||
fn string_to_u32(s: &str) -> u32 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
@@ -80,20 +79,16 @@ pub(crate) async fn handle_char_list_req(
|
||||
let request = CliCharListReq::decode(packet.payload.as_slice());
|
||||
debug!("{:?}", request);
|
||||
|
||||
let mut user_id= "".to_string();
|
||||
let mut user_id = "".to_string();
|
||||
let session_id;
|
||||
if let Some(mut state) = connection_service.get_connection(&connection_id) {
|
||||
user_id = state.user_id.expect("Missing user id in connection state");
|
||||
session_id = state
|
||||
.session_id
|
||||
.expect("Missing session id in connection state");
|
||||
session_id = state.session_id.expect("Missing session id in connection state");
|
||||
}
|
||||
|
||||
// query the character service for the character list for this user
|
||||
let mut character_client = character_client.lock().await;
|
||||
let character_list = character_client
|
||||
.get_character_list(&user_id)
|
||||
.await?;
|
||||
let character_list = character_client.get_character_list(&user_id).await?;
|
||||
let mut characters = vec![];
|
||||
let mut character_id_list: Vec<u32> = Vec::new();
|
||||
for character in character_list.characters {
|
||||
@@ -154,9 +149,7 @@ pub(crate) async fn handle_create_char_req(
|
||||
let session_id;
|
||||
if let Some(mut state) = connection_service.get_connection(&connection_id) {
|
||||
user_id = state.user_id.expect("Missing user id in connection state");
|
||||
session_id = state
|
||||
.session_id
|
||||
.expect("Missing session id in connection state");
|
||||
session_id = state.session_id.expect("Missing session id in connection state");
|
||||
}
|
||||
|
||||
// send the data to the character service to create the character
|
||||
@@ -181,10 +174,7 @@ pub(crate) async fn handle_create_char_req(
|
||||
_ => srv_create_char_reply::Result::Failed,
|
||||
};
|
||||
|
||||
let data = SrvCreateCharReply {
|
||||
result,
|
||||
platininum: 0,
|
||||
};
|
||||
let data = SrvCreateCharReply { result, platininum: 0 };
|
||||
let response_packet = Packet::new(PacketType::PakccCreateCharReply, &data)?;
|
||||
send_packet(stream, &response_packet).await?;
|
||||
|
||||
@@ -209,9 +199,7 @@ pub(crate) async fn handle_delete_char_req(
|
||||
|
||||
if let Some(mut state) = connection_service.get_connection(&connection_id) {
|
||||
user_id = state.user_id.expect("Missing user id in connection state");
|
||||
session_id = state
|
||||
.session_id
|
||||
.expect("Missing session id in connection state");
|
||||
session_id = state.session_id.expect("Missing session id in connection state");
|
||||
character_id_list = state.character_list.expect("Missing character id list");
|
||||
}
|
||||
|
||||
@@ -256,10 +244,7 @@ pub(crate) async fn handle_select_char_req(
|
||||
let mut character_id_list: Vec<u32> = Vec::new();
|
||||
if let Some(mut state) = connection_service.get_connection_mut(&connection_id) {
|
||||
user_id = state.user_id.clone().expect("Missing user id in connection state");
|
||||
character_id_list = state
|
||||
.character_list
|
||||
.clone()
|
||||
.expect("Missing character id list");
|
||||
character_id_list = state.character_list.clone().expect("Missing character id list");
|
||||
state.character_id = Some(request.char_id as i8);
|
||||
}
|
||||
|
||||
@@ -274,10 +259,7 @@ pub(crate) async fn handle_select_char_req(
|
||||
|
||||
let mut character_client = character_client.lock().await;
|
||||
let character_data = character_client
|
||||
.get_character(
|
||||
&user_id.to_string(),
|
||||
character_id_list[request.char_id as usize] as u8,
|
||||
)
|
||||
.get_character(&user_id.to_string(), character_id_list[request.char_id as usize] as u8)
|
||||
.await?;
|
||||
|
||||
let character = character_data.character.unwrap_or_default();
|
||||
@@ -332,8 +314,7 @@ pub(crate) async fn handle_select_char_req(
|
||||
|
||||
let mut effect_list: [StatusEffect; (MAX_STATUS_EFFECTS as usize)] =
|
||||
core::array::from_fn(|i| StatusEffect::default());
|
||||
let mut hotbar_list: [HotbarItem; (MAX_HOTBAR_ITEMS as usize)] =
|
||||
core::array::from_fn(|i| HotbarItem::default());
|
||||
let mut hotbar_list: [HotbarItem; (MAX_HOTBAR_ITEMS as usize)] = core::array::from_fn(|i| HotbarItem::default());
|
||||
let data = SrvSelectCharReply {
|
||||
race: looks.race as u8,
|
||||
map: position.map_id as u16,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::character_client::CharacterClient;
|
||||
use crate::character_client::CharacterClient;
|
||||
use crate::connection_service::ConnectionService;
|
||||
use crate::packet::{send_packet, Packet, PacketPayload};
|
||||
use crate::packet_type::PacketType;
|
||||
@@ -32,24 +32,14 @@ pub(crate) async fn handle_change_map_req(
|
||||
let session_id;
|
||||
if let Some(mut state) = connection_service.get_connection(&connection_id) {
|
||||
user_id = state.user_id.expect("Missing user id in connection state");
|
||||
session_id = state
|
||||
.session_id
|
||||
.expect("Missing session id in connection state");
|
||||
char_id = state
|
||||
.character_id
|
||||
.expect("Missing character id in connection state");
|
||||
character_id_list = state
|
||||
.character_list
|
||||
.clone()
|
||||
.expect("Missing character id list");
|
||||
session_id = state.session_id.expect("Missing session id in connection state");
|
||||
char_id = state.character_id.expect("Missing character id in connection state");
|
||||
character_id_list = state.character_list.clone().expect("Missing character id list");
|
||||
}
|
||||
|
||||
let mut character_client = character_client.lock().await;
|
||||
let character_data = character_client
|
||||
.get_character(
|
||||
&user_id.to_string(),
|
||||
character_id_list[char_id as usize] as u8,
|
||||
)
|
||||
.get_character(&user_id.to_string(), character_id_list[char_id as usize] as u8)
|
||||
.await?;
|
||||
|
||||
let character = character_data.character.unwrap_or_default();
|
||||
@@ -93,24 +83,14 @@ pub(crate) async fn handle_mouse_cmd_req(
|
||||
let mut char_id = 0;
|
||||
let mut character_id_list: Vec<u32> = Vec::new();
|
||||
if let Some(mut state) = connection_service.get_connection(&connection_id) {
|
||||
char_id = state
|
||||
.character_id
|
||||
.expect("Missing character id in connection state");
|
||||
character_id_list = state
|
||||
.character_list
|
||||
.clone()
|
||||
.expect("Missing character id list");
|
||||
char_id = state.character_id.expect("Missing character id in connection state");
|
||||
character_id_list = state.character_list.clone().expect("Missing character id list");
|
||||
}
|
||||
|
||||
let data = SrvMouseCmd {
|
||||
id: character_id_list[char_id as usize] as u16,
|
||||
target_id: request.target_id,
|
||||
distance: distance(
|
||||
520000 as f64,
|
||||
520000 as f64,
|
||||
request.x as f64,
|
||||
request.y as f64,
|
||||
),
|
||||
distance: distance(520000 as f64, 520000 as f64, request.x as f64, request.y as f64),
|
||||
x: request.x,
|
||||
y: request.y,
|
||||
z: request.z,
|
||||
|
||||
7
packet-service/src/lib.rs
Normal file
7
packet-service/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// Re-export only the modules needed for tests
|
||||
pub mod bufferpool;
|
||||
pub mod connection_service;
|
||||
pub mod connection_state;
|
||||
pub mod metrics;
|
||||
pub mod packet;
|
||||
pub mod packet_type;
|
||||
@@ -21,8 +21,8 @@ use tokio::{select, signal};
|
||||
use tracing::Level;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use utils::service_discovery::get_kube_service_endpoints_by_dns;
|
||||
use utils::{health_check, logging};
|
||||
use utils::service_discovery::{get_kube_service_endpoints_by_dns};
|
||||
use warp::Filter;
|
||||
|
||||
mod auth_client;
|
||||
@@ -66,8 +66,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let addr = env::var("LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0".to_string());
|
||||
let port = env::var("SERVICE_PORT").unwrap_or_else(|_| "29000".to_string());
|
||||
let metrics_port = env::var("PACKET_METRICS_PORT").unwrap_or_else(|_| "4001".to_string());
|
||||
let auth_url = format!("http://{}",get_kube_service_endpoints_by_dns("auth-service","tcp","auth-service").await?.get(0).unwrap());
|
||||
let character_url = format!("http://{}",get_kube_service_endpoints_by_dns("character-service","tcp","character-service").await?.get(0).unwrap());
|
||||
let auth_url = format!(
|
||||
"http://{}",
|
||||
get_kube_service_endpoints_by_dns("auth-service", "tcp", "auth-service")
|
||||
.await?
|
||||
.get(0)
|
||||
.unwrap()
|
||||
);
|
||||
let character_url = format!(
|
||||
"http://{}",
|
||||
get_kube_service_endpoints_by_dns("character-service", "tcp", "character-service")
|
||||
.await?
|
||||
.get(0)
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// Start health-check endpoint
|
||||
health_check::start_health_check(addr.as_str()).await?;
|
||||
@@ -109,9 +121,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
{
|
||||
error!("Error handling connection: {}", e);
|
||||
}
|
||||
packet_router
|
||||
.connection_service
|
||||
.remove_connection(&connection_id);
|
||||
packet_router.connection_service.remove_connection(&connection_id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use lazy_static::lazy_static;
|
||||
use prometheus::{
|
||||
register_counter, register_gauge, register_histogram, Counter, Encoder, Gauge, Histogram,
|
||||
TextEncoder,
|
||||
register_counter, register_gauge, register_histogram, Counter, Encoder, Gauge, Histogram, TextEncoder,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
|
||||
@@ -52,8 +52,7 @@ impl PacketRouter {
|
||||
Ok(packet) => {
|
||||
debug!("Parsed Packet: {:?}", packet);
|
||||
// Handle the parsed packet (route it, process it, etc.)
|
||||
self.route_packet(stream, packet, connection_id.clone())
|
||||
.await?;
|
||||
self.route_packet(stream, packet, connection_id.clone()).await?;
|
||||
}
|
||||
Err(e) => warn!("Failed to parse packet: {}", e),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user