105 lines
2.8 KiB
Rust
105 lines
2.8 KiB
Rust
|
use std::{collections::HashMap, time::Duration, net::ToSocketAddrs};
|
||
|
|
||
|
use event::ServerEvent;
|
||
|
use log::{info, error};
|
||
|
use tokio::{net::TcpListener, sync::mpsc::{Sender, self}, select};
|
||
|
use uuid::Uuid;
|
||
|
|
||
|
use crate::{client::run_client, event::ClientEvent};
|
||
|
|
||
|
mod event;
|
||
|
mod protocol;
|
||
|
mod ser;
|
||
|
mod varint;
|
||
|
mod client;
|
||
|
|
||
|
pub type JsonValue = serde_json::Value;
|
||
|
|
||
|
#[derive(Clone, Debug)]
|
||
|
pub struct ClientInfo {
|
||
|
addr: String,
|
||
|
port: u16,
|
||
|
proto_version: i32,
|
||
|
proto_name: &'static str,
|
||
|
}
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub struct Player {
|
||
|
name: String,
|
||
|
uuid: Uuid,
|
||
|
}
|
||
|
|
||
|
struct Client {
|
||
|
tx: Sender<ServerEvent>,
|
||
|
keepalive: Option<i64>,
|
||
|
info: Option<ClientInfo>,
|
||
|
player: Option<Player>,
|
||
|
}
|
||
|
|
||
|
#[tokio::main]
|
||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
env_logger::init();
|
||
|
let socket_addr = "0.0.0.0:25565".to_socket_addrs()?.next().expect("invalid server address");
|
||
|
let listener = TcpListener::bind(socket_addr).await?;
|
||
|
let mut clients = HashMap::new();
|
||
|
let mut next_id = 0;
|
||
|
let (c_tx, mut c_rx) = mpsc::channel(16);
|
||
|
let mut keepalive = tokio::time::interval(Duration::from_secs(15));
|
||
|
info!("listening on {socket_addr}");
|
||
|
loop { select! {
|
||
|
conn = listener.accept() => {
|
||
|
let c_tx = c_tx.clone();
|
||
|
let (stream, addr) = conn?;
|
||
|
let id = next_id;
|
||
|
next_id += 1;
|
||
|
let (s_tx, s_rx) = mpsc::channel(16);
|
||
|
clients.insert(id, Client {
|
||
|
tx: s_tx,
|
||
|
keepalive: None,
|
||
|
info: None,
|
||
|
player: None,
|
||
|
});
|
||
|
info!("#{id} connected from {addr}");
|
||
|
tokio::spawn(async move {
|
||
|
let c_tx2 = c_tx.clone();
|
||
|
match run_client(id, stream, c_tx, s_rx).await {
|
||
|
Ok(_) => info!("client {id} disconnected"),
|
||
|
Err(e) => error!("client {id} error: {e}"),
|
||
|
}
|
||
|
c_tx2.send((id, ClientEvent::Disconnect)).await.unwrap();
|
||
|
});
|
||
|
},
|
||
|
_ = keepalive.tick() => {
|
||
|
for (_, client) in &mut clients {
|
||
|
if client.keepalive.is_some() {
|
||
|
client.tx.send(ServerEvent::Disconnect(Some("Failed to respond to keep alives".to_owned()))).await?;
|
||
|
} else if client.player.is_some() {
|
||
|
let data = 1;
|
||
|
client.keepalive = Some(data);
|
||
|
client.tx.send(ServerEvent::KeepAlive(data)).await?;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
ev = c_rx.recv() => {
|
||
|
let Some(ev) = ev else {
|
||
|
return Err("reciever closed".into());
|
||
|
};
|
||
|
let id = ev.0;
|
||
|
let client = clients.get_mut(&id).unwrap();
|
||
|
match ev.1 {
|
||
|
ClientEvent::Handshake(info) => client.info = Some(info),
|
||
|
ClientEvent::Join(player) => clients.get_mut(&id).unwrap().player = Some(player),
|
||
|
ClientEvent::Disconnect => { clients.remove(&id); },
|
||
|
ClientEvent::KeepAlive(data) => {
|
||
|
let client = clients.get_mut(&id).unwrap();
|
||
|
if client.keepalive == Some(data) {
|
||
|
client.keepalive = None;
|
||
|
} else {
|
||
|
client.keepalive = Some(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} }
|
||
|
}
|