|
|
|
@ -10,47 +10,42 @@ use crossterm::{ |
|
|
|
terminal::{Clear, ClearType}, |
|
|
|
}; |
|
|
|
|
|
|
|
use fern::colors::{ColoredLevelConfig, Color}; |
|
|
|
pub fn setup() -> Result<(Close, Stdin<String>), fern::InitError> { |
|
|
|
let (stdout, stdin, close, join_handle) = TerminalHandler::new(|x| { |
|
|
|
if x == "sv_cheats" { |
|
|
|
log::info!("CHEATS ENABLED") |
|
|
|
} |
|
|
|
x |
|
|
|
}); |
|
|
|
let colors_line = ColoredLevelConfig::new() |
|
|
|
.error(Color::Red) |
|
|
|
.warn(Color::Yellow) |
|
|
|
// we actually don't need to specify the color for debug and info, they are white by default
|
|
|
|
.info(Color::White) |
|
|
|
.debug(Color::BrightBlack) |
|
|
|
// depending on the terminals color scheme, this is the same as the background color
|
|
|
|
.trace(Color::BrightBlack); |
|
|
|
let colors_level = colors_line.clone().info(Color::Green).debug(Color::BrightBlack); |
|
|
|
let stdout_logger = fern::Dispatch::new() |
|
|
|
.format(move |out, message, record| { |
|
|
|
out.finish(format_args!( |
|
|
|
"{colors_line}{}[{}{colors_line}][{}] {}\x1B[0m", |
|
|
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), |
|
|
|
colors_level.clone().color(record.level()), |
|
|
|
record.target(), |
|
|
|
message, |
|
|
|
colors_line = format!("\x1B[{}m", colors_line.clone().get_color(&record.level()).to_fg_str()), |
|
|
|
// colors_level = colors_level.clone().get_color(&record.level()).to_fg_str(),
|
|
|
|
)) |
|
|
|
}) |
|
|
|
.level(log::LevelFilter::Debug) |
|
|
|
use fern::colors::{Color, ColoredLevelConfig}; |
|
|
|
|
|
|
|
mod color_message; |
|
|
|
use color_message::print_line; |
|
|
|
|
|
|
|
// TODO: Cleanup
|
|
|
|
|
|
|
|
pub fn setup( |
|
|
|
properties: &crate::server_properties::ServerProperties, |
|
|
|
) -> Result<(Close, Stdin<String>), fern::InitError> { |
|
|
|
let (stdout, stdin, close, join_handle) = TerminalHandler::new( |
|
|
|
|x| { |
|
|
|
if x == "sv_cheats" { |
|
|
|
log::info!("CHEATS ENABLED") |
|
|
|
} |
|
|
|
x |
|
|
|
}, |
|
|
|
properties.use_colors, |
|
|
|
); |
|
|
|
|
|
|
|
// let simple_formatter = |out: fern::FormatCallback, message: _, record: &log::Record| {
|
|
|
|
// out.finish(format_args!(
|
|
|
|
// "{}[{}][{}] {}",
|
|
|
|
// chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
|
|
|
|
// record.level(),
|
|
|
|
// record.target(),
|
|
|
|
// message,
|
|
|
|
// ))
|
|
|
|
// };
|
|
|
|
let stdout_logger = if properties.use_colors { |
|
|
|
colored_formatter(fern::Dispatch::new()) |
|
|
|
} else { |
|
|
|
simple_formatter(fern::Dispatch::new()) |
|
|
|
} |
|
|
|
.chain(stdout); |
|
|
|
let file = fern::Dispatch::new().format(|out, message, record| { |
|
|
|
out.finish(format_args!( |
|
|
|
"{}[{}][{}] {}", |
|
|
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), |
|
|
|
record.level(), |
|
|
|
record.target(), |
|
|
|
message, |
|
|
|
)) |
|
|
|
}) |
|
|
|
.chain( |
|
|
|
let file = simple_formatter(fern::Dispatch::new()).chain( |
|
|
|
std::fs::OpenOptions::new() |
|
|
|
.write(true) |
|
|
|
.create(true) |
|
|
|
@ -59,16 +54,67 @@ pub fn setup() -> Result<(Close, Stdin<String>), fern::InitError> { |
|
|
|
); |
|
|
|
|
|
|
|
fern::Dispatch::new() |
|
|
|
.level(log::LevelFilter::Debug) |
|
|
|
.level_for("h2::codec", log::LevelFilter::Info) |
|
|
|
.level_for("tokio::codec", log::LevelFilter::Info) |
|
|
|
.level_for("sqlx::query", log::LevelFilter::Info) |
|
|
|
.chain(stdout_logger) |
|
|
|
.chain(file) |
|
|
|
.apply()?; |
|
|
|
log::warn!("TEST1"); |
|
|
|
log::error!("TEST2"); |
|
|
|
log::info!("Saving output to output.log"); |
|
|
|
// std::process::exit(1);
|
|
|
|
Ok((Close{close, handle: join_handle}, stdin)) |
|
|
|
Ok(( |
|
|
|
Close { |
|
|
|
close, |
|
|
|
handle: join_handle, |
|
|
|
}, |
|
|
|
stdin, |
|
|
|
)) |
|
|
|
} |
|
|
|
|
|
|
|
fn simple_formatter(d: fern::Dispatch) -> fern::Dispatch { |
|
|
|
d.format( |
|
|
|
|out: fern::FormatCallback, message: _, record: &log::Record| { |
|
|
|
out.finish(format_args!( |
|
|
|
"{}[{}][{}] {}", |
|
|
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), |
|
|
|
record.level(), |
|
|
|
record.target(), |
|
|
|
message, |
|
|
|
)) |
|
|
|
}, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
fn colored_formatter(d: fern::Dispatch) -> fern::Dispatch { |
|
|
|
let colors_line = ColoredLevelConfig::new() |
|
|
|
.error(Color::Red) |
|
|
|
.warn(Color::Yellow) |
|
|
|
// we actually don't need to specify the color for debug and info, they are white by default
|
|
|
|
.info(Color::White) |
|
|
|
.debug(Color::BrightBlack) |
|
|
|
// depending on the terminals color scheme, this is the same as the background color
|
|
|
|
.trace(Color::BrightBlack); |
|
|
|
let colors_level = colors_line |
|
|
|
.clone() |
|
|
|
.info(Color::Green) |
|
|
|
.debug(Color::BrightBlack); |
|
|
|
d.format( |
|
|
|
move |out: fern::FormatCallback, message: _, record: &log::Record| { |
|
|
|
out.finish(format_args!( |
|
|
|
"{colors_line}{}[{}{colors_line}][{}] {}\x1B[0m", |
|
|
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), |
|
|
|
colors_level.clone().color(record.level()), |
|
|
|
record.target(), |
|
|
|
message, |
|
|
|
colors_line = format!( |
|
|
|
"\x1B[{}m", |
|
|
|
colors_line.clone().get_color(&record.level()).to_fg_str() |
|
|
|
), |
|
|
|
// colors_level = colors_level.clone().get_color(&record.level()).to_fg_str(),
|
|
|
|
)) |
|
|
|
}, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
pub type Stdout = mpsc::Sender<String>; |
|
|
|
@ -83,8 +129,9 @@ where |
|
|
|
stdin: mpsc::Sender<T>, |
|
|
|
close: mpsc::Receiver<()>, |
|
|
|
handler: F, |
|
|
|
lines: LimitedVec<String>, |
|
|
|
command: String, |
|
|
|
lines: LimitedVec<String>, |
|
|
|
command: String, |
|
|
|
use_colors: bool, |
|
|
|
} |
|
|
|
|
|
|
|
impl<T, F> TerminalHandler<T, F> |
|
|
|
@ -94,6 +141,7 @@ where |
|
|
|
{ |
|
|
|
fn new( |
|
|
|
handler: F, |
|
|
|
use_colors: bool, |
|
|
|
) -> ( |
|
|
|
Stdout, |
|
|
|
Stdin<T>, |
|
|
|
@ -112,17 +160,16 @@ where |
|
|
|
stdin: stdin_send, |
|
|
|
close: close_recv, |
|
|
|
handler, |
|
|
|
lines: LimitedVec::new(crossterm::terminal::size().unwrap().1 as usize - 1), |
|
|
|
command: String::new(), |
|
|
|
lines: LimitedVec::new(crossterm::terminal::size().unwrap().1 as usize - 1), |
|
|
|
command: String::new(), |
|
|
|
use_colors, |
|
|
|
}; |
|
|
|
loop { |
|
|
|
if s.iterate() { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
queue!(stdout, crossterm::event::DisableMouseCapture).unwrap(); |
|
|
|
crossterm::terminal::disable_raw_mode().ok(); |
|
|
|
println!("Closing printing thread"); |
|
|
|
cleanup(); |
|
|
|
}); |
|
|
|
(stdout_send, stdin_recv, close_send, join_handle) |
|
|
|
} |
|
|
|
@ -132,46 +179,42 @@ where |
|
|
|
match self.close.try_recv() { |
|
|
|
Err(mpsc::TryRecvError::Empty) => (), |
|
|
|
_ => return true, |
|
|
|
} |
|
|
|
} |
|
|
|
while is_event_available() { |
|
|
|
match crossterm::event::read().unwrap() { |
|
|
|
Event::Resize(_cols, rows) => self.lines.size = rows as usize - 1, |
|
|
|
Event::Key(k) => match (k.code, k.modifiers) { |
|
|
|
(KeyCode::Char('c'), KeyModifiers::CONTROL) => { |
|
|
|
let mut stdout = std::io::stdout(); |
|
|
|
queue!(stdout, crossterm::event::DisableMouseCapture).unwrap(); |
|
|
|
crossterm::terminal::disable_raw_mode().unwrap(); |
|
|
|
stdout.flush().unwrap(); |
|
|
|
println!("Exiting server"); |
|
|
|
cleanup(); |
|
|
|
std::process::exit(0) |
|
|
|
} |
|
|
|
(k, _m) => { |
|
|
|
match k { |
|
|
|
KeyCode::Char(c) => self.command.push(c), |
|
|
|
KeyCode::Backspace => {self.command.pop();}, |
|
|
|
KeyCode::Enter => { |
|
|
|
log::info!(target: "COMMAND", "{}", self.command); |
|
|
|
match self.stdin.send((self.handler)(self.command.clone())) { |
|
|
|
Ok(_) => (), |
|
|
|
Err(e) => log::error!("{}", e), |
|
|
|
}; |
|
|
|
self.command = String::new(); |
|
|
|
} |
|
|
|
KeyCode::Esc => { |
|
|
|
self.lines.scroll_to_bottom(); |
|
|
|
} |
|
|
|
_ => () |
|
|
|
} |
|
|
|
}, |
|
|
|
(k, _m) => match k { |
|
|
|
KeyCode::Char(c) => self.command.push(c), |
|
|
|
KeyCode::Backspace => { |
|
|
|
self.command.pop(); |
|
|
|
} |
|
|
|
KeyCode::Enter => { |
|
|
|
log::info!(target: "command", " >> {}", self.command); |
|
|
|
match self.stdin.send((self.handler)(self.command.clone())) { |
|
|
|
Ok(_) => (), |
|
|
|
Err(e) => log::error!("{}", e), |
|
|
|
}; |
|
|
|
self.command = String::new(); |
|
|
|
} |
|
|
|
KeyCode::Esc => { |
|
|
|
self.lines.scroll_to_bottom(); |
|
|
|
} |
|
|
|
_ => (), |
|
|
|
}, |
|
|
|
}, |
|
|
|
Event::Mouse(m) => match m { |
|
|
|
MouseEvent::ScrollUp(_, _, _) => self.lines.scroll_up(), |
|
|
|
MouseEvent::ScrollDown(_, _, _) => self.lines.scroll_down(), |
|
|
|
_ => (), |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
updated = true; |
|
|
|
updated = true; |
|
|
|
} |
|
|
|
while let Some(x) = match self.stdout.try_recv() { |
|
|
|
Err(mpsc::TryRecvError::Empty) => None, |
|
|
|
@ -190,18 +233,44 @@ where |
|
|
|
// println!("Got stdout");
|
|
|
|
if updated { |
|
|
|
queue!(stdout, Clear(ClearType::All), MoveTo(0, 0)).unwrap(); |
|
|
|
for v in self.lines.iter() { |
|
|
|
queue!(stdout, Print(v), MoveToNextLine(1)).unwrap(); |
|
|
|
let mut i = 0; |
|
|
|
let size = crossterm::terminal::size().unwrap(); |
|
|
|
for v in self.lines.iter(self.use_colors) { |
|
|
|
print_line(&v, self.use_colors, &mut stdout); |
|
|
|
queue!(stdout, MoveToNextLine(1)).unwrap(); |
|
|
|
i += 1; |
|
|
|
if i >= size.1 as usize - 1 { |
|
|
|
break; |
|
|
|
} |
|
|
|
// println!("{}", v);
|
|
|
|
} |
|
|
|
let size = crossterm::terminal::size().unwrap(); |
|
|
|
queue!(stdout, MoveTo(0, size.1), Clear(ClearType::CurrentLine), Print(&self.command)).unwrap(); |
|
|
|
} |
|
|
|
queue!( |
|
|
|
stdout, |
|
|
|
MoveTo(0, size.1), |
|
|
|
// Clear(ClearType::CurrentLine),
|
|
|
|
Print(&format!(" >> {}", self.command)) |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
|
stdout.flush().unwrap(); |
|
|
|
} |
|
|
|
false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn cleanup() { |
|
|
|
let mut stdout = std::io::stdout(); |
|
|
|
queue!( |
|
|
|
stdout, |
|
|
|
Clear(ClearType::All), |
|
|
|
MoveTo(0, 0), |
|
|
|
crossterm::event::DisableMouseCapture |
|
|
|
) |
|
|
|
.unwrap(); |
|
|
|
crossterm::terminal::disable_raw_mode().unwrap(); |
|
|
|
stdout.flush().unwrap(); |
|
|
|
println!("Exiting server, output has been saved to output.log"); |
|
|
|
} |
|
|
|
|
|
|
|
impl<T, F> Drop for TerminalHandler<T, F> |
|
|
|
where |
|
|
|
T: Send + 'static, |
|
|
|
@ -218,15 +287,15 @@ fn is_event_available() -> bool { |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Close { |
|
|
|
close: mpsc::Sender<()>, |
|
|
|
handle: std::thread::JoinHandle<()>, |
|
|
|
close: mpsc::Sender<()>, |
|
|
|
handle: std::thread::JoinHandle<()>, |
|
|
|
} |
|
|
|
|
|
|
|
impl Close { |
|
|
|
pub fn close(self) { |
|
|
|
self.close.send(()).unwrap(); |
|
|
|
self.handle.join().unwrap(); |
|
|
|
println!("CLOSING"); |
|
|
|
self.close.send(()).unwrap(); |
|
|
|
self.handle.join().unwrap(); |
|
|
|
println!("CLOSING"); |
|
|
|
queue!(std::io::stdout(), crossterm::event::DisableMouseCapture).unwrap(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -249,15 +318,18 @@ impl<T> LimitedVec<T> { |
|
|
|
fn push(&mut self, v: T) { |
|
|
|
// while self.inner.len() >= self.size {
|
|
|
|
// self.inner.remove(0);
|
|
|
|
// }
|
|
|
|
if self.pos != 0 { |
|
|
|
self.pos += 1; |
|
|
|
} |
|
|
|
// }
|
|
|
|
if self.pos != 0 { |
|
|
|
self.pos += 1; |
|
|
|
} |
|
|
|
self.inner.push(v); |
|
|
|
// assert!(self.inner.len() <= self.size)
|
|
|
|
} |
|
|
|
|
|
|
|
fn iter(&self) -> std::slice::Iter<T> { |
|
|
|
fn iter<'a>(&'a self, use_colors: bool) -> Box<dyn Iterator<Item = String> + 'a> |
|
|
|
where |
|
|
|
T: std::fmt::Display, |
|
|
|
{ |
|
|
|
let start = if self.inner.len() < self.size { |
|
|
|
0 |
|
|
|
} else { |
|
|
|
@ -271,7 +343,24 @@ impl<T> LimitedVec<T> { |
|
|
|
if end < self.inner.len() { |
|
|
|
end = self.inner.len() |
|
|
|
} |
|
|
|
self.inner[start..end].iter() |
|
|
|
let iter = self.inner[start..end].iter(); |
|
|
|
|
|
|
|
let map = iter.enumerate().map(move |(i, x)| { |
|
|
|
format!( |
|
|
|
"{}{}", |
|
|
|
if use_colors { |
|
|
|
format!( |
|
|
|
"\x1B[{}m{:>5}\x1B[0m ", |
|
|
|
fern::colors::Color::BrightBlack.to_fg_str(), |
|
|
|
start + i |
|
|
|
) |
|
|
|
} else { |
|
|
|
String::new() |
|
|
|
}, |
|
|
|
x |
|
|
|
) |
|
|
|
}); |
|
|
|
Box::new(map) |
|
|
|
} |
|
|
|
|
|
|
|
fn scroll_up(&mut self) { |
|
|
|
|