Files
matrix-lolopener/src/mqtt.rs
T

120 lines
3.0 KiB
Rust

/*!
* matrix-lolopener v0.1.0
*
* Copyright (C) 2026 The 1312 Media Collective
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use rumqttc::{
MqttOptions,
AsyncClient,
EventLoop,
Event,
Incoming,
QoS,
};
use std::{
time::Duration,
fmt,
};
use serde::Deserialize;
use tracing::{ info, debug };
use crate::config::MQTTConfig;
#[derive(Deserialize, Debug)]
pub struct StatusMessage {
pub contact: bool,
}
pub struct MQTT {
config: MQTTConfig,
client: AsyncClient,
eventloop: EventLoop,
}
impl MQTT {
pub async fn new(config: MQTTConfig) -> Self {
let mut mqttoptions = MqttOptions::new(config.id.clone(), config.host.clone(), config.port);
mqttoptions.set_keep_alive(Duration::from_secs(5));
let (client, eventloop) = AsyncClient::new(mqttoptions, 1);
MQTT {
config,
client,
eventloop,
}
}
pub async fn subscribe<F: Fn(StatusMessage)>(&mut self, callback: F) -> Result<()> {
self.client.subscribe(self.config.topic.clone(), QoS::AtMostOnce).await?;
loop {
let notification = self.eventloop.poll().await?;
debug!("Notification = {:?}", notification);
if let Event::Incoming(Incoming::Publish(p)) = notification {
let msg: StatusMessage = serde_json::from_slice(p.payload.as_ref())?;
info!("Message: {:?}", msg);
callback(msg);
}
}
#[allow(unreachable_code)]
Ok(())
}
}
#[derive(Debug)]
#[allow(dead_code)] // we use Debug, so inner fields are never read
pub enum Error {
MQTTClient(rumqttc::ClientError),
MQTTConnection(rumqttc::ConnectionError),
InvalidFormat(serde_json::Error),
}
impl From<rumqttc::ClientError> for Error {
fn from(e: rumqttc::ClientError) -> Self {
Self::MQTTClient(e)
}
}
impl From<rumqttc::ConnectionError> for Error {
fn from(e: rumqttc::ConnectionError) -> Self {
Self::MQTTConnection(e)
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Self::InvalidFormat(e)
}
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
write!(fmt, "{self:?}")
}
}
pub type Result<T> = std::result::Result<T, Error>;