Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
use crate::{cli, Message, Shutdown, LOG};
|
2020-08-31 08:41:11 +00:00
|
|
|
use crossterm::{
|
|
|
|
event::{DisableMouseCapture, EnableMouseCapture},
|
|
|
|
execute,
|
|
|
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
|
|
};
|
|
|
|
use std::{
|
2021-03-09 19:12:57 +00:00
|
|
|
io,
|
2020-09-01 14:33:41 +00:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
mpsc, Arc,
|
|
|
|
},
|
2020-08-31 08:41:11 +00:00
|
|
|
time::Duration,
|
|
|
|
};
|
2021-03-13 06:48:30 +00:00
|
|
|
use tracing::{debug, error, warn};
|
2020-08-31 08:41:11 +00:00
|
|
|
use tui::{
|
|
|
|
backend::CrosstermBackend,
|
|
|
|
layout::Rect,
|
|
|
|
text::Text,
|
|
|
|
widgets::{Block, Borders, Paragraph, Wrap},
|
|
|
|
Terminal,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Tui {
|
2020-09-20 02:40:26 +00:00
|
|
|
pub msg_r: mpsc::Receiver<Message>,
|
2020-08-31 08:41:11 +00:00
|
|
|
background: Option<std::thread::JoinHandle<()>>,
|
2020-10-03 19:10:34 +00:00
|
|
|
basic: bool,
|
2020-08-31 12:38:54 +00:00
|
|
|
running: Arc<AtomicBool>,
|
2020-08-31 08:41:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Tui {
|
|
|
|
fn handle_events(input: &mut String, msg_s: &mut mpsc::Sender<Message>) {
|
|
|
|
use crossterm::event::*;
|
|
|
|
if let Event::Key(event) = read().unwrap() {
|
|
|
|
match event.code {
|
|
|
|
KeyCode::Char('c') => {
|
|
|
|
if event.modifiers.contains(KeyModifiers::CONTROL) {
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
msg_s
|
|
|
|
.send(Message::Shutdown {
|
|
|
|
command: Shutdown::Immediate,
|
|
|
|
})
|
|
|
|
.unwrap()
|
2020-08-31 08:41:11 +00:00
|
|
|
} else {
|
|
|
|
input.push('c');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
KeyCode::Char(c) => input.push(c),
|
|
|
|
KeyCode::Backspace => {
|
|
|
|
input.pop();
|
|
|
|
},
|
|
|
|
KeyCode::Enter => {
|
2020-09-07 11:31:32 +00:00
|
|
|
debug!(?input, "tui mode: command entered");
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
cli::parse_command(input, msg_s);
|
2020-08-31 08:41:11 +00:00
|
|
|
|
|
|
|
*input = String::new();
|
|
|
|
},
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 02:40:26 +00:00
|
|
|
pub fn run(basic: bool) -> Self {
|
2021-03-22 11:37:03 +00:00
|
|
|
let (msg_s, msg_r) = mpsc::channel();
|
2020-09-20 02:40:26 +00:00
|
|
|
let running = Arc::new(AtomicBool::new(true));
|
2020-10-05 08:56:28 +00:00
|
|
|
let running2 = Arc::clone(&running);
|
2020-08-31 08:41:11 +00:00
|
|
|
|
2021-03-22 11:37:03 +00:00
|
|
|
let builder = std::thread::Builder::new().name("tui_runner".to_owned());
|
2020-09-20 02:40:26 +00:00
|
|
|
let background = if basic {
|
2021-03-22 11:37:03 +00:00
|
|
|
builder.spawn(|| Self::work_b(running2, msg_s)).unwrap();
|
2020-09-20 02:40:26 +00:00
|
|
|
None
|
2020-09-02 11:47:17 +00:00
|
|
|
} else {
|
2021-03-22 11:37:03 +00:00
|
|
|
Some(builder.spawn(|| Self::work_e(running2, msg_s)).unwrap())
|
2020-09-20 02:40:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Self {
|
|
|
|
msg_r,
|
|
|
|
background,
|
|
|
|
basic,
|
|
|
|
running,
|
2020-09-02 11:47:17 +00:00
|
|
|
}
|
2020-08-31 08:41:11 +00:00
|
|
|
}
|
|
|
|
|
2021-03-22 11:37:03 +00:00
|
|
|
/// In a seperate Thread
|
|
|
|
fn work_b(running: Arc<AtomicBool>, mut msg_s: mpsc::Sender<Message>) {
|
|
|
|
while running.load(Ordering::Relaxed) {
|
|
|
|
let mut line = String::new();
|
|
|
|
|
|
|
|
match io::stdin().read_line(&mut line) {
|
|
|
|
Err(e) => {
|
|
|
|
error!(
|
|
|
|
?e,
|
|
|
|
"couldn't read from stdin, cli commands are disabled now!"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
},
|
|
|
|
Ok(0) => {
|
|
|
|
//Docker seem to send EOF all the time
|
|
|
|
warn!("EOF received, cli commands are disabled now!");
|
|
|
|
break;
|
|
|
|
},
|
|
|
|
Ok(_) => {
|
|
|
|
debug!(?line, "basic mode: command entered");
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
crate::cli::parse_command(&line, &mut msg_s);
|
2021-03-22 11:37:03 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// In a seperate Thread
|
|
|
|
fn work_e(running: Arc<AtomicBool>, mut msg_s: mpsc::Sender<Message>) {
|
|
|
|
// Start the tui
|
|
|
|
let mut stdout = io::stdout();
|
|
|
|
execute!(stdout, EnterAlternateScreen, EnableMouseCapture).unwrap();
|
|
|
|
|
|
|
|
enable_raw_mode().unwrap();
|
|
|
|
|
|
|
|
let backend = CrosstermBackend::new(stdout);
|
|
|
|
let mut terminal = Terminal::new(backend).unwrap();
|
|
|
|
|
|
|
|
let mut input = String::new();
|
|
|
|
|
|
|
|
if let Err(e) = terminal.clear() {
|
|
|
|
error!(?e, "couldn't clean terminal");
|
|
|
|
};
|
|
|
|
|
|
|
|
while running.load(Ordering::Relaxed) {
|
|
|
|
if let Err(e) = terminal.draw(|f| {
|
|
|
|
let (log_rect, input_rect) = if f.size().height > 6 {
|
|
|
|
let mut log_rect = f.size();
|
|
|
|
log_rect.height -= 3;
|
|
|
|
|
|
|
|
let mut input_rect = f.size();
|
|
|
|
input_rect.y = input_rect.height - 3;
|
|
|
|
input_rect.height = 3;
|
|
|
|
|
|
|
|
(log_rect, input_rect)
|
|
|
|
} else {
|
|
|
|
(f.size(), Rect::default())
|
|
|
|
};
|
|
|
|
|
|
|
|
let block = Block::default().borders(Borders::ALL);
|
|
|
|
|
|
|
|
let wrap = Wrap {
|
|
|
|
scroll_callback: Some(Box::new(|text_area, lines| {
|
|
|
|
LOG.resize(text_area.height as usize);
|
|
|
|
let len = lines.len() as u16;
|
|
|
|
(len.saturating_sub(text_area.height), 0)
|
|
|
|
})),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let logger = Paragraph::new(LOG.inner.lock().unwrap().clone())
|
|
|
|
.block(block)
|
|
|
|
.wrap(wrap);
|
|
|
|
f.render_widget(logger, log_rect);
|
|
|
|
|
|
|
|
let text: Text = input.as_str().into();
|
|
|
|
|
|
|
|
let block = Block::default().borders(Borders::ALL);
|
|
|
|
let size = block.inner(input_rect);
|
|
|
|
|
|
|
|
let x = (size.x + text.width() as u16).min(size.width);
|
|
|
|
|
|
|
|
let input_field = Paragraph::new(text).block(block);
|
|
|
|
f.render_widget(input_field, input_rect);
|
|
|
|
|
|
|
|
f.set_cursor(x, size.y);
|
|
|
|
}) {
|
|
|
|
warn!(?e, "couldn't draw frame");
|
|
|
|
};
|
|
|
|
if crossterm::event::poll(Duration::from_millis(100)).unwrap() {
|
|
|
|
Self::handle_events(&mut input, &mut msg_s);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-03 19:10:34 +00:00
|
|
|
pub fn shutdown(basic: bool) {
|
|
|
|
if !basic {
|
|
|
|
let mut stdout = io::stdout();
|
|
|
|
execute!(stdout, LeaveAlternateScreen, DisableMouseCapture).unwrap();
|
|
|
|
disable_raw_mode().unwrap();
|
|
|
|
}
|
2020-08-31 08:41:11 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-31 12:38:54 +00:00
|
|
|
|
|
|
|
impl Drop for Tui {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.running.store(false, Ordering::Relaxed);
|
|
|
|
self.background.take().map(|m| m.join());
|
2020-10-03 19:10:34 +00:00
|
|
|
Tui::shutdown(self.basic);
|
2020-08-31 12:38:54 +00:00
|
|
|
}
|
|
|
|
}
|