diff --git a/Cargo.toml b/Cargo.toml index bbec0c3..87bd201 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "ghost-eye" authors = ["str3tch "] description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost" -version = "0.3.17" +version = "0.3.18" edition = "2021" [dependencies] diff --git a/src/action.rs b/src/action.rs index aa0254d..ebcd227 100644 --- a/src/action.rs +++ b/src/action.rs @@ -33,6 +33,7 @@ pub enum Action { RemoveEraToWatch(u32), ClosePopup, + RotateSessionKeys, PayoutValidatorPopup(u32, bool), BalanceRequest([u8; 32], bool), diff --git a/src/components/validator/mod.rs b/src/components/validator/mod.rs index f04a055..39761fb 100644 --- a/src/components/validator/mod.rs +++ b/src/components/validator/mod.rs @@ -23,6 +23,7 @@ mod staking_details; mod reward_details; mod bond_popup; mod payout_popup; +mod rotate_popup; use stash_details::StashDetails; use staking_details::StakingDetails; @@ -36,6 +37,7 @@ use history::History; use withdrawals::Withdrawals; use bond_popup::BondPopup; use payout_popup::PayoutPopup; +use rotate_popup::RotatePopup; #[derive(Debug, Copy, Clone, PartialEq)] pub enum CurrentTab { @@ -49,6 +51,7 @@ pub enum CurrentTab { EventLogs, BondPopup, PayoutPopup, + RotatePopup, } pub trait PartialComponent: Component { @@ -81,6 +84,7 @@ impl Default for Validator { Box::new(EventLogs::default()), Box::new(BondPopup::default()), Box::new(PayoutPopup::default()), + Box::new(RotatePopup::default()), ], } } @@ -140,6 +144,7 @@ impl Component for Validator { match self.current_tab { CurrentTab::BondPopup | + CurrentTab::RotatePopup | CurrentTab::PayoutPopup => match key.code { KeyCode::Esc => { self.current_tab = self.previous_tab; @@ -174,6 +179,13 @@ impl Component for Validator { component.set_active(self.current_tab.clone()); } }, + KeyCode::Char('R') => { + self.previous_tab = self.current_tab; + self.current_tab = CurrentTab::RotatePopup; + for component in self.components.iter_mut() { + component.set_active(self.current_tab.clone()); + } + }, KeyCode::Char('B') => { self.previous_tab = self.current_tab; self.current_tab = CurrentTab::BondPopup; diff --git a/src/components/validator/rotate_popup.rs b/src/components/validator/rotate_popup.rs new file mode 100644 index 0000000..a5b296a --- /dev/null +++ b/src/components/validator/rotate_popup.rs @@ -0,0 +1,107 @@ +use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; +use color_eyre::Result; +use ratatui::{ + layout::{Alignment, Constraint, Flex, Layout, Rect}, + widgets::{Block, Clear, Paragraph}, + Frame +}; +//use tokio::sync::mpsc::UnboundedSender; +use std::sync::mpsc::Sender; + +use super::{Component, PartialComponent, CurrentTab}; +use crate::{ + action::Action, + config::Config, + palette::StylePalette, + //types::{ActionLevel, ActionTarget}, +}; + +#[derive(Debug)] +pub struct RotatePopup { + is_active: bool, + //action_tx: Option>, + network_tx: Option>, + palette: StylePalette +} + +impl Default for RotatePopup { + fn default() -> Self { + Self::new() + } +} + +impl RotatePopup { + pub fn new() -> Self { + Self { + is_active: false, + //action_tx: None, + network_tx: None, + palette: StylePalette::default(), + } + } + + fn rotate_keys(&mut self) { + todo!(); + //if let Some(network_tx) = &self.network_tx { + // let _ = network_tx.send(Action::RotateSessionKeys); + //} + } +} + +impl PartialComponent for RotatePopup { + fn set_active(&mut self, current_tab: CurrentTab) { + match current_tab { + CurrentTab::RotatePopup => self.is_active = true, + _ => self.is_active = false, + }; + } +} + +impl Component for RotatePopup { + fn register_network_handler(&mut self, tx: Sender) -> Result<()> { + self.network_tx = Some(tx); + Ok(()) + } + + fn register_config_handler(&mut self, config: Config) -> Result<()> { + if let Some(style) = config.styles.get(&crate::app::Mode::Wallet) { + self.palette.with_normal_style(style.get("normal_style").copied()); + self.palette.with_normal_border_style(style.get("normal_border_style").copied()); + self.palette.with_normal_title_style(style.get("normal_title_style").copied()); + self.palette.with_popup_style(style.get("popup_style").copied()); + self.palette.with_popup_title_style(style.get("popup_title_style").copied()); + } + Ok(()) + } + fn handle_key_event(&mut self, key: KeyEvent) -> Result> { + if self.is_active && key.kind == KeyEventKind::Press { + match key.code { + KeyCode::Enter => self.rotate_keys(), + KeyCode::Esc => self.is_active = false, + _ => {}, + }; + } + Ok(None) + } + + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + if self.is_active { + let (border_style, border_type) = self.palette.create_popup_style(); + let popup = Paragraph::new(" Do you want to proceed key rotation?") + .block(Block::bordered() + .border_style(border_style) + .border_type(border_type) + .title_style(self.palette.create_popup_title_style()) + .title_alignment(Alignment::Right) + .title("Enter to proceed / Esc to close")); + let v = Layout::vertical([Constraint::Max(3)]).flex(Flex::Center); + let h = Layout::horizontal([Constraint::Max(50)]).flex(Flex::Center); + let [area] = v.areas(area); + let [area] = h.areas(area); + + frame.render_widget(Clear, area); + frame.render_widget(popup, area); + } + Ok(()) + } +} diff --git a/src/components/validator/stash_info.rs b/src/components/validator/stash_info.rs index dc42484..95379d0 100644 --- a/src/components/validator/stash_info.rs +++ b/src/components/validator/stash_info.rs @@ -48,7 +48,7 @@ pub struct StashInfo { stash_address: String, session_keys: std::collections::HashMap, key_names: &'static [&'static str], - file_path: PathBuf, + stash_filepath: PathBuf, } impl Default for StashInfo { @@ -70,7 +70,7 @@ impl StashInfo { stash_pair: None, session_keys: Default::default(), key_names: &["gran", "babe", "audi", "slow"], - file_path: PathBuf::from("/etc/ghost/stash-key"), + stash_filepath: PathBuf::from("/etc/ghost/stash-key"), } } @@ -127,7 +127,7 @@ impl StashInfo { } fn read_or_create_stash(&mut self) -> Result<()> { - match File::open(&self.file_path) { + match File::open(&self.stash_filepath) { Ok(file) => { let reader = BufReader::new(file); if let Some(Ok(line)) = reader.lines().next() { @@ -157,7 +157,7 @@ impl StashInfo { Ok(()) } else { self.log_event( - format!("file at '{:?}' is empty, trying to create new key", &self.file_path), + format!("file at '{:?}' is empty, trying to create new key", &self.stash_filepath), ActionLevel::Warn); self.generate_and_save_new_key() @@ -165,7 +165,7 @@ impl StashInfo { }, Err(_) => { self.log_event( - format!("file at '{:?}' not found, trying to create new key", &self.file_path), + format!("file at '{:?}' not found, trying to create new key", &self.stash_filepath), ActionLevel::Warn); self.generate_and_save_new_key() @@ -181,12 +181,12 @@ impl StashInfo { .to_ss58check_with_version(Ss58AddressFormat::custom(1996)); let pair_signer = PairSigner::::new(pair); - let mut new_file = File::create(&self.file_path)?; + let mut new_file = File::create(&self.stash_filepath)?; writeln!(new_file, "0x{}", &secret_seed)?; self.initiate_stash_info(account_id, seed); self.log_event( - format!("new stash key {} created and stored at {:?}", &address, self.file_path), + format!("new stash key {} created and stored at {:?}", &address, self.stash_filepath), ActionLevel::Info); self.stash_address = address;