rust_minecraft_server/src/server/mod.rs
2025-05-02 19:26:43 +03:00

97 lines
3.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::{error::Error, fmt::Display, net::TcpListener, sync::Arc, thread, time::Duration};
use context::ServerContext;
use ignore_result::Ignore;
use log::{error, info};
use player::context::ClientContext;
use protocol::handle_connection;
use rust_mc_proto::{MinecraftConnection, ProtocolError};
pub mod config;
pub mod data;
pub mod event;
pub mod player;
pub mod context;
pub mod protocol;
// Ошибки сервера
#[derive(Debug)]
pub enum ServerError {
UnknownPacket(String),
Protocol(ProtocolError),
ConnectionClosed,
SerTextComponent,
DeTextComponent,
UnexpectedState
}
impl Display for ServerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("{:?}", self))
}
}
impl Error for ServerError {}
// Делаем чтобы ProtocolError мог переделываться в наш ServerError
impl From<ProtocolError> for ServerError {
fn from(error: ProtocolError) -> ServerError {
match error {
// Если просто закрыто соединение, переделываем в нашу ошибку этого
ProtocolError::ConnectionClosedError => {
ServerError::ConnectionClosed
},
// Все остальное просто засовываем в обертку
error => {
ServerError::Protocol(error)
},
}
}
}
pub fn start_server(server: Arc<ServerContext>) {
// Биндим сервер где надо
let Ok(listener) = TcpListener::bind(&server.config.bind.host) else {
error!("Не удалось забиндить сервер на {}", &server.config.bind.host);
return;
};
info!("Сервер запущен на {}", &server.config.bind.host);
while let Ok((stream, addr)) = listener.accept() {
let server = server.clone();
thread::spawn(move || {
info!("Подключение: {}", addr);
// Установка таймаутов на чтение и запись
// По умолчанию пусть будет 5 секунд, надо будет сделать настройку через конфиг
stream.set_read_timeout(Some(Duration::from_secs(server.config.bind.timeout))).ignore();
stream.set_write_timeout(Some(Duration::from_secs(server.config.bind.timeout))).ignore();
// Оборачиваем стрим в майнкрафт конекшн лично для нашего удовольствия
let conn = MinecraftConnection::new(stream);
// Создаем контекст клиента
// Передавется во все листенеры и хандлеры чтобы определять именно этот клиент
let client = Arc::new(ClientContext::new(server.clone(), conn));
server.clients.insert(client.addr, client.clone());
// Обработка подключения
// Если ошибка -> выводим
match handle_connection(client.clone()) {
Ok(_) => {},
Err(ServerError::ConnectionClosed) => {},
Err(error) => {
error!("Ошибка подключения: {error:?}");
},
};
server.clients.remove(&client.addr);
info!("Отключение: {}", addr);
});
}
}