mirror of
https://github.com/robcholz/vibebox.git
synced 2026-07-08 13:07:47 +02:00
feat: added explain command to display network
This commit is contained in:
+25
-4
@@ -168,12 +168,13 @@ fn handle_command(command: Command, cwd: &PathBuf, config_override: Option<&Path
|
|||||||
}
|
}
|
||||||
Command::Explain => {
|
Command::Explain => {
|
||||||
let config = config::load_config_with_path(cwd, config_override);
|
let config = config::load_config_with_path(cwd, config_override);
|
||||||
let rows = build_mount_rows(cwd, &config)?;
|
let mounts = build_mount_rows(cwd, &config)?;
|
||||||
if rows.is_empty() {
|
let networks = build_network_rows(cwd)?;
|
||||||
println!("No mounts configured.");
|
if mounts.is_empty() && networks.is_empty() {
|
||||||
|
println!("No mounts or network info available.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
tui::render_mounts_table(&rows)?;
|
tui::render_explain_tables(&mounts, &networks)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,6 +253,26 @@ fn build_mount_rows(cwd: &Path, config: &config::Config) -> Result<Vec<tui::Moun
|
|||||||
Ok(rows)
|
Ok(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_network_rows(cwd: &Path) -> Result<Vec<tui::NetworkListRow>> {
|
||||||
|
let instance_dir = cwd.join(session_manager::INSTANCE_DIR_NAME);
|
||||||
|
let mut vm_ip = "-".to_string();
|
||||||
|
if let Ok(Some(ip)) = instance::read_instance_vm_ip(&instance_dir) {
|
||||||
|
vm_ip = ip;
|
||||||
|
}
|
||||||
|
let host_to_vm = if vm_ip == "-" {
|
||||||
|
"ssh: <pending>:22".to_string()
|
||||||
|
} else {
|
||||||
|
format!("ssh: {vm_ip}:22")
|
||||||
|
};
|
||||||
|
let row = tui::NetworkListRow {
|
||||||
|
network_type: "NAT".to_string(),
|
||||||
|
vm_ip: vm_ip.clone(),
|
||||||
|
host_to_vm,
|
||||||
|
vm_to_host: "none".to_string(),
|
||||||
|
};
|
||||||
|
Ok(vec![row])
|
||||||
|
}
|
||||||
|
|
||||||
fn default_mounts(cwd: &Path) -> Result<Vec<tui::MountListRow>> {
|
fn default_mounts(cwd: &Path) -> Result<Vec<tui::MountListRow>> {
|
||||||
let project_name = cwd
|
let project_name = cwd
|
||||||
.file_name()
|
.file_name()
|
||||||
|
|||||||
@@ -162,6 +162,25 @@ pub(crate) fn load_or_create_instance_config(
|
|||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_instance_config(
|
||||||
|
instance_dir: &Path,
|
||||||
|
) -> Result<Option<InstanceConfig>, Box<dyn std::error::Error>> {
|
||||||
|
let config_path = instance_dir.join(INSTANCE_FILENAME);
|
||||||
|
if !config_path.exists() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let raw = fs::read_to_string(&config_path)?;
|
||||||
|
let config = toml::from_str::<InstanceConfig>(&raw)?;
|
||||||
|
Ok(Some(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_instance_vm_ip(
|
||||||
|
instance_dir: &Path,
|
||||||
|
) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||||
|
let config = read_instance_config(instance_dir)?;
|
||||||
|
Ok(config.and_then(|cfg| cfg.vm_ipv4))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn touch_last_active(instance_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn touch_last_active(instance_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut config = load_or_create_instance_config(instance_dir)?;
|
let mut config = load_or_create_instance_config(instance_dir)?;
|
||||||
let now = OffsetDateTime::now_utc().format(&Rfc3339)?;
|
let now = OffsetDateTime::now_utc().format(&Rfc3339)?;
|
||||||
|
|||||||
+101
-6
@@ -115,6 +115,14 @@ pub struct MountListRow {
|
|||||||
pub default_mount: String,
|
pub default_mount: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct NetworkListRow {
|
||||||
|
pub network_type: String,
|
||||||
|
pub vm_ip: String,
|
||||||
|
pub host_to_vm: String,
|
||||||
|
pub vm_to_host: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
struct PageLayout {
|
struct PageLayout {
|
||||||
header: Rect,
|
header: Rect,
|
||||||
@@ -253,6 +261,65 @@ pub fn render_mounts_table(rows: &[MountListRow]) -> Result<()> {
|
|||||||
let mut buffer = Buffer::empty(Rect::new(0, 0, width, height));
|
let mut buffer = Buffer::empty(Rect::new(0, 0, width, height));
|
||||||
let area = Rect::new(0, 0, width, height);
|
let area = Rect::new(0, 0, width, height);
|
||||||
|
|
||||||
|
render_mounts_table_into(rows, area, &mut buffer);
|
||||||
|
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
execute!(stdout, Clear(ClearType::All), MoveTo(0, 0), Show)?;
|
||||||
|
write_buffer_with_style(&buffer, &mut stdout)?;
|
||||||
|
stdout.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_explain_tables(mounts: &[MountListRow], networks: &[NetworkListRow]) -> Result<()> {
|
||||||
|
let (width, _) = crossterm::terminal::size()?;
|
||||||
|
if width == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mounts_height = if mounts.is_empty() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(mounts.len() as u16).saturating_add(3)
|
||||||
|
};
|
||||||
|
let networks_height = if networks.is_empty() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(networks.len() as u16).saturating_add(3)
|
||||||
|
};
|
||||||
|
let gap = if mounts_height > 0 && networks_height > 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let total_height = mounts_height
|
||||||
|
.saturating_add(gap)
|
||||||
|
.saturating_add(networks_height);
|
||||||
|
if total_height == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = Buffer::empty(Rect::new(0, 0, width, total_height));
|
||||||
|
let mut y = 0u16;
|
||||||
|
|
||||||
|
if mounts_height > 0 {
|
||||||
|
let area = Rect::new(0, y, width, mounts_height);
|
||||||
|
render_mounts_table_into(mounts, area, &mut buffer);
|
||||||
|
y = y.saturating_add(mounts_height).saturating_add(gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if networks_height > 0 {
|
||||||
|
let area = Rect::new(0, y, width, networks_height);
|
||||||
|
render_networks_table_into(networks, area, &mut buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
execute!(stdout, Clear(ClearType::All), MoveTo(0, 0), Show)?;
|
||||||
|
write_buffer_with_style(&buffer, &mut stdout)?;
|
||||||
|
stdout.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_mounts_table_into(rows: &[MountListRow], area: Rect, buffer: &mut Buffer) {
|
||||||
let header = Row::new(vec![
|
let header = Row::new(vec![
|
||||||
Cell::from("Host"),
|
Cell::from("Host"),
|
||||||
Cell::from("Guest"),
|
Cell::from("Guest"),
|
||||||
@@ -286,13 +353,41 @@ pub fn render_mounts_table(rows: &[MountListRow]) -> Result<()> {
|
|||||||
.block(Block::default().title("Mounts").borders(Borders::ALL))
|
.block(Block::default().title("Mounts").borders(Borders::ALL))
|
||||||
.column_spacing(1);
|
.column_spacing(1);
|
||||||
|
|
||||||
table.render(area, &mut buffer);
|
table.render(area, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
let mut stdout = io::stdout();
|
fn render_networks_table_into(rows: &[NetworkListRow], area: Rect, buffer: &mut Buffer) {
|
||||||
execute!(stdout, Clear(ClearType::All), MoveTo(0, 0), Show)?;
|
let header = Row::new(vec![
|
||||||
write_buffer_with_style(&buffer, &mut stdout)?;
|
Cell::from("Type"),
|
||||||
stdout.flush()?;
|
Cell::from("VM IP"),
|
||||||
Ok(())
|
Cell::from("Host \u{2192} VM"),
|
||||||
|
Cell::from("VM \u{2192} Host"),
|
||||||
|
])
|
||||||
|
.style(Style::default().fg(Color::Cyan));
|
||||||
|
|
||||||
|
let table_rows = rows.iter().map(|row| {
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(row.network_type.clone()),
|
||||||
|
Cell::from(row.vm_ip.clone()),
|
||||||
|
Cell::from(row.host_to_vm.clone()),
|
||||||
|
Cell::from(row.vm_to_host.clone()),
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
|
let table = Table::new(
|
||||||
|
table_rows,
|
||||||
|
[
|
||||||
|
Constraint::Length(8),
|
||||||
|
Constraint::Length(16),
|
||||||
|
Constraint::Min(24),
|
||||||
|
Constraint::Min(20),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.header(header)
|
||||||
|
.block(Block::default().title("Network").borders(Borders::ALL))
|
||||||
|
.column_spacing(1);
|
||||||
|
|
||||||
|
table.render(area, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn passthrough_vm_io(
|
pub fn passthrough_vm_io(
|
||||||
|
|||||||
Reference in New Issue
Block a user