wip new console

This commit is contained in:
Luuk van Oijen
2023-11-21 17:24:14 +01:00
parent 67cec26979
commit d9e0761e07
7 changed files with 465 additions and 11 deletions

245
Cargo.lock generated
View File

@@ -17,6 +17,18 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@@ -26,6 +38,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -111,6 +129,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"crossterm",
"flate2",
"futures",
"lazy_static",
@@ -119,6 +138,7 @@ dependencies = [
"nalgebra",
"num_enum",
"pretty_env_logger",
"ratatui",
"reqwest",
"serde",
"serde-aux",
@@ -167,6 +187,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.0.83"
@@ -219,6 +245,31 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.4.1",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "either"
version = "1.9.0"
@@ -434,6 +485,16 @@ name = "hashbrown"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
@@ -592,12 +653,27 @@ dependencies = [
"hashbrown 0.14.2",
]
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.9"
@@ -631,12 +707,31 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "lru"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60"
dependencies = [
"hashbrown 0.14.2",
]
[[package]]
name = "lua-src"
version = "546.0.1"
@@ -694,6 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
@@ -898,6 +994,29 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "paste"
version = "1.0.14"
@@ -972,6 +1091,24 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "ratatui"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ebc917cfb527a566c37ecb94c7e3fd098353516fb4eb6bea17015ade0182425"
dependencies = [
"bitflags 2.4.1",
"cassowary",
"crossterm",
"indoc",
"itertools",
"lru",
"paste",
"strum",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "rawpointer"
version = "0.2.1"
@@ -1079,6 +1216,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.15"
@@ -1103,6 +1246,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.9.2"
@@ -1180,6 +1329,36 @@ dependencies = [
"serde",
]
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "simba"
version = "0.7.3"
@@ -1202,6 +1381,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "socket2"
version = "0.4.10"
@@ -1222,6 +1407,28 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "strum"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.39",
]
[[package]]
name = "syn"
version = "1.0.109"
@@ -1438,6 +1645,18 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "url"
version = "2.4.1"
@@ -1455,6 +1674,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.1"
@@ -1692,3 +1917,23 @@ dependencies = [
"cfg-if",
"windows-sys",
]
[[package]]
name = "zerocopy"
version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]

View File

@@ -28,3 +28,6 @@ toml = "0.5"
flate2 = "1.0"
mlua = { version = "0.9.1", features = ["lua54", "vendored", "send"] }
ratatui = "0.24.0"
crossterm = "0.27.0"

View File

@@ -47,7 +47,7 @@ pub async fn backend_heartbeat(config: std::sync::Arc<crate::config::Config>, mu
if let Some(status) = status {
trace!("status update: {:?}", status);
info.players = status.player_count;
info.playerslist = status.player_list.clone();
info.playerslist = status.player_list.iter().map(|(_id, name)| format!("{};", name)).collect();
}
}
}
@@ -64,7 +64,7 @@ async fn heartbeat_post(heartbeat_info: &HeartbeatInfo) {
.await
{
Ok(resp) => {
debug!("heartbeat response:\n{:?}", resp.text().await);
trace!("heartbeat response:\n{:?}", resp.text().await);
},
Err(e) => error!("Heartbeat error occured: {e}"),
}

38
src/logger.rs Normal file
View File

@@ -0,0 +1,38 @@
use log::{Record, Level, Metadata, SetLoggerError, LevelFilter};
use std::sync::Mutex;
lazy_static! {
static ref LOG_BUFFER: Mutex<Vec<(Level, String)>> = Mutex::new(Vec::new());
}
struct BufferedLogger;
impl log::Log for BufferedLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let msg = format!("{}", record.args());
let mut lock = LOG_BUFFER.lock().expect("Logging lock poisoned!");
lock.push((record.level(), msg));
}
}
fn flush(&self) {}
}
static LOGGER: BufferedLogger = BufferedLogger;
pub fn init(filter: LevelFilter) -> Result<(), SetLoggerError> {
log::set_logger(&LOGGER)
.map(|()| log::set_max_level(filter))
}
pub async fn drain_log_buffer() -> Vec<(Level, String)> {
let mut lock = LOG_BUFFER.lock().expect("Logging lock poisoned!");
let v = lock.drain(..).collect();
drop(lock);
v
}

View File

