Skip to content

Commit 3ad9b6a

Browse files
committed
implement scan command with save
closes #1
1 parent 1ba5b4f commit 3ad9b6a

File tree

7 files changed

+145
-1
lines changed

7 files changed

+145
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
target
2+
.idea

Cargo.lock

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bacli/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ config = { version = "0.14.1", default-features = false, features = [
2020
] }
2121
directories = "5.0.1"
2222
env_logger = "0.11.5"
23+
futures = "0.3.31"
2324
humantime = "2.1.0"
25+
ipnetwork = "0.20.0"
2426
log = "0.4.22"
27+
reqwest = "0.12.9"
2528
serde = { version = "1.0.215", features = ["derive"] }
2629
serde_json = "1.0.133"
2730
serde_with = "3.11.0"

crates/bacli/src/commands/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ mod alias;
22
mod info;
33
mod list;
44
mod restart;
5+
mod scan;
56
mod update_settings;
67

78
pub use alias::*;
89
pub use info::*;
910
pub use list::*;
1011
pub use restart::*;
12+
pub use scan::*;
1113
pub use update_settings::*;

crates/bacli/src/commands/scan.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::net::IpAddr;
2+
use std::time::Duration;
3+
4+
use anyhow::Result;
5+
use bitaxe_api::prelude::*;
6+
use comfy_table::Table;
7+
use futures::future;
8+
use ipnetwork::IpNetwork;
9+
use log::debug;
10+
11+
use crate::config::Config;
12+
use crate::models::ScanArgs;
13+
14+
pub async fn scan(mut config: Config, args: ScanArgs) -> Result<()> {
15+
debug!("Scanning network for devices: {:?}", args);
16+
let pool = reqwest::Client::builder()
17+
.timeout(Duration::from_secs(1))
18+
.build()?;
19+
20+
let network = IpNetwork::with_netmask(args.base, args.mask)?;
21+
let devices = future::join_all(network.into_iter().map(|i| check_ip(pool.clone(), i)))
22+
.await
23+
.into_iter()
24+
.filter_map(|res| res.ok());
25+
26+
let mut table = Table::new();
27+
table.set_header(vec!["IP", "Alias", "Board Version", "OS Version"]);
28+
29+
for (ip, info) in devices {
30+
let alias = match config.clone().get_device(&ip.to_string()) {
31+
Some(device) => device.alias.clone().unwrap_or("None".to_string()),
32+
None => {
33+
if args.should_save {
34+
config.upsert_device(&ip, None).await?;
35+
}
36+
"None".to_string()
37+
}
38+
};
39+
40+
table.add_row(vec![
41+
ip.to_string(),
42+
alias,
43+
info.board_version,
44+
info.version,
45+
]);
46+
}
47+
48+
println!("{table}");
49+
50+
Ok(())
51+
}
52+
53+
async fn check_ip(pool: reqwest::Client, ip: IpAddr) -> Result<(IpAddr, SystemInfo)> {
54+
let client = BitaxeClient::new_with_client(pool, &ip);
55+
let info = client.system_info().await?;
56+
57+
Ok((ip, info))
58+
}

crates/bacli/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ async fn main() -> anyhow::Result<()> {
2323
Command::UpdateSettings(args) => update_settings(cfg, args).await?,
2424
Command::List => list(cfg).await?,
2525
Command::Alias(args) => alias(cfg, args).await?,
26+
Command::Scan(args) => scan(cfg, args).await?,
2627
}
2728

2829
Ok(())

crates/bacli/src/models.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::net::IpAddr;
2+
13
use bitaxe_api::models::Settings;
24
use clap::{Args, Parser, Subcommand};
35
use serde::{Deserialize, Serialize};
@@ -26,6 +28,8 @@ pub enum Command {
2628
List,
2729
/// Associate an alias with a base (IP)
2830
Alias(AliasArgs),
31+
/// Scan the local network for devices
32+
Scan(ScanArgs),
2933
}
3034

3135
#[derive(Debug, Clone, Args)]
@@ -55,10 +59,23 @@ pub struct UpdateSetttingsArgs {
5559
pub struct AliasArgs {
5660
/// The URL of the device on the local network. This will usually be an IP address.
5761
pub base: String,
58-
/// The alias to reference the IP
62+
/// The alias to reference the IP.
5963
pub alias: String,
6064
}
6165

66+
#[derive(Debug, Clone, Args)]
67+
pub struct ScanArgs {
68+
/// An IP address in the IP range of the network containing the devices.
69+
#[arg(long, default_value = "192.168.1.1")]
70+
pub base: IpAddr,
71+
/// A mask to apply to the base IP to get the range of available IPs.
72+
#[arg(long, default_value = "255.255.255.0")]
73+
pub mask: IpAddr,
74+
/// Save any new found devices to the config.
75+
#[arg(short, long = "save")]
76+
pub should_save: bool,
77+
}
78+
6279
#[serde_as]
6380
#[skip_serializing_none]
6481
#[derive(Debug, Clone, Serialize, Deserialize)]

0 commit comments

Comments
 (0)