From 0642807b06a3f40baa577673b111fd153e45e82d Mon Sep 17 00:00:00 2001 From: Gvidas Juknevicius Date: Fri, 21 Aug 2026 11:05:10 +0300 Subject: [PATCH] Works --- Cargo.lock | 10 +++++ Cargo.toml | 1 + src/db/mod.rs | 2 +- src/db/models.rs | 8 ++-- src/main.rs | 110 +++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 117 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e785705..dab7085 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -824,6 +824,15 @@ dependencies = [ "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]] name = "pin-project-lite" version = "0.2.17" @@ -1348,6 +1357,7 @@ dependencies = [ "lazy_static", "log", "mikrotik-rs", + "parse_int", "regex", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 0ef1c92..2b9e1f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ futures = "0.3.34" lazy_static = "1.5.0" log = "0.4.33" mikrotik-rs = { version = "0.8.0", features = ["tokio-tls"] } +parse_int = "0.9.0" regex = "1.12.4" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.150" diff --git a/src/db/mod.rs b/src/db/mod.rs index ac85dcf..38f70f3 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -14,6 +14,6 @@ pub fn init_db(database_url: &str) -> PgConnection { connection .run_pending_migrations(MIGRATIONS) .unwrap_or_else(|e| panic!("Error running migrations: {e}")); - + log::info!("Connected to database"); connection } diff --git a/src/db/models.rs b/src/db/models.rs index db6bb1f..0a75463 100644 --- a/src/db/models.rs +++ b/src/db/models.rs @@ -1,7 +1,7 @@ use chrono::NaiveDateTime; use diesel::prelude::*; -#[derive(Queryable, Selectable)] +#[derive(Debug, Queryable, Selectable)] #[diesel(table_name = crate::db::schema::antennas)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct Antenna { @@ -11,7 +11,7 @@ pub struct Antenna { pub error: Option, } -#[derive(Insertable)] +#[derive(Debug, Insertable)] #[diesel(table_name = crate::db::schema::antennas)] pub struct NewAntenna { pub name: String, @@ -19,7 +19,7 @@ pub struct NewAntenna { pub error: Option, } -#[derive(Queryable, Selectable)] +#[derive(Debug, Queryable, Selectable)] #[diesel(table_name = crate::db::schema::client_readings)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct ClientReading { @@ -31,7 +31,7 @@ pub struct ClientReading { pub read_at: NaiveDateTime, } -#[derive(Insertable)] +#[derive(Debug, Insertable)] #[diesel(table_name = crate::db::schema::client_readings)] pub struct NewClientReading { pub ip: String, diff --git a/src/main.rs b/src/main.rs index 5b7c6f8..702a27f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,17 +11,21 @@ use std::{ collections::{BTreeMap, HashMap}, net::IpAddr, str::FromStr, - time::Duration, }; use clap::builder; +use diesel::{ExpressionMethods, RunQueryDsl}; use log::LevelFilter; use serde_json::json; use tabled::Table; +use tokio::time::{self, Duration}; -use crate::config::{ - Config, ConfigHost, - cli::{CliCommand, CliDeviceCommand, OutputFormat}, +use crate::{ + config::{ + Config, ConfigHost, + cli::{CliCommand, CliDeviceCommand, OutputFormat}, + }, + db::models::{NewAntenna, NewClientReading}, }; mod config; @@ -51,6 +55,26 @@ async fn main() -> anyhow::Result<()> { match &cfg.cli.command { 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), + )) + .execute(&mut conn) + .unwrap(); + } + let v6_hosts = cfg .hosts .iter() @@ -68,11 +92,79 @@ async fn main() -> anyhow::Result<()> { let v6_cmd = "/interface/wireless/registration-table/print"; let v7_cmd = "/interface/wifi/registration-table/print"; - 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(&v7_hosts, v7_cmd), - ); - let (v6_res, v7_res) = (v6_res?, v7_res?); + let mut interval = time::interval(Duration::from_secs(5)); + + loop { + interval.tick().await; + + 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(&v7_hosts, v7_cmd), + ); + 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::(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::(&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 { all,