@@ -5,6 +5,8 @@
use std::sync::Arc;
use tokio::sync::mpsc;
mod logger;
mod tui;
mod server;
mod config;
mod heartbeat;
@@ -12,12 +14,13 @@ mod heartbeat;
#[tokio::main]
async fn main() {
// pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::max()).init();
pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::Debug).init();
// pretty_env_logger::formatted_timed_builder().filter_level(log::LevelFilter::Debug).init();
logger::init(log::LevelFilter::max()).expect("Failed to enable logger!");
let mut user_config: config::Config = toml::from_str(
&std::fs::read_to_string("ServerConfig.toml")
.map_err(|_| error!("Failed to read config file!"))
.expect("Failed to read config file!")
&std::fs::read_to_string("ServerConfig.toml")
.map_err(|_| error!("Failed to read config file!"))
.expect("Failed to read config file!")
)
.map_err(|_| error!("Failed to parse config file!"))
.expect("Failed to parse config file!");
@@ -43,10 +46,14 @@ async fn main() {
let user_config = Arc::new(user_config);
server_main(user_config).await;
let (cmd_tx, cmd_rx) = mpsc::channel(100);
tokio::spawn(tui::tui_main(user_config.clone(), cmd_tx));
server_main(user_config, cmd_rx).await;
}
async fn server_main(user_config: Arc<config::Config>) {
async fn server_main(user_config: Arc<config::Config>, mut cmd_rx: mpsc::Receiver<Vec<String>>) {
let (hb_tx, hb_rx) = mpsc::channel(100);
tokio::spawn(heartbeat::backend_heartbeat(user_config.clone(), hb_rx));
@@ -89,9 +96,25 @@ async fn server_main(user_config: Arc<config::Config>) {
let new_status = server.get_server_status();
if status != new_status {
trace!("WHAT");
status = new_status;
hb_tx.send(status.clone()).await;
}
// Process commands
match cmd_rx.try_recv() {
Ok(cmd) => if cmd.len() > 0 {
match cmd[0].as_str() {
"exit" => break,
_ => info!("Unknown command!"),
}
} else {
// what!
},
Err(mpsc::error::TryRecvError::Empty) => {},
Err(e) => {
error!("Error: {e}");
break;
},
}
}
}

View File

@@ -74,7 +74,7 @@ fn load_plugins() -> Vec<Plugin> {
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ServerStatus {
pub player_count: usize,
pub player_list: String,
pub player_list: Vec<(u8, String)>,
pub max_players: usize,
}
@@ -320,7 +320,7 @@ impl Server {
ServerStatus {
player_count: self.clients.len(),
player_list: self.clients.iter().map(|client| {
format!("{};", &client.get_name())
(client.id, client.get_name().to_string())
}).collect(),
// max_players: self.max_players, // TODO: Support this
max_players: self.config.general.max_players,

145
src/tui.rs Normal file
View File

@@ -0,0 +1,145 @@
use std::sync::Arc;
use std::io::{stdout, Result};
use std::collections::VecDeque;
use log::Level;
use crossterm::{
event::{self, KeyCode, KeyEventKind},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
};
use ratatui::{
prelude::*,
widgets::{Paragraph, Block, Borders},
};
use tokio::sync::mpsc;
use crate::config::Config;
pub async fn tui_main(config: Arc<Config>, cmd_tx: mpsc::Sender<Vec<String>>) {
let mut tui = Tui::new().expect("Failed to initialize tui!");
'app: loop {
if tui.update().await.expect("Failed to run tui.update!") {
cmd_tx.send(vec!["exit".to_string()]).await.unwrap();
break 'app;
}
tui.draw().expect("Failed to run tui.draw!");
}
}
struct Tui {
terminal: Terminal<CrosstermBackend<std::io::Stdout>>,
log_buffer: VecDeque<(Level, String)>,
input: String,
}
impl Drop for Tui {
fn drop(&mut self) {
if let Err(e) = self.cleanup() {
eprintln!("Error occured related to the TUI: {}", e);
}
}
}
impl Tui {
fn new() -> Result<Self> {
stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?;
let terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
Ok(Self {
terminal,
log_buffer: VecDeque::new(),
input: String::new(),
})
}
fn cleanup(&self) -> Result<()> {
stdout().execute(LeaveAlternateScreen)?;
disable_raw_mode()?;
Ok(())
}
async fn update(&mut self) -> Result<bool> {
for (level, msg) in crate::logger::drain_log_buffer().await {
self.log_buffer.push_front((level, msg));
if self.log_buffer.len() > 100 {
self.log_buffer.pop_back();
}
}
if event::poll(std::time::Duration::from_millis(16))? {
if let event::Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
return Ok(true);
}
}
}
Ok(false)
}
fn draw(&mut self) -> Result<()> {
self.terminal.draw(|frame| {
let area = frame.size();
let vert_layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![
Constraint::Length(area.height - 3),
Constraint::Length(3),
])
.split(area);
let horiz_layout = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![
Constraint::Percentage(70),
Constraint::Percentage(30),
])
.split(vert_layout[0]);
let mut lines = Vec::new();
for (i, (level, msg)) in self.log_buffer.iter().enumerate() {
if i >= (area.height as usize - 5) { break; }
let level_style = match level {
Level::Info => Style::default().green(),
Level::Warn => Style::default().yellow(),
Level::Error => Style::default().red(),
Level::Debug => Style::default().gray(),
Level::Trace => Style::default().cyan(),
};
lines.push(Line::from(vec![
Span::styled("[", Style::default()),
Span::styled(format!("{}", level), level_style),
Span::styled(format!("] {}", msg), Style::default()),
]));
}
lines.reverse();
frame.render_widget(
// Paragraph::new("[INFO] info!!!\n[DEBUG] debug!!!!").block(Block::new().borders(Borders::ALL)),
Paragraph::new(Text::from(lines)).block(Block::new().borders(Borders::ALL)),
horiz_layout[0],
);
frame.render_widget(
Paragraph::new("0 - luuk-bepis\n1 - lion guy\n2 - the_racc").block(Block::new().borders(Borders::ALL)),
horiz_layout[1],
);
frame.render_widget(
Paragraph::new(format!(" > {}", self.input)).block(Block::new().borders(Borders::ALL)),
vert_layout[1],
);
})?;
Ok(())
}
}