(tools, client, server) feat: Remove gRPC support, add TCP back and reorganized project
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
use std::io::Write;
|
||||
|
||||
pub(crate) fn run() {
|
||||
use crate::servers::tcp_server::TCP_SERVER;
|
||||
use crate::servers::udp_server::UDP_SERVER;
|
||||
|
||||
pub(crate) async fn run() {
|
||||
let stdin = std::io::stdin();
|
||||
|
||||
loop {
|
||||
@ -14,7 +17,12 @@ pub(crate) fn run() {
|
||||
.expect("Failed to read from standard input!");
|
||||
|
||||
match input.trim() {
|
||||
"exit" => break,
|
||||
"exit" => {
|
||||
TCP_SERVER.lock().await.stop().await;
|
||||
UDP_SERVER.lock().await.stop().await;
|
||||
|
||||
break;
|
||||
}
|
||||
_ => println!("Usage: <command>"),
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use tokio::task;
|
||||
use tonic::transport::Server;
|
||||
use tonic_web::GrpcWebLayer;
|
||||
|
||||
use crate::protocol::game_service_server::GameServiceServer;
|
||||
use crate::services::game_service::GameServiceImpl;
|
||||
|
||||
pub(crate) struct GrpcServer;
|
||||
|
||||
impl GrpcServer {
|
||||
pub(crate) async fn init() {
|
||||
let addr = SocketAddr::new([127, 0, 0, 1].into(), 12345);
|
||||
|
||||
let game_service = GameServiceServer::new(GameServiceImpl);
|
||||
|
||||
task::spawn(async move {
|
||||
Server::builder()
|
||||
.accept_http1(true)
|
||||
.layer(GrpcWebLayer::new())
|
||||
.add_service(game_service)
|
||||
.serve(addr)
|
||||
.await
|
||||
.unwrap_or_else(|e| log::error!("Failed to build server: {e}"));
|
||||
});
|
||||
}
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
mod command_helper;
|
||||
mod grpc_server;
|
||||
mod protocol;
|
||||
mod server_logger;
|
||||
mod servers;
|
||||
mod services;
|
||||
mod udp_server;
|
||||
|
||||
use grpc_server::GrpcServer;
|
||||
use server_logger::ServerLogger;
|
||||
use udp_server::UdpServer;
|
||||
use servers::tcp_server::TCP_SERVER;
|
||||
use servers::udp_server::UDP_SERVER;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@ -15,10 +14,10 @@ async fn main() {
|
||||
|
||||
log::info!("Starting server...");
|
||||
|
||||
GrpcServer::init().await;
|
||||
UdpServer::init();
|
||||
TCP_SERVER.lock().await.start().await;
|
||||
UDP_SERVER.lock().await.start().await;
|
||||
|
||||
log::info!("Server successfully started!");
|
||||
|
||||
command_helper::run();
|
||||
command_helper::run().await;
|
||||
}
|
||||
|
4
Server/src/servers.rs
Normal file
4
Server/src/servers.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub(crate) mod tcp_server;
|
||||
pub(crate) mod udp_server;
|
||||
|
||||
const SERVER_ADDR: &str = "127.0.0.1:12345";
|
120
Server/src/servers/tcp_server.rs
Normal file
120
Server/src/servers/tcp_server.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::{Mutex, mpsc};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use super::SERVER_ADDR;
|
||||
|
||||
pub(crate) static TCP_SERVER: LazyLock<Mutex<TcpServer>> =
|
||||
LazyLock::new(|| Mutex::new(TcpServer::new()));
|
||||
|
||||
pub(crate) struct TcpServer {
|
||||
is_running: bool,
|
||||
clients: HashMap<SocketAddr, JoinHandle<()>>,
|
||||
shutdown_tx: Option<mpsc::Sender<()>>,
|
||||
}
|
||||
|
||||
impl TcpServer {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
is_running: false,
|
||||
clients: HashMap::new(),
|
||||
shutdown_tx: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn start(&mut self) {
|
||||
if self.is_running {
|
||||
log::warn!("TCP server is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
match TcpListener::bind(SERVER_ADDR).await {
|
||||
Ok(listener) => {
|
||||
let (shutdown_tx, shutdown_rx) = mpsc::channel(1);
|
||||
self.is_running = true;
|
||||
self.shutdown_tx = Some(shutdown_tx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
Self::listen_to_clients(listener, shutdown_rx).await;
|
||||
});
|
||||
|
||||
log::info!("TCP Server started on {}", SERVER_ADDR);
|
||||
}
|
||||
Err(e) => log::error!("Failed to bind to address: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn stop(&mut self) {
|
||||
if !self.is_running {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_running = false;
|
||||
|
||||
if let Some(shutdown_tx) = self.shutdown_tx.take() {
|
||||
_ = shutdown_tx.send(()).await;
|
||||
}
|
||||
|
||||
for (addr, connection) in self.clients.drain() {
|
||||
log::info!("Closing connection to {}", addr);
|
||||
connection.abort();
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen_to_clients(listener: TcpListener, mut shutdown_rx: mpsc::Receiver<()>) {
|
||||
loop {
|
||||
tokio::select! {
|
||||
result = listener.accept() => {
|
||||
match result {
|
||||
Ok((socket, addr)) => {
|
||||
log::info!("New client connected: {addr}");
|
||||
|
||||
let task_handle = tokio::spawn(async move {
|
||||
if let Err(e) = Self::handle_client(socket, addr).await {
|
||||
log::error!("Client {addr} error: {e}");
|
||||
}
|
||||
log::info!("Client {addr} disconnected");
|
||||
});
|
||||
|
||||
let mut server = TCP_SERVER.lock().await;
|
||||
server.clients.insert(addr, task_handle);
|
||||
}
|
||||
Err(e) => log::error!("Couldn't get client: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
_ = shutdown_rx.recv() => {
|
||||
log::info!("TCP Server shutting down");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_client(mut socket: TcpStream, addr: SocketAddr) -> io::Result<()> {
|
||||
let mut buffer = [0; 1024];
|
||||
|
||||
loop {
|
||||
let len = socket.read(&mut buffer).await?;
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
log::debug!("Received {} bytes from {}", len, addr);
|
||||
|
||||
// TODO: Deserialize data
|
||||
socket.write_all(&buffer[..len]).await?;
|
||||
}
|
||||
|
||||
let mut server = TCP_SERVER.lock().await;
|
||||
server.clients.remove(&addr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
68
Server/src/servers/udp_server.rs
Normal file
68
Server/src/servers/udp_server.rs
Normal file
@ -0,0 +1,68 @@
|
||||
use std::io;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use super::SERVER_ADDR;
|
||||
|
||||
pub(crate) static UDP_SERVER: LazyLock<Mutex<UdpServer>> =
|
||||
LazyLock::new(|| Mutex::new(UdpServer::new()));
|
||||
|
||||
pub(crate) struct UdpServer {
|
||||
is_running: bool,
|
||||
}
|
||||
|
||||
impl UdpServer {
|
||||
fn new() -> Self {
|
||||
Self { is_running: false }
|
||||
}
|
||||
|
||||
pub(crate) async fn start(&mut self) {
|
||||
if self.is_running {
|
||||
log::warn!("UDP server is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
match UdpSocket::bind(SERVER_ADDR).await {
|
||||
Ok(socket) => {
|
||||
self.is_running = true;
|
||||
|
||||
tokio::spawn(async move {
|
||||
Self::handle_client(&socket)
|
||||
.await
|
||||
.unwrap_or_else(|e| log::error!("Failed to process data: {e}"))
|
||||
});
|
||||
|
||||
log::info!("UDP Server started on {}", SERVER_ADDR);
|
||||
}
|
||||
Err(e) => log::error!("Failed to bind to address: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn stop(&mut self) {
|
||||
if !self.is_running {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_running = false;
|
||||
}
|
||||
|
||||
async fn handle_client(socket: &UdpSocket) -> io::Result<()> {
|
||||
loop {
|
||||
let mut buffer = [0; 1024];
|
||||
let (len, addr) = socket.recv_from(&mut buffer).await?;
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
log::info!("Received message from client {addr}");
|
||||
|
||||
// TODO: Deserialize data
|
||||
let buffer = &buffer[..len];
|
||||
socket.send_to(buffer, addr).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,33 +1 @@
|
||||
use tonic::{Request, Response, Status};
|
||||
|
||||
use crate::protocol::game_service_server::GameService;
|
||||
use crate::protocol::{LoginRequest, LoginResponse, RequestResult, SignupRequest, SignupResponse};
|
||||
|
||||
pub(crate) struct GameServiceImpl;
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl GameService for GameServiceImpl {
|
||||
async fn login(
|
||||
&self,
|
||||
request: Request<LoginRequest>,
|
||||
) -> Result<Response<LoginResponse>, Status> {
|
||||
log::info!("User {} logged in!", request.get_ref().username);
|
||||
|
||||
Ok(Response::new(LoginResponse {
|
||||
result: RequestResult::Success.into(),
|
||||
message: "".into(),
|
||||
}))
|
||||
}
|
||||
|
||||
async fn signup(
|
||||
&self,
|
||||
request: Request<SignupRequest>,
|
||||
) -> Result<Response<SignupResponse>, Status> {
|
||||
log::info!("User {} signed up!", request.get_ref().username);
|
||||
|
||||
Ok(Response::new(SignupResponse {
|
||||
result: RequestResult::Success.into(),
|
||||
message: "".into(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
use std::net::UdpSocket;
|
||||
|
||||
use tokio::task;
|
||||
|
||||
pub(crate) struct UdpServer;
|
||||
|
||||
impl UdpServer {
|
||||
pub(crate) fn init() {
|
||||
match UdpSocket::bind("127.0.0.1:12345") {
|
||||
Ok(socket) => {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
let mut buf = [0; 1500];
|
||||
let (amt, src) = socket.recv_from(&mut buf).unwrap();
|
||||
|
||||
log::info!("Received message from client {src}");
|
||||
|
||||
// TODO: Process received data in an independent method.
|
||||
let buf = &buf[..amt];
|
||||
socket.send_to(buf, src).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => log::error!("Failed to bind to address: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user