mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Testing setup working, settings moved to a singleton and initialized on
main.
This commit is contained in:
+6
-2
@@ -9,7 +9,7 @@ use r2d2_sqlite::SqliteConnectionManager;
|
||||
use rusqlite_migration::Migrations;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::settings;
|
||||
use crate::settings::get_settings;
|
||||
|
||||
static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/database_migrations");
|
||||
static INITIALISED: Mutex<bool> = Mutex::const_new(false);
|
||||
@@ -20,7 +20,11 @@ lazy_static! {
|
||||
Migrations::from_directory(&MIGRATIONS_DIR).unwrap();
|
||||
|
||||
// TODO : Move pool size to configuration file
|
||||
static ref POOL: r2d2::Pool<SqliteConnectionManager> = r2d2::Pool::builder().max_size(10).build(r2d2_sqlite::SqliteConnectionManager::file(settings::CONFIG.database.path.as_str())).unwrap();
|
||||
static ref POOL: r2d2::Pool<SqliteConnectionManager> = r2d2::Pool::builder().
|
||||
max_size(10).
|
||||
build(
|
||||
r2d2_sqlite::SqliteConnectionManager::file(get_settings().database.path.as_str())
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_db_connection() -> PooledConnection<SqliteConnectionManager> {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use chrono::Local;
|
||||
use log::debug;
|
||||
|
||||
use crate::model::{self, notifications::Notification};
|
||||
|
||||
pub fn list() -> Vec<model::notifications::Notification> {
|
||||
debug!("Listing notifications");
|
||||
let mut result = Vec::new();
|
||||
result.push(Notification {
|
||||
id: 1,
|
||||
@@ -23,7 +25,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn list_default() {
|
||||
tests_common::setup_database().await;
|
||||
tests_common::setup().await;
|
||||
let notifications = list();
|
||||
assert_eq!(notifications.len(), 1);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod packet_send_receive;
|
||||
|
||||
use crate::model::devices::Device;
|
||||
use crate::settings::CONFIG;
|
||||
use crate::settings::get_settings;
|
||||
use duration_string::DurationString;
|
||||
use log::{debug, error, info, warn};
|
||||
use packet_send_receive::{listen_for_packets, send_packet};
|
||||
@@ -83,14 +83,17 @@ pub async fn find(interface: String) -> Result<Vec<Device>, String> {
|
||||
let send_interface = network_interface.clone();
|
||||
|
||||
// Get timeouts
|
||||
let sender_timeout: Duration = CONFIG.timings.arp_sender_timeout.into();
|
||||
let sender_timeout: Duration = get_settings().timings.arp_sender_timeout.into();
|
||||
info!(
|
||||
"Sender timeout set to {}",
|
||||
CONFIG.timings.arp_sender_timeout
|
||||
get_settings().timings.arp_sender_timeout
|
||||
);
|
||||
let scan_duration: Duration = CONFIG.timings.arp_scan_duration.into();
|
||||
let scan_duration: Duration = get_settings().timings.arp_scan_duration.into();
|
||||
let receiver_timeout: Duration = scan_duration * 2;
|
||||
info!("Scan duration set to {}", CONFIG.timings.arp_scan_duration);
|
||||
info!(
|
||||
"Scan duration set to {}",
|
||||
get_settings().timings.arp_scan_duration
|
||||
);
|
||||
info!(
|
||||
"Receiver timeout set to {}",
|
||||
String::from(DurationString::from(receiver_timeout))
|
||||
|
||||
@@ -3,7 +3,7 @@ mod pushover;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::model::devices::Device;
|
||||
use crate::settings::CONFIG;
|
||||
use crate::settings::get_settings;
|
||||
use chrono::Local;
|
||||
use duration_string::DurationString;
|
||||
use log::{debug, info, warn};
|
||||
@@ -12,7 +12,7 @@ use log::{debug, info, warn};
|
||||
fn send_message(body: String) -> Result<(), String> {
|
||||
debug!("About to send notification ({body}).");
|
||||
|
||||
match CONFIG.notifications.method.as_str() {
|
||||
match get_settings().notifications.method.as_str() {
|
||||
"pushover" => {
|
||||
pushover::send_message(body)?;
|
||||
}
|
||||
@@ -36,7 +36,9 @@ pub fn trigger_existing_device(existing_device: Device, new_device: Device) -> R
|
||||
.to_std()
|
||||
.unwrap_or(Duration::from_secs(0));
|
||||
|
||||
if elapsed_since_last_seen >= Duration::from(CONFIG.notifications.notify_when_not_seen_for) {
|
||||
if elapsed_since_last_seen
|
||||
>= Duration::from(get_settings().notifications.notify_when_not_seen_for)
|
||||
{
|
||||
send_message(format!(
|
||||
"Device MAC {} - IP {} - Vendor {} came back online after {}.",
|
||||
new_device.mac_address,
|
||||
|
||||
@@ -2,15 +2,15 @@ use log::{debug, error};
|
||||
use pushover::API;
|
||||
use pushover::requests::message::SendMessage;
|
||||
|
||||
use crate::settings::CONFIG;
|
||||
use crate::settings::get_settings;
|
||||
|
||||
pub fn send_message(body: String) -> Result<(), String> {
|
||||
debug!("About to send message via pushover ({body})");
|
||||
let api = API::new();
|
||||
|
||||
let msg = SendMessage::new(
|
||||
CONFIG.notifications.pushover.token.as_str(),
|
||||
CONFIG.notifications.pushover.user_key.as_str(),
|
||||
get_settings().notifications.pushover.token.as_str(),
|
||||
get_settings().notifications.pushover.user_key.as_str(),
|
||||
body,
|
||||
);
|
||||
|
||||
|
||||
+20
-2
@@ -1,4 +1,5 @@
|
||||
use crate::settings::CONFIG;
|
||||
use crate::settings::get_settings;
|
||||
use clap::Parser;
|
||||
use log::{LevelFilter, info};
|
||||
|
||||
mod db;
|
||||
@@ -13,10 +14,27 @@ mod web_server;
|
||||
#[cfg(test)]
|
||||
mod tests_common;
|
||||
|
||||
// Command line parameters
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Config file path
|
||||
#[arg(short, long)]
|
||||
config: Option<String>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), String> {
|
||||
// Parse command line parameters and init settings
|
||||
// this is not thread safe so it needs to run just once
|
||||
let args = Args::parse();
|
||||
let config_path = args
|
||||
.config
|
||||
.unwrap_or(settings::DEFAULT_CONFIG_FILE_PATH.to_string());
|
||||
settings::init(config_path);
|
||||
|
||||
// Initialize logging
|
||||
let log_level = match CONFIG.log.level.as_str() {
|
||||
let log_level = match get_settings().log.level.as_str() {
|
||||
"off" => LevelFilter::Off,
|
||||
"error" => LevelFilter::Error,
|
||||
"warn" => LevelFilter::Warn,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use crate::db;
|
||||
use crate::device_finders;
|
||||
use crate::events;
|
||||
use crate::settings::CONFIG;
|
||||
use crate::settings::get_settings;
|
||||
use log::{debug, info};
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
pub async fn scan() -> Result<(), String> {
|
||||
loop {
|
||||
// Find online devices via ARP
|
||||
let devices = device_finders::arp::find(CONFIG.networking.interface.to_string()).await?;
|
||||
let devices =
|
||||
device_finders::arp::find(get_settings().networking.interface.to_string()).await?;
|
||||
|
||||
info!("Done with ARP probes");
|
||||
info!("Found {} online devices", devices.iter().count());
|
||||
@@ -44,8 +45,8 @@ pub async fn scan() -> Result<(), String> {
|
||||
}
|
||||
info!(
|
||||
"Scan finished. Sleeping for {} seconds",
|
||||
CONFIG.timings.wait_between_scans
|
||||
get_settings().timings.wait_between_scans
|
||||
);
|
||||
sleep(Duration::from(CONFIG.timings.wait_between_scans)).await;
|
||||
sleep(Duration::from(get_settings().timings.wait_between_scans)).await;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-32
@@ -1,8 +1,6 @@
|
||||
use clap::Parser;
|
||||
use config::{Config, ConfigError, File};
|
||||
use duration_string::DurationString;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{debug, error, info};
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde::Deserialize;
|
||||
|
||||
// -----------------------------------------------------------
|
||||
@@ -54,29 +52,9 @@ pub struct Settings {
|
||||
// End configuration structure
|
||||
// -----------------------------------------------------------
|
||||
|
||||
// Command line parameters relevant to configuration
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Config file path
|
||||
#[arg(short, long)]
|
||||
config: Option<String>,
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG_FILE_PATH: &str = "./oott.toml";
|
||||
|
||||
impl Settings {
|
||||
pub fn new() -> Result<Self, ConfigError> {
|
||||
debug!("Starting configuration");
|
||||
|
||||
let args_result = Args::try_parse();
|
||||
|
||||
let config_path = match args_result {
|
||||
Ok(value) => value.config.unwrap_or(DEFAULT_CONFIG_FILE_PATH.to_string()),
|
||||
Err(_) => DEFAULT_CONFIG_FILE_PATH.to_string(),
|
||||
};
|
||||
|
||||
info!("Reading configuration from {}", config_path);
|
||||
pub fn new(config_path: String) -> Result<Self, ConfigError> {
|
||||
println!("Reading configuration from {}", config_path);
|
||||
|
||||
let local_settings = Config::builder()
|
||||
.add_source(File::with_name(config_path.as_str()))
|
||||
@@ -86,12 +64,24 @@ impl Settings {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CONFIG: Settings = match Settings::new() {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
error!("Error reading configuration file: {error}");
|
||||
panic!("Error reading configuration file: {error}");
|
||||
pub const DEFAULT_CONFIG_FILE_PATH: &str = "./oott.toml";
|
||||
static SETTINGS: OnceCell<Settings> = OnceCell::new();
|
||||
|
||||
pub fn get_settings() -> &'static Settings {
|
||||
match SETTINGS.get() {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
println!(
|
||||
"Configuration was not initialized, reading from default path ({})",
|
||||
DEFAULT_CONFIG_FILE_PATH
|
||||
);
|
||||
let settings = Settings::new(DEFAULT_CONFIG_FILE_PATH.to_string()).unwrap();
|
||||
let _ = SETTINGS.set(settings);
|
||||
SETTINGS.get().unwrap()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(config_path: String) {
|
||||
let _ = SETTINGS.set(Settings::new(config_path).unwrap());
|
||||
}
|
||||
|
||||
+44
-15
@@ -1,30 +1,59 @@
|
||||
use crate::db;
|
||||
use crate::settings::get_settings;
|
||||
use include_dir::{Dir, include_dir};
|
||||
use log::{debug, info};
|
||||
use rusqlite_migration::Migrations;
|
||||
use std::sync::LazyLock;
|
||||
use log::{LevelFilter, debug, info};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
static TEST_MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/tests_database_migrations");
|
||||
|
||||
// Define migrations. These are applied atomically.
|
||||
static TEST_MIGRATIONS: LazyLock<Migrations<'static>> =
|
||||
LazyLock::new(|| Migrations::from_directory(&TEST_MIGRATIONS_DIR).unwrap());
|
||||
static TEST_MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/tests/database_setup");
|
||||
|
||||
// Use a Mutex bool as semaphore to ensure single initialization
|
||||
static INITIALISED: Mutex<bool> = Mutex::const_new(false);
|
||||
|
||||
pub async fn setup_database() {
|
||||
debug!("About to setup database for testing.");
|
||||
pub async fn setup() {
|
||||
debug!("About to setup testing.");
|
||||
let mut initialised = INITIALISED.lock().await;
|
||||
if *initialised {
|
||||
debug!("Database was already initialised, nothing to do.");
|
||||
debug!("Testing was already initialised, nothing to do.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize logging
|
||||
let log_level = match get_settings().log.level.as_str() {
|
||||
"off" => LevelFilter::Off,
|
||||
"error" => LevelFilter::Error,
|
||||
"warn" => LevelFilter::Warn,
|
||||
"info" => LevelFilter::Info,
|
||||
"debug" => LevelFilter::Debug,
|
||||
"trace" => LevelFilter::Trace,
|
||||
_ => LevelFilter::Error,
|
||||
};
|
||||
|
||||
env_logger::Builder::new()
|
||||
.filter(None, log_level)
|
||||
.write_style(env_logger::WriteStyle::Always)
|
||||
.init();
|
||||
|
||||
// Initialize database
|
||||
db::init_db().await.unwrap();
|
||||
info!("Initializing database for testing.");
|
||||
let mut conn = db::get_db_connection();
|
||||
debug!("Running migrations for testing.");
|
||||
TEST_MIGRATIONS.to_latest(&mut conn).unwrap();
|
||||
debug!("Testing migrations run on database.");
|
||||
let conn = db::get_db_connection();
|
||||
debug!("Running database setup scripts for testing.");
|
||||
|
||||
for entry in TEST_MIGRATIONS_DIR.entries() {
|
||||
if entry.path().extension().map_or(false, |ext| ext == "sql") {
|
||||
debug!("About to run {}", entry.path().display());
|
||||
|
||||
if entry.path().extension().map_or(false, |ext| ext == "sql") {
|
||||
let sql = entry.as_file().unwrap().contents_utf8().unwrap();
|
||||
conn.execute(&sql, []).unwrap_or_else(|err| {
|
||||
panic!("Error executing script: {}", err);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Database setup for testing.");
|
||||
|
||||
// Done
|
||||
*initialised = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user