Cleaned up imports a bit and added rustfmt.toml
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
tab_spaces=2
|
||||||
|
edition = "2021"
|
||||||
|
reorder_imports = true
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
reorder_modules = true
|
||||||
|
merge_derives = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
format_macro_matchers = true
|
||||||
|
format_macro_bodies = true
|
||||||
+57
-61
@@ -7,93 +7,89 @@ use crate::app::radarr::RadarrData;
|
|||||||
|
|
||||||
use super::network::RadarrEvent;
|
use super::network::RadarrEvent;
|
||||||
|
|
||||||
pub mod radarr;
|
|
||||||
pub(crate) mod key_binding;
|
pub(crate) mod key_binding;
|
||||||
|
pub mod radarr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
network_tx: Option<Sender<RadarrEvent>>,
|
network_tx: Option<Sender<RadarrEvent>>,
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
pub tick_until_poll: u64,
|
pub tick_until_poll: u64,
|
||||||
pub tick_count: u64,
|
pub tick_count: u64,
|
||||||
pub config: AppConfig,
|
pub config: AppConfig,
|
||||||
pub data: Data,
|
pub data: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(
|
pub fn new(network_tx: Sender<RadarrEvent>, tick_until_poll: u64, config: AppConfig) -> Self {
|
||||||
network_tx: Sender<RadarrEvent>,
|
App {
|
||||||
tick_until_poll: u64,
|
network_tx: Some(network_tx),
|
||||||
config: AppConfig
|
tick_until_poll,
|
||||||
) -> Self {
|
config,
|
||||||
App {
|
..App::default()
|
||||||
network_tx: Some(network_tx),
|
}
|
||||||
tick_until_poll,
|
}
|
||||||
config,
|
|
||||||
..App::default()
|
pub async fn dispatch(&mut self, action: RadarrEvent) {
|
||||||
}
|
if let Some(network_tx) = &self.network_tx {
|
||||||
|
if let Err(e) = network_tx.send(action).await {
|
||||||
|
error!("Failed to send event. {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.tick_count = 0;
|
||||||
|
// self.data = Data::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn on_tick(&mut self) {
|
||||||
|
if self.tick_count % self.tick_until_poll == 0 {
|
||||||
|
self.dispatch(RadarrEvent::GetOverview).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn dispatch(&mut self, action: RadarrEvent) {
|
self.tick_count += 1;
|
||||||
if let Some(network_tx) = &self.network_tx {
|
}
|
||||||
if let Err(e) = network_tx.send(action).await {
|
|
||||||
error!("Failed to send event. {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.tick_count = 0;
|
|
||||||
// self.data = Data::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn on_tick(&mut self) {
|
|
||||||
if self.tick_count % self.tick_until_poll == 0 {
|
|
||||||
self.dispatch(RadarrEvent::GetOverview).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tick_count += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for App {
|
impl Default for App {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
App {
|
App {
|
||||||
network_tx: None,
|
network_tx: None,
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
title: "DevTools",
|
title: "DevTools",
|
||||||
tick_until_poll: 0,
|
tick_until_poll: 0,
|
||||||
tick_count: 0,
|
tick_count: 0,
|
||||||
config: AppConfig::default(),
|
config: AppConfig::default(),
|
||||||
data: Data::default()
|
data: Data::default(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub radarr_data: RadarrData,
|
pub radarr_data: RadarrData,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
pub radarr: RadarrConfig,
|
pub radarr: RadarrConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct RadarrConfig {
|
pub struct RadarrConfig {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
pub api_token: String
|
pub api_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RadarrConfig {
|
impl Default for RadarrConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
RadarrConfig {
|
RadarrConfig {
|
||||||
host: "localhost".to_string(),
|
host: "localhost".to_string(),
|
||||||
port: Some(7878),
|
port: Some(7878),
|
||||||
api_token: "".to_string()
|
api_token: "".to_string(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+32
-31
@@ -9,44 +9,45 @@ use crossterm::event::Event as CrosstermEvent;
|
|||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
|
||||||
pub enum InputEvent<T> {
|
pub enum InputEvent<T> {
|
||||||
KeyEvent(T),
|
KeyEvent(T),
|
||||||
Tick
|
Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Events {
|
pub struct Events {
|
||||||
_tx: Sender<InputEvent<Key>>,
|
_tx: Sender<InputEvent<Key>>,
|
||||||
rx: Receiver<InputEvent<Key>>
|
rx: Receiver<InputEvent<Key>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Events {
|
impl Events {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let tick_rate: Duration = Duration::from_millis(250);
|
let tick_rate: Duration = Duration::from_millis(250);
|
||||||
|
|
||||||
let event_tx = tx.clone();
|
let event_tx = tx.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut last_tick = Instant::now();
|
let mut last_tick = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
let timeout = tick_rate.checked_sub(last_tick.elapsed())
|
let timeout = tick_rate
|
||||||
.unwrap_or_else(|| Duration::from_secs(0));
|
.checked_sub(last_tick.elapsed())
|
||||||
if event::poll(timeout).unwrap() {
|
.unwrap_or_else(|| Duration::from_secs(0));
|
||||||
if let CrosstermEvent::Key(key) = event::read().unwrap() {
|
if event::poll(timeout).unwrap() {
|
||||||
let key = Key::from(key);
|
if let CrosstermEvent::Key(key) = event::read().unwrap() {
|
||||||
event_tx.send(InputEvent::KeyEvent(key)).unwrap();
|
let key = Key::from(key);
|
||||||
}
|
event_tx.send(InputEvent::KeyEvent(key)).unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if last_tick.elapsed() >= tick_rate {
|
if last_tick.elapsed() >= tick_rate {
|
||||||
event_tx.send(InputEvent::Tick).unwrap();
|
event_tx.send(InputEvent::Tick).unwrap();
|
||||||
last_tick = Instant::now();
|
last_tick = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events { _tx: tx, rx }
|
Events { _tx: tx, rx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&self) -> Result<InputEvent<Key>, mpsc::RecvError> {
|
pub fn next(&self) -> Result<InputEvent<Key>, mpsc::RecvError> {
|
||||||
self.rx.recv()
|
self.rx.recv()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-26
@@ -5,44 +5,47 @@ use crossterm::event::{KeyCode, KeyEvent};
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
Char(char),
|
Char(char),
|
||||||
Unknown
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Key {
|
impl Display for Key {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Key::Char(c) => write!(f, "<{}>", c),
|
Key::Char(c) => write!(f, "<{}>", c),
|
||||||
_ => write!(f, "<{:?}>", self)
|
_ => write!(f, "<{:?}>", self),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KeyEvent> for Key {
|
impl From<KeyEvent> for Key {
|
||||||
fn from(key_event: KeyEvent) -> Self {
|
fn from(key_event: KeyEvent) -> Self {
|
||||||
match key_event {
|
match key_event {
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Char(c),
|
code: KeyCode::Char(c),
|
||||||
..
|
..
|
||||||
} => Key::Char(c),
|
} => Key::Char(c),
|
||||||
_ => Key::Unknown
|
_ => Key::Unknown,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
|
|
||||||
use crate::event::key::Key;
|
use crate::event::key::Key;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_formatter() {
|
fn test_key_formatter() {
|
||||||
assert_eq!(format!("{}", Key::Char('q')), "<q>");
|
assert_eq!(format!("{}", Key::Char('q')), "<q>");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from() {
|
fn test_key_from() {
|
||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Char('q'))), Key::Char('q'))
|
assert_eq!(
|
||||||
}
|
Key::from(KeyEvent::from(KeyCode::Char('q'))),
|
||||||
}
|
Key::Char('q')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+46
-53
@@ -1,16 +1,17 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use crossterm::execute;
|
use crossterm::execute;
|
||||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen};
|
use crossterm::terminal::{
|
||||||
|
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
||||||
|
};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use tokio::sync::{mpsc, Mutex};
|
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
use tui::Terminal;
|
use tokio::sync::{mpsc, Mutex};
|
||||||
use tui::backend::CrosstermBackend;
|
use tui::backend::CrosstermBackend;
|
||||||
|
use tui::Terminal;
|
||||||
|
|
||||||
use utils::init_logging_config;
|
use utils::init_logging_config;
|
||||||
|
|
||||||
@@ -29,78 +30,70 @@ mod utils;
|
|||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
struct Cli {
|
struct Cli {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
log4rs::init_config(init_logging_config())?;
|
log4rs::init_config(init_logging_config())?;
|
||||||
Cli::parse();
|
Cli::parse();
|
||||||
|
|
||||||
let config = confy::load("managarr", "config")?;
|
let config = confy::load("managarr", "config")?;
|
||||||
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
|
let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
|
||||||
|
|
||||||
let app = Arc::new(Mutex::new(App::new(
|
let app = Arc::new(Mutex::new(App::new(sync_network_tx, 5000 / 250, config)));
|
||||||
sync_network_tx,
|
|
||||||
5000 / 250,
|
|
||||||
config
|
|
||||||
)));
|
|
||||||
|
|
||||||
let app_nw = Arc::clone(&app);
|
let app_nw = Arc::clone(&app);
|
||||||
|
|
||||||
std::thread::spawn(move || start_networking(sync_network_rx, &app_nw));
|
std::thread::spawn(move || start_networking(sync_network_rx, &app_nw));
|
||||||
|
|
||||||
info!("Checking if Radarr server is up and running...");
|
info!("Checking if Radarr server is up and running...");
|
||||||
app.lock().await.dispatch(RadarrEvent::HealthCheck).await;
|
app.lock().await.dispatch(RadarrEvent::HealthCheck).await;
|
||||||
|
|
||||||
simple_ui(&app).await?;
|
simple_ui(&app).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn start_networking(mut network_rx: Receiver<RadarrEvent>, app: &Arc<Mutex<App>>) {
|
async fn start_networking(mut network_rx: Receiver<RadarrEvent>, app: &Arc<Mutex<App>>) {
|
||||||
let network = Network::new(reqwest::Client::new(), app);
|
let network = Network::new(reqwest::Client::new(), app);
|
||||||
|
|
||||||
while let Some(network_event) = network_rx.recv().await {
|
while let Some(network_event) = network_rx.recv().await {
|
||||||
debug!("Received network event: {:?}", network_event);
|
debug!("Received network event: {:?}", network_event);
|
||||||
network.handle_radarr_event(network_event).await;
|
network.handle_radarr_event(network_event).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn simple_ui(app: &Arc<Mutex<App>>) -> Result<()> {
|
async fn simple_ui(app: &Arc<Mutex<App>>) -> Result<()> {
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
|
|
||||||
execute!(stdout, EnterAlternateScreen)?;
|
execute!(stdout, EnterAlternateScreen)?;
|
||||||
let backend = CrosstermBackend::new(stdout);
|
let backend = CrosstermBackend::new(stdout);
|
||||||
let mut terminal = Terminal::new(backend)?;
|
let mut terminal = Terminal::new(backend)?;
|
||||||
terminal.clear()?;
|
terminal.clear()?;
|
||||||
terminal.hide_cursor()?;
|
terminal.hide_cursor()?;
|
||||||
|
|
||||||
let input_events = Events::new();
|
let input_events = Events::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut app = app.lock().await;
|
let mut app = app.lock().await;
|
||||||
terminal.draw(|f| ui(f, &app))?;
|
terminal.draw(|f| ui(f, &app))?;
|
||||||
|
|
||||||
match input_events.next()? {
|
match input_events.next()? {
|
||||||
InputEvent::KeyEvent(key) => {
|
InputEvent::KeyEvent(key) => {
|
||||||
if key == Key::Char('q') {
|
if key == Key::Char('q') {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
InputEvent::Tick => {
|
|
||||||
app.on_tick().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
InputEvent::Tick => app.on_tick().await,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
terminal.show_cursor()?;
|
terminal.show_cursor()?;
|
||||||
disable_raw_mode()?;
|
disable_raw_mode()?;
|
||||||
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
|
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
|
||||||
terminal.show_cursor()?;
|
terminal.show_cursor()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -9,18 +9,18 @@ pub(crate) mod radarr;
|
|||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum RadarrEvent {
|
pub enum RadarrEvent {
|
||||||
HealthCheck,
|
HealthCheck,
|
||||||
GetOverview
|
GetOverview,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Network<'a> {
|
pub struct Network<'a> {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
|
|
||||||
pub app: &'a Arc<Mutex<App>>
|
pub app: &'a Arc<Mutex<App>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Network<'a> {
|
impl<'a> Network<'a> {
|
||||||
pub fn new(client: Client, app: &'a Arc<Mutex<App>>) -> Self {
|
pub fn new(client: Client, app: &'a Arc<Mutex<App>>) -> Self {
|
||||||
Network { client, app }
|
Network { client, app }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user