Skip to content

Commit

Permalink
feat(launchpad): keep track of the nodes to start
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandSherwin authored and joshuef committed May 31, 2024
1 parent db88896 commit 23c0181
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 62 deletions.
2 changes: 1 addition & 1 deletion node-launchpad/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum Action {
SwitchInputMode(InputMode),

StoreDiscordUserName(String),
StoreAllocatedDiskSpace(usize),
StoreNodesToStart(usize),

Tick,
Render,
Expand Down
10 changes: 5 additions & 5 deletions node-launchpad/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ impl App {
let app_data = AppData::load()?;

let home = Home::new(
app_data.allocated_disk_space,
app_data.nodes_to_start,
&app_data.discord_username,
peers_args,
safenode_path,
)?;
let config = Config::new()?;
let discord_username_input = BetaProgramme::new(app_data.discord_username.clone());
let manage_nodes = ManageNodes::new(app_data.allocated_disk_space)?;
let manage_nodes = ManageNodes::new(app_data.nodes_to_start)?;
let footer = Footer::default();
let help = HelpPopUp::default();

Expand Down Expand Up @@ -180,9 +180,9 @@ impl App {
self.app_data.discord_username.clone_from(username);
self.app_data.save()?;
}
Action::StoreAllocatedDiskSpace(space) => {
debug!("Storing allocated disk space: {space:?}");
self.app_data.allocated_disk_space = space;
Action::StoreNodesToStart(count) => {
debug!("Storing nodes to start: {count:?}");
self.app_data.nodes_to_start = count;
self.app_data.save()?;
}
_ => {}
Expand Down
18 changes: 8 additions & 10 deletions node-launchpad/src/components/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use super::{
};
use crate::{
action::{Action, FooterActions, HomeActions},
components::manage_nodes::GB_PER_NODE,
config::Config,
mode::{InputMode, Scene},
style::{COOL_GREY, EUCALYPTUS, GHOST_WHITE, VERY_LIGHT_AZURE},
Expand Down Expand Up @@ -47,7 +46,7 @@ pub struct Home {
node_services: Vec<NodeServiceData>,
node_stats: NodesStats,
node_table_state: TableState,
allocated_disk_space: usize,
nodes_to_start: usize,
discord_username: String,
// Currently the node registry file does not support concurrent actions and thus can lead to
// inconsistent state. Another solution would be to have a file lock/db.
Expand All @@ -72,7 +71,7 @@ impl Home {
active: true,
node_services: Default::default(),
node_stats: NodesStats::new(),
allocated_disk_space,
nodes_to_start: allocated_disk_space,
node_table_state: Default::default(),
lock_registry: Default::default(),
discord_username: discord_username.to_string(),
Expand Down Expand Up @@ -219,8 +218,8 @@ impl Component for Home {
Scene::BetaProgramme | Scene::ManageNodes | Scene::HelpPopUp => self.active = true,
_ => self.active = false,
},
Action::StoreAllocatedDiskSpace(space) => {
self.allocated_disk_space = space;
Action::StoreNodesToStart(count) => {
self.nodes_to_start = count;
}
Action::StoreDiscordUserName(username) => {
let reset_safenode_services = (self.discord_username != username)
Expand All @@ -243,22 +242,21 @@ impl Component for Home {
return Ok(None);
}

if self.allocated_disk_space == 0 {
info!("Disk space not allocated. Ask for input.");
if self.nodes_to_start == 0 {
info!("Nodes to start not set. Ask for input.");
return Ok(Some(Action::HomeActions(HomeActions::TriggerManageNodes)));
}
if self.discord_username.is_empty() {
info!("Discord username not assigned. Ask for input.");
return Ok(Some(Action::HomeActions(HomeActions::TriggerBetaProgramme)));
}

let node_count = self.allocated_disk_space / GB_PER_NODE;
self.lock_registry = true;
let action_sender = self.get_actions_sender()?;
info!("Running maintain node count: {node_count:?}");
info!("Running maintain node count: {:?}", self.nodes_to_start);

maintain_n_running_nodes(
node_count as u16,
self.nodes_to_start as u16,
self.discord_username.clone(),
self.peers_args.clone(),
self.safenode_path.clone(),
Expand Down
106 changes: 61 additions & 45 deletions node-launchpad/src/components/manage_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ pub const GB: usize = MB * 1000;
pub struct ManageNodes {
/// Whether the component is active right now, capturing keystrokes + drawing things.
active: bool,
available_disk_space_bytes: usize,
allocated_space_input: Input,
available_disk_space_gb: usize,
nodes_to_start_input: Input,
// cache the old value incase user presses Esc.
old_value: String,
}
Expand All @@ -38,14 +38,18 @@ impl ManageNodes {
pub fn new(allocated_space: usize) -> Result<Self> {
let new = Self {
active: false,
available_disk_space_bytes: Self::get_available_space_gb()?,
allocated_space_input: Input::default().with_value(allocated_space.to_string()),
available_disk_space_gb: Self::get_available_space_b()? / GB,
nodes_to_start_input: Input::default().with_value(allocated_space.to_string()),
old_value: Default::default(),
};
Ok(new)
}

fn get_available_space_gb() -> Result<usize> {
fn get_nodes_to_start(&self) -> usize {
self.nodes_to_start_input.value().parse().unwrap_or(0)
}

fn get_available_space_b() -> Result<usize> {
let disks = Disks::new_with_refreshed_list();

let available_space_b = disks
Expand Down Expand Up @@ -77,27 +81,25 @@ impl Component for ManageNodes {
// while in entry mode, key bindings are not captured, so gotta exit entry mode from here
let send_back = match key.code {
KeyCode::Enter => {
let allocated_space_str = self.allocated_space_input.value().to_string();
let allocated_space =
if let Ok(allocated_space) = allocated_space_str.trim().parse::<usize>() {
let allocated_space =
std::cmp::min(allocated_space, self.available_disk_space_bytes);
let max_nodes = allocated_space / GB_PER_NODE;
max_nodes * GB_PER_NODE
} else {
0
};
let nodes_to_start_str = self.nodes_to_start_input.value().to_string();
let nodes_to_start = {
let max_space_to_use = std::cmp::min(
self.get_nodes_to_start() * GB_PER_NODE,
self.available_disk_space_gb,
);
max_space_to_use / GB_PER_NODE
};
// set the new value
self.allocated_space_input = self
.allocated_space_input
self.nodes_to_start_input = self
.nodes_to_start_input
.clone()
.with_value(allocated_space.to_string());
.with_value(nodes_to_start.to_string());

debug!(
"Got Enter, value found to be {allocated_space} derived from input: {allocated_space_str:?} and switching scene",
"Got Enter, value found to be {nodes_to_start} derived from input: {nodes_to_start_str:?} and switching scene",
);
vec![
Action::StoreAllocatedDiskSpace(allocated_space),
Action::StoreNodesToStart(nodes_to_start),
Action::SwitchScene(Scene::Home),
]
}
Expand All @@ -107,47 +109,61 @@ impl Component for ManageNodes {
self.old_value
);
// reset to old value
self.allocated_space_input = self
.allocated_space_input
self.nodes_to_start_input = self
.nodes_to_start_input
.clone()
.with_value(self.old_value.clone());
vec![Action::SwitchScene(Scene::Home)]
}
KeyCode::Char(c) if c.is_numeric() => {
self.allocated_space_input.handle_event(&Event::Key(key));
// don't allow leading zeros
if c == '0' && self.nodes_to_start_input.value().is_empty() {
return Ok(vec![]);
}
// if it might exceed the available space, then enter the max
let number = c.to_string().parse::<usize>().unwrap_or(0);
let new_value = format!("{}{}", self.get_nodes_to_start(), number)
.parse::<usize>()
.unwrap_or(0);
if new_value * GB_PER_NODE > self.available_disk_space_gb {
let max_nodes = self.available_disk_space_gb / GB_PER_NODE;
self.nodes_to_start_input = self
.nodes_to_start_input
.clone()
.with_value(max_nodes.to_string());
return Ok(vec![]);
}
self.nodes_to_start_input.handle_event(&Event::Key(key));
vec![]
}
KeyCode::Backspace => {
self.allocated_space_input.handle_event(&Event::Key(key));
self.nodes_to_start_input.handle_event(&Event::Key(key));
vec![]
}
KeyCode::Up | KeyCode::Down => {
let allocated_space_str = self.allocated_space_input.value().to_string();
let allocated_space = if let Ok(allocated_space) =
allocated_space_str.trim().parse::<usize>()
{
let nodes_to_start = {
let nodes_to_start = self.get_nodes_to_start();

if key.code == KeyCode::Up {
if allocated_space + GB_PER_NODE <= self.available_disk_space_bytes / GB {
allocated_space + GB_PER_NODE
if (nodes_to_start + 1) * GB_PER_NODE <= self.available_disk_space_gb {
nodes_to_start + 1
} else {
allocated_space
nodes_to_start
}
} else {
// Key::Down
if allocated_space >= GB_PER_NODE {
allocated_space - GB_PER_NODE
if nodes_to_start == 0 {
0
} else {
allocated_space
nodes_to_start - 1
}
}
} else {
0
};
// set the new value
self.allocated_space_input = self
.allocated_space_input
self.nodes_to_start_input = self
.nodes_to_start_input
.clone()
.with_value(allocated_space.to_string());
.with_value(nodes_to_start.to_string());
vec![]
}
_ => {
Expand All @@ -162,7 +178,7 @@ impl Component for ManageNodes {
Action::SwitchScene(scene) => match scene {
Scene::ManageNodes => {
self.active = true;
self.old_value = self.allocated_space_input.value().to_string();
self.old_value = self.nodes_to_start_input.value().to_string();
// set to entry input mode as we want to handle everything within our handle_key_events
// so by default if this scene is active, we capture inputs.
Some(Action::SwitchInputMode(InputMode::Entry))
Expand Down Expand Up @@ -232,12 +248,12 @@ impl Component for ManageNodes {
)
.split(layer_one[1]);

let start = Paragraph::new("Start").style(Style::default().fg(GHOST_WHITE));
let start = Paragraph::new("Start ").style(Style::default().fg(GHOST_WHITE));
f.render_widget(start, layer_input_field[1]);

let width = layer_input_field[2].width.max(3) - 3;
let scroll = self.allocated_space_input.visual_scroll(width as usize);
let input = Paragraph::new(self.allocated_space_input.value())
let scroll = self.nodes_to_start_input.visual_scroll(width as usize);
let input = Paragraph::new(self.get_nodes_to_start().to_string())
.style(Style::new().fg(VIVID_SKY_BLUE))
.scroll((0, scroll as u16))
.alignment(Alignment::Center);
Expand All @@ -248,12 +264,12 @@ impl Component for ManageNodes {
f.render_widget(nodes_text, layer_input_field[3]);

// ==== info field ====
let available_space_gb = self.available_disk_space_bytes / GB;
let available_space_gb = self.available_disk_space_gb;
let info_style = Style::default().fg(VIVID_SKY_BLUE);
let info = Line::from(vec![
Span::styled("Using", info_style),
Span::styled(
format!(" {}GB ", self.allocated_space_input.value()),
format!(" {}GB ", self.get_nodes_to_start() * GB_PER_NODE),
info_style.bold(),
),
Span::styled(
Expand Down
2 changes: 1 addition & 1 deletion node-launchpad/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CONFIG: &str = include_str!("../.config/config.json5");
#[derive(Clone, Debug, Deserialize, Default, Serialize)]
pub struct AppData {
pub discord_username: String,
pub allocated_disk_space: usize,
pub nodes_to_start: usize,
}

impl AppData {
Expand Down

0 comments on commit 23c0181

Please sign in to comment.