Pumpkin/pumpkin/src/main.rs
2024-08-07 13:32:48 +02:00

162 lines
5.4 KiB
Rust

use mio::net::TcpListener;
use mio::{Events, Interest, Poll, Token};
use std::io::{self};
use client::Client;
use commands::handle_command;
use config::AdvancedConfiguration;
use std::{collections::HashMap, rc::Rc, thread};
use client::interrupted;
use config::BasicConfiguration;
use server::Server;
// Setup some tokens to allow us to identify which event is for which socket.
const SERVER: Token = Token(0);
pub mod client;
pub mod commands;
pub mod config;
pub mod entity;
pub mod server;
pub mod util;
#[cfg(not(target_os = "wasi"))]
fn main() -> io::Result<()> {
use std::{cell::RefCell, time::Instant};
let time = Instant::now();
let basic_config = BasicConfiguration::load("configuration.toml");
let advanced_configuration = AdvancedConfiguration::load("features.toml");
simple_logger::SimpleLogger::new().init().unwrap();
// Create a poll instance.
let mut poll = Poll::new()?;
// Create storage for events.
let mut events = Events::with_capacity(128);
// Setup the TCP server socket.
let addr = format!(
"{}:{}",
basic_config.server_address, basic_config.server_port
)
.parse()
.unwrap();
let mut listener = TcpListener::bind(addr)?;
// Register the server with poll we can receive events for it.
poll.registry()
.register(&mut listener, SERVER, Interest::READABLE)?;
// Unique token for each incoming connection.
let mut unique_token = Token(SERVER.0 + 1);
let use_console = advanced_configuration.commands.use_console;
let mut connections: HashMap<Token, Rc<RefCell<Client>>> = HashMap::new();
let mut server = Server::new((basic_config, advanced_configuration));
log::info!("Started Server took {}ms", time.elapsed().as_millis());
log::info!("You now can connect to the server");
if use_console {
thread::spawn(move || {
let stdin = std::io::stdin();
loop {
let mut out = String::new();
stdin
.read_line(&mut out)
.expect("Failed to read console line");
handle_command(&mut commands::CommandSender::Console, out);
}
});
}
loop {
if let Err(err) = poll.poll(&mut events, None) {
if interrupted(&err) {
continue;
}
return Err(err);
}
for event in events.iter() {
match event.token() {
SERVER => loop {
// Received an event for the TCP server socket, which
// indicates we can accept an connection.
let (mut connection, address) = match listener.accept() {
Ok((connection, address)) => (connection, address),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
// If we get a `WouldBlock` error we know our
// listener has no more incoming connections queued,
// so we can return to polling and wait for some
// more.
break;
}
Err(e) => {
// If it was any other kind of error, something went
// wrong and we terminate with an error.
return Err(e);
}
};
if let Err(e) = connection.set_nodelay(true) {
log::warn!("failed to set TCP_NODELAY {e}");
}
log::info!("Accepted connection from: {}", address);
let token = next(&mut unique_token);
poll.registry().register(
&mut connection,
token,
Interest::READABLE.add(Interest::WRITABLE),
)?;
let rc_token = Rc::new(token);
let client = Rc::new(RefCell::new(Client::new(
Rc::clone(&rc_token),
connection,
addr,
)));
server.add_client(rc_token, Rc::clone(&client));
connections.insert(token, client);
},
token => {
// Maybe received an event for a TCP connection.
let done = if let Some(client) = connections.get_mut(&token) {
let mut client = client.borrow_mut();
client.poll(&mut server, event);
client.closed
} else {
// Sporadic events happen, we can safely ignore them.
false
};
if done {
if let Some(client) = connections.remove(&token) {
let mut client = client.borrow_mut();
server.remove_client(&token);
poll.registry().deregister(&mut client.connection)?;
}
}
}
}
}
}
}
fn next(current: &mut Token) -> Token {
let next = current.0;
current.0 += 1;
Token(next)
}
#[cfg(target_os = "wasi")]
fn main() {
panic!("can't bind to an address with wasi")
}