9e77d961f5
- Capture SIGTERM et SIGINT via libc::signal → AtomicBool RUNNING - La boucle principale s'arrête proprement à la prochaine itération - Envoi d'un paquet status:offline via UDP avant de quitter - MQTT : publish status offline + disconnect() pour déconnexion gracieuse (le last_will reste actif pour les déconnexions brutales) - payload.rs: #[serde(default)] sur version pour compatibilité descendante Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
2.7 KiB
Rust
86 lines
2.7 KiB
Rust
use rumqttc::{Client, LastWill, MqttOptions, QoS, Event, Packet, Transport};
|
|
use std::sync::mpsc::Sender;
|
|
use std::time::Duration;
|
|
use crate::config::MqttConfig;
|
|
|
|
pub enum MqttIncoming {
|
|
ConfigUpdate(Vec<u8>),
|
|
}
|
|
|
|
pub fn start(
|
|
hostname: &str,
|
|
cfg: &MqttConfig,
|
|
incoming_tx: Sender<MqttIncoming>,
|
|
) -> Client {
|
|
let status_topic = format!("{}/{}/status", cfg.topic_base, hostname);
|
|
let config_topic = format!("{}/{}/config", cfg.topic_base, hostname);
|
|
|
|
let mut opts = MqttOptions::new(
|
|
format!("nanometrics-{}", hostname),
|
|
&cfg.host,
|
|
cfg.port,
|
|
);
|
|
opts.set_keep_alive(Duration::from_secs(30));
|
|
// Forcer TCP non-TLS (use-native-tls est activé en feature mais le broker est sans TLS)
|
|
opts.set_transport(Transport::Tcp);
|
|
|
|
if cfg.last_will {
|
|
opts.set_last_will(LastWill::new(
|
|
&status_topic,
|
|
"offline",
|
|
QoS::AtLeastOnce,
|
|
true,
|
|
));
|
|
}
|
|
|
|
let (client, mut connection) = Client::new(opts, 16);
|
|
|
|
let client_clone = client.clone();
|
|
let config_topic_clone = config_topic.clone();
|
|
let status_topic_clone = status_topic.clone();
|
|
let birth = cfg.birth_message;
|
|
|
|
std::thread::spawn(move || {
|
|
for event in connection.iter() {
|
|
match event {
|
|
Ok(Event::Incoming(Packet::ConnAck(_))) => {
|
|
if birth {
|
|
let _ = client_clone.publish(
|
|
&status_topic_clone,
|
|
QoS::AtLeastOnce,
|
|
true,
|
|
"online",
|
|
);
|
|
}
|
|
let _ = client_clone.subscribe(
|
|
&config_topic_clone,
|
|
QoS::AtLeastOnce,
|
|
);
|
|
}
|
|
Ok(Event::Incoming(Packet::Publish(p))) if p.topic == config_topic_clone => {
|
|
let _ = incoming_tx.send(MqttIncoming::ConfigUpdate(
|
|
p.payload.to_vec(),
|
|
));
|
|
}
|
|
Err(e) => {
|
|
eprintln!("[mqtt] erreur: {}", e);
|
|
std::thread::sleep(Duration::from_secs(5));
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
});
|
|
|
|
client
|
|
}
|
|
|
|
pub fn publish_metrics(client: &Client, topic_base: &str, hostname: &str, json: &str) {
|
|
let topic = format!("{}/{}/metrics", topic_base, hostname);
|
|
let _ = client.publish(topic, QoS::AtMostOnce, false, json);
|
|
}
|
|
|
|
pub fn publish_status(client: &Client, topic_base: &str, hostname: &str, status: &str) {
|
|
let topic = format!("{}/{}/status", topic_base, hostname);
|
|
let _ = client.publish(topic, QoS::AtLeastOnce, true, status);
|
|
}
|