Owo
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
* permission.
|
||||
*/
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use clap::ArgGroup;
|
||||
use serde::de;
|
||||
|
||||
@@ -25,9 +27,13 @@ pub struct CliArgs {
|
||||
pub config_file: camino::Utf8PathBuf,
|
||||
|
||||
/// Output more information in logs
|
||||
#[arg(long = "verbose", short = 'v')]
|
||||
#[arg(long = "verbose", short = 'v', conflicts_with="quiet")]
|
||||
pub verbose: bool,
|
||||
|
||||
/// Output more information in logs
|
||||
#[arg(long = "quiet", short = 'q', conflicts_with="verbose")]
|
||||
pub quiet: bool,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub command: CliCommand,
|
||||
}
|
||||
@@ -96,7 +102,28 @@ pub enum CliCommand {
|
||||
pub enum CliDeviceCommand {
|
||||
/// List devices
|
||||
List,
|
||||
|
||||
Add {
|
||||
/// Device name
|
||||
#[arg(short='n', long)]
|
||||
name: String,
|
||||
/// Device address, ipv4 or ipv6
|
||||
#[arg(short='H', long)]
|
||||
host: IpAddr,
|
||||
/// Device Port (skip for default)
|
||||
#[arg(short='p', long)]
|
||||
port: Option<u16>,
|
||||
/// Username (skip for default)
|
||||
#[arg(short='U', long)]
|
||||
username: Option<String>,
|
||||
/// Password (skip for default)
|
||||
#[arg(short='P', long)]
|
||||
password: Option<String>
|
||||
},
|
||||
Remove {
|
||||
/// Name of the device
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
},
|
||||
#[default]
|
||||
#[clap(skip)]
|
||||
None,
|
||||
|
||||
@@ -71,6 +71,11 @@ impl Config {
|
||||
slf.cli = cli;
|
||||
Ok(slf)
|
||||
}
|
||||
pub fn save(&self) -> anyhow::Result<()> {
|
||||
let data = toml::to_string_pretty(self)?;
|
||||
std::fs::write(&self.cli.config_file, data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigHost {
|
||||
|
||||
23
src/main.rs
23
src/main.rs
@@ -29,19 +29,21 @@ mod mt_commander;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let cfg = config::Config::parse()?;
|
||||
let mut cfg = config::Config::parse()?;
|
||||
//dbg!(&cfg);
|
||||
|
||||
env_logger::builder()
|
||||
.parse_default_env()
|
||||
.filter_module(
|
||||
"wara",
|
||||
if cfg.cli.verbose {
|
||||
LevelFilter::Debug
|
||||
} else if cfg.cli.quiet {
|
||||
LevelFilter::Error
|
||||
} else {
|
||||
LevelFilter::Info
|
||||
},
|
||||
)
|
||||
.parse_default_env()
|
||||
.init();
|
||||
|
||||
mt_commander::MtCommander::init(cfg.clone())?;
|
||||
@@ -71,12 +73,27 @@ async fn main() -> anyhow::Result<()> {
|
||||
tokio::time::sleep(Duration::from_secs_f32(*interval)).await;
|
||||
}
|
||||
}
|
||||
CliCommand::Device { command } => match command {
|
||||
CliCommand::Device { command } => match command.clone() {
|
||||
CliDeviceCommand::List => {
|
||||
let devices = cfg.hosts.iter().map(|h| h.display_tabled(&cfg));
|
||||
|
||||
let table = tabled::Table::new(devices);
|
||||
println!("{}", table);
|
||||
},
|
||||
CliDeviceCommand::Add { name, host, port, username, password } => {
|
||||
cfg.hosts.push(ConfigHost { name, ip: host, port, username, password });
|
||||
cfg.save()?;
|
||||
}
|
||||
CliDeviceCommand::Remove { name } => {
|
||||
for (i, host) in cfg.hosts.iter().enumerate() {
|
||||
if host.name == name {
|
||||
cfg.hosts.remove(i);
|
||||
cfg.save()?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
log::error!("Unable to find host with name '{name}' to remove");
|
||||
return Ok(());
|
||||
}
|
||||
CliDeviceCommand::None => unreachable!(),
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::bail;
|
||||
use mikrotik_rs::{Command, CommandBuilder, Event, MikrotikDevice};
|
||||
use regex::Regex;
|
||||
|
||||
@@ -112,23 +113,36 @@ impl MtCommanderInternal {
|
||||
host: &ConfigHost,
|
||||
cmd: &str,
|
||||
) -> anyhow::Result<Vec<HashMap<String, Option<String>>>> {
|
||||
let dev = MikrotikDevice::connect(
|
||||
format!("{}:{}", &host.ip, host.port(&self.cfg())),
|
||||
let addr = format!("{}:{}", &host.ip, host.port(&self.cfg()));
|
||||
let dev_res = MikrotikDevice::connect(
|
||||
&addr,
|
||||
&host.username(self.cfg()),
|
||||
Some(&host.password(self.cfg())),
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let dev = match dev_res {
|
||||
Ok(dev) => {
|
||||
log::info!("({addr}) Connected successfully!");
|
||||
dev
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to connect to {addr}: {e}");
|
||||
bail!(e);
|
||||
}
|
||||
};
|
||||
|
||||
let mut rx = dev
|
||||
.send_command(CommandBuilder::new().command(cmd).build())
|
||||
.await?;
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
let mut size = 0;
|
||||
while let Some(event) = rx.recv().await {
|
||||
match event {
|
||||
Event::Reply { response, .. } => {
|
||||
Event::Reply { response, tag: _ } => {
|
||||
log::debug!("({}) {:?}", &host.ip, response.attributes);
|
||||
size += response.attributes.values().flatten().map(|v| v.len()).sum::<usize>();
|
||||
res.push(response.attributes);
|
||||
}
|
||||
Event::Done { .. } => {
|
||||
@@ -140,6 +154,7 @@ impl MtCommanderInternal {
|
||||
other => println!("{other:?}"),
|
||||
}
|
||||
}
|
||||
log::info!("({addr}) Command finished, read {size} bytes");
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user