This commit is contained in:
2026-08-21 11:05:10 +03:00
parent 3c904db36f
commit 0642807b06
5 changed files with 117 additions and 14 deletions

10
Cargo.lock generated
View File

@@ -824,6 +824,15 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "parse_int"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c464266693329dd5a8715098c7f86e6c5fd5d985018b8318f53d9c6c2b21a31"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.17" version = "0.2.17"
@@ -1348,6 +1357,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"mikrotik-rs", "mikrotik-rs",
"parse_int",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",

View File

@@ -19,6 +19,7 @@ futures = "0.3.34"
lazy_static = "1.5.0" lazy_static = "1.5.0"
log = "0.4.33" log = "0.4.33"
mikrotik-rs = { version = "0.8.0", features = ["tokio-tls"] } mikrotik-rs = { version = "0.8.0", features = ["tokio-tls"] }
parse_int = "0.9.0"
regex = "1.12.4" regex = "1.12.4"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150" serde_json = "1.0.150"

View File

@@ -14,6 +14,6 @@ pub fn init_db(database_url: &str) -> PgConnection {
connection connection
.run_pending_migrations(MIGRATIONS) .run_pending_migrations(MIGRATIONS)
.unwrap_or_else(|e| panic!("Error running migrations: {e}")); .unwrap_or_else(|e| panic!("Error running migrations: {e}"));
log::info!("Connected to database");
connection connection
} }

View File

@@ -1,7 +1,7 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::prelude::*; use diesel::prelude::*;
#[derive(Queryable, Selectable)] #[derive(Debug, Queryable, Selectable)]
#[diesel(table_name = crate::db::schema::antennas)] #[diesel(table_name = crate::db::schema::antennas)]
#[diesel(check_for_backend(diesel::pg::Pg))] #[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Antenna { pub struct Antenna {
@@ -11,7 +11,7 @@ pub struct Antenna {
pub error: Option<String>, pub error: Option<String>,
} }
#[derive(Insertable)] #[derive(Debug, Insertable)]
#[diesel(table_name = crate::db::schema::antennas)] #[diesel(table_name = crate::db::schema::antennas)]
pub struct NewAntenna { pub struct NewAntenna {
pub name: String, pub name: String,
@@ -19,7 +19,7 @@ pub struct NewAntenna {
pub error: Option<String>, pub error: Option<String>,
} }
#[derive(Queryable, Selectable)] #[derive(Debug, Queryable, Selectable)]
#[diesel(table_name = crate::db::schema::client_readings)] #[diesel(table_name = crate::db::schema::client_readings)]
#[diesel(check_for_backend(diesel::pg::Pg))] #[diesel(check_for_backend(diesel::pg::Pg))]
pub struct ClientReading { pub struct ClientReading {
@@ -31,7 +31,7 @@ pub struct ClientReading {
pub read_at: NaiveDateTime, pub read_at: NaiveDateTime,
} }
#[derive(Insertable)] #[derive(Debug, Insertable)]
#[diesel(table_name = crate::db::schema::client_readings)] #[diesel(table_name = crate::db::schema::client_readings)]
pub struct NewClientReading { pub struct NewClientReading {
pub ip: String, pub ip: String,

View File

@@ -11,17 +11,21 @@ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
net::IpAddr, net::IpAddr,
str::FromStr, str::FromStr,
time::Duration,
}; };
use clap::builder; use clap::builder;
use diesel::{ExpressionMethods, RunQueryDsl};
use log::LevelFilter; use log::LevelFilter;
use serde_json::json; use serde_json::json;
use tabled::Table; use tabled::Table;
use tokio::time::{self, Duration};
use crate::config::{ use crate::{
config::{
Config, ConfigHost, Config, ConfigHost,
cli::{CliCommand, CliDeviceCommand, OutputFormat}, cli::{CliCommand, CliDeviceCommand, OutputFormat},
},
db::models::{NewAntenna, NewClientReading},
}; };
mod config; mod config;
@@ -51,6 +55,26 @@ async fn main() -> anyhow::Result<()> {
match &cfg.cli.command { match &cfg.cli.command {
CliCommand::BesWifi => { CliCommand::BesWifi => {
let mut conn = db::init_db(&cfg.db_url);
for host in &cfg.hosts {
use crate::db::schema::antennas;
diesel::insert_into(antennas::table)
.values(&NewAntenna {
name: host.name.clone(),
ip: host.ip.to_string(),
error: None,
})
.on_conflict(antennas::ip)
.do_update()
.set((
antennas::name.eq(host.name.clone()),
antennas::error.eq(&None as &Option<String>),
))
.execute(&mut conn)
.unwrap();
}
let v6_hosts = cfg let v6_hosts = cfg
.hosts .hosts
.iter() .iter()
@@ -68,11 +92,79 @@ async fn main() -> anyhow::Result<()> {
let v6_cmd = "/interface/wireless/registration-table/print"; let v6_cmd = "/interface/wireless/registration-table/print";
let v7_cmd = "/interface/wifi/registration-table/print"; let v7_cmd = "/interface/wifi/registration-table/print";
let mut interval = time::interval(Duration::from_secs(5));
loop {
interval.tick().await;
let (v6_res, v7_res) = futures::join!( let (v6_res, v7_res) = futures::join!(
mt_commander::MtCommander::run_command_on_hosts(&v6_hosts, v6_cmd), mt_commander::MtCommander::run_command_on_hosts(&v6_hosts, v6_cmd),
mt_commander::MtCommander::run_command_on_hosts(&v7_hosts, v7_cmd), mt_commander::MtCommander::run_command_on_hosts(&v7_hosts, v7_cmd),
); );
let (v6_res, v7_res) = (v6_res?, v7_res?); let mut records = Vec::new();
for (antenna, res) in v6_res?.iter().chain(v7_res?.iter()) {
match res {
Ok(vals) if antenna.tags.contains(&"v7".to_string()) => {
for val in vals {
let client_ip = String::new();
let Some(client_mac) = val.get("mac-address").unwrap() else {
todo!("Do err")
};
let Some(client_db) = val.get("signal").unwrap() else {
todo!("Do err")
};
let client_db =
parse_int::parse::<i32>(client_db).expect("Unparseble number");
records.push(NewClientReading {
ip: client_ip.clone(),
mac: client_mac.clone(),
antenna_ip: antenna.ip.to_string(),
db_reading: client_db,
});
}
}
Ok(vals) if antenna.tags.contains(&"v6".to_string()) => {
for val in vals {
let client_ip;
if let Some(ip) = val.get("last-ip") {
client_ip = ip.clone().unwrap();
} else {
client_ip = String::new();
}
let Some(client_mac) = val.get("mac-address").unwrap() else {
todo!("Do err")
};
let Some(mut client_db) =
val.get("signal-strength").unwrap().clone()
else {
todo!("Do err")
};
if client_db.contains("@") {
client_db = client_db.split('@').nth(0).unwrap().to_string();
}
dbg!(&client_db);
let client_db =
parse_int::parse::<i32>(&client_db).expect("Unparseble number");
records.push(NewClientReading {
ip: client_ip.clone(),
mac: client_mac.clone(),
antenna_ip: antenna.ip.to_string(),
db_reading: client_db,
});
}
}
Ok(_) => unreachable!(),
Err(_) => {}
}
}
log::info!("inserting: {records:?}");
diesel::insert_into(crate::db::schema::client_readings::table)
.values(&records)
.execute(&mut conn)
.unwrap();
}
} }
CliCommand::Run { CliCommand::Run {
all, all,