Hassliebe/src/main.rs

118 lines
3.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::Arc;
use anyhow::{anyhow, Result};
use crate::modules::{InitializationContext, ModuleContext, ModuleContextMqtt};
use crate::mqtt::OwnedTopicsService;
use crate::util::generate_alphanumeric_id;
mod config;
mod modules;
mod mqtt;
mod util;
struct Paths {
data_directory: Box<Path>,
config: Box<Path>,
}
async fn get_paths_and_create_directories() -> Result<Paths> {
let project_dirs = directories::ProjectDirs::from("", "", "Hassliebe");
let paths = Paths {
config: std::env::var_os("HASS_CONFIG")
.map(PathBuf::from)
// I dont like this clone
.or(project_dirs.clone().map(|d| d.config_dir().to_path_buf().join("config.toml")))
.ok_or_else(|| anyhow!("Please specify a config file via HASS_CONFIG"))?
.into_boxed_path(),
data_directory: std::env::var_os("HASS_DATA_DIR")
.map(PathBuf::from)
.or(project_dirs.map(|d| d.data_dir().to_path_buf()))
.ok_or_else(|| anyhow!("Please specify a data directory via HASS_DATA_DIR"))?
.into_boxed_path(),
};
if let Some(p) = paths.config.parent() {
tokio::fs::create_dir_all(p).await?;
}
tokio::fs::create_dir_all(&paths.data_directory).await?;
Ok(paths)
}
fn initialize_logger() {
let mut builder = env_logger::builder();
builder.parse_filters("warn,hassliebe=info");
builder.parse_default_env();
builder.init();
}
async fn load_machine_id(paths: &Paths) -> Result<String> {
let overwrite_path = paths.data_directory.join("machine_id");
let mut value = tokio::fs::read_to_string(&overwrite_path).await.unwrap_or("".to_owned()).trim().to_owned();
if value.is_empty() {
log::debug!("{} does not exist or is empty", overwrite_path.to_string_lossy());
match tokio::fs::read_to_string("/etc/machine-id").await {
Ok(id) => {
value = id.trim().to_owned();
log::debug!("Found machine ID in /etc/machine-id: {}", value);
}
Err(_) => {
log::debug!("Could not read /etc/machine-id");
value = generate_alphanumeric_id(32);
log::info!("Generated new machine ID: {}", value);
tokio::fs::write(overwrite_path, &value).await?;
}
}
} else {
log::debug!("Found machine ID in {}: {}", overwrite_path.to_string_lossy(), value);
}
Ok(value)
}
#[tokio::main]
async fn main() -> Result<()> {
initialize_logger();
let paths = get_paths_and_create_directories().await?;
let machine_id = load_machine_id(&paths).await?;
let Some(config) = config::load(&paths.config)? else {
exit(exitcode::CONFIG);
};
let availability_topic = config.friendly_id.to_owned() + "/availability";
let (mqtt_client, event_loop) = mqtt::create_client(&config, &machine_id, &availability_topic).await?;
let discovery_device_object = mqtt::create_discovery_device_object(&config, &machine_id);
let owned_topics_service = OwnedTopicsService::new(&paths.data_directory).await?;
let mut initialization_context = InitializationContext {
owned_mqtt_topics: HashSet::new(),
message_handler_by_mqtt_topic: HashMap::new(),
full: Arc::new(ModuleContext {
config,
machine_id,
mqtt: ModuleContextMqtt {
client: mqtt_client,
availability_topic,
discovery_device_object,
},
// dbus_session_connection: zbus::Connection::session().await.context("while connecting to the D-Bus session bus")?
}),
};
modules::init_all(&mut initialization_context).await?;
mqtt::start_communication(&initialization_context, event_loop, owned_topics_service).await
}