Chore: use diffrent topics for time and confirmation
This commit is contained in:
parent
5b2aefe659
commit
1a1320c09c
|
@ -1,10 +1,11 @@
|
||||||
use crypto_helper::crypto::Crypto;
|
use crypto_helper::crypto::Crypto;
|
||||||
|
use mqtt::{Event, ConnectionError};
|
||||||
use std::{time::Duration, cell::RefCell};
|
use std::{time::Duration, cell::RefCell};
|
||||||
extern crate rumqttc as mqtt;
|
extern crate rumqttc as mqtt;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub type TimeCallback = fn(u32) -> Result<(),()>;
|
pub type TimeCallback<T> = fn(u32, &T) -> Result<(),()>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq)]
|
#[derive(Serialize, Deserialize, PartialEq)]
|
||||||
enum MqttMessageKind {
|
enum MqttMessageKind {
|
||||||
|
@ -19,20 +20,25 @@ struct MqttMessage {
|
||||||
time: u32,
|
time: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Comm {
|
struct Topics {
|
||||||
|
time: String,
|
||||||
|
confirmation: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Comm<T> {
|
||||||
client: RefCell<mqtt::Client>,
|
client: RefCell<mqtt::Client>,
|
||||||
connection: RefCell<mqtt::Connection>,
|
connection: RefCell<mqtt::Connection>,
|
||||||
handler: TimeCallback,
|
handler: TimeCallback<T>,
|
||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
topic: String,
|
topics: Topics,
|
||||||
last_uuids: RefCell<Vec<uuid::Uuid>>
|
last_uuids: RefCell<Vec<uuid::Uuid>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Comm {
|
impl<T> Comm<T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
broker_domain: &str,
|
broker_domain: &str,
|
||||||
password: &str,
|
password: &str,
|
||||||
handler: TimeCallback,
|
handler: TimeCallback<T>,
|
||||||
) -> Result<Self, mqtt::ClientError> {
|
) -> Result<Self, mqtt::ClientError> {
|
||||||
let mut create_opts =
|
let mut create_opts =
|
||||||
mqtt::MqttOptions::new(uuid::Uuid::new_v4().to_string(), broker_domain, 8883);
|
mqtt::MqttOptions::new(uuid::Uuid::new_v4().to_string(), broker_domain, 8883);
|
||||||
|
@ -45,48 +51,66 @@ impl Comm {
|
||||||
|
|
||||||
let crypto = Crypto::new(password, broker_domain);
|
let crypto = Crypto::new(password, broker_domain);
|
||||||
|
|
||||||
let topic = format!("org.speedclimbing.ok-ready-go.{password}");
|
let time_topic = format!("org.speedclimbing.ok-ready-go.{password}.time");
|
||||||
let topic = Crypto::sha256(&crypto.encrypt(&topic));
|
let time_topic = Crypto::sha256(&crypto.encrypt(&time_topic));
|
||||||
|
|
||||||
cli.subscribe(&topic, mqtt::QoS::AtMostOnce)?;
|
let confirmation_topic = format!("org.speedclimbing.ok-ready-go.{password}.confirmation");
|
||||||
|
let confirmation_topic = Crypto::sha256(&crypto.encrypt(&confirmation_topic));
|
||||||
|
|
||||||
|
cli.subscribe(&time_topic, mqtt::QoS::AtMostOnce)?;
|
||||||
|
|
||||||
Ok(Comm {
|
Ok(Comm {
|
||||||
client: RefCell::new(cli),
|
client: RefCell::new(cli),
|
||||||
connection: RefCell::new(conn),
|
connection: RefCell::new(conn),
|
||||||
handler,
|
handler,
|
||||||
crypto,
|
crypto,
|
||||||
topic,
|
topics: Topics {
|
||||||
|
time: time_topic,
|
||||||
|
confirmation: confirmation_topic
|
||||||
|
},
|
||||||
last_uuids: RefCell::new(Vec::new())
|
last_uuids: RefCell::new(Vec::new())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen(&self) {
|
pub fn handle_next_event(&self, handler_arg: &T) {
|
||||||
for (_, notification) in self.connection.borrow_mut().iter().enumerate() {
|
let notification = self.connection.borrow_mut().iter().next();
|
||||||
if let Err(e) = notification {
|
if notification.is_none() {
|
||||||
println!("Error: {:?}", e);
|
return;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let notification = notification.unwrap();
|
let notification = notification.unwrap();
|
||||||
if let mqtt::Event::Outgoing(_) = notification {
|
self._handle_notification(notification, handler_arg);
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let mqtt::Event::Incoming(notification) = notification {
|
pub fn disconnect(&self) {
|
||||||
self._handle_incoming_packet(notification);
|
self.client.borrow_mut().disconnect().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _handle_notification(&self, notification: Result<Event, ConnectionError>, handler_arg: &T) {
|
||||||
|
if let Err(e) = notification {
|
||||||
|
println!("Error: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let notification = notification.unwrap();
|
||||||
|
if let mqtt::Event::Outgoing(_) = notification {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let mqtt::Event::Incoming(notification) = notification {
|
||||||
|
self._handle_incoming_packet(notification, handler_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _handle_incoming_packet(&self, packet: mqtt::Packet) {
|
fn _handle_incoming_packet(&self, packet: mqtt::Packet, handler_arg: &T) {
|
||||||
match packet {
|
match packet {
|
||||||
mqtt::Packet::Publish(publish) => self._handle_publish_packet(publish),
|
mqtt::Packet::Publish(publish) => self._handle_publish_packet(publish, handler_arg),
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _handle_publish_packet(&self, packet: mqtt::Publish) {
|
fn _handle_publish_packet(&self, packet: mqtt::Publish, handler_arg: &T) {
|
||||||
if packet.topic != self.topic {
|
if packet.topic != self.topics.time {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +129,7 @@ impl Comm {
|
||||||
|
|
||||||
self.last_uuids.borrow_mut().push(msg.id);
|
self.last_uuids.borrow_mut().push(msg.id);
|
||||||
|
|
||||||
if (self.handler)(msg.time).is_err() {
|
if (self.handler)(msg.time, handler_arg).is_err() {
|
||||||
println!("[WARN] error in time handler -> not sending confirmation");
|
println!("[WARN] error in time handler -> not sending confirmation");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +143,7 @@ impl Comm {
|
||||||
let reply = serde_json::to_string(&reply).unwrap();
|
let reply = serde_json::to_string(&reply).unwrap();
|
||||||
let reply = self.crypto.encrypt(&reply);
|
let reply = self.crypto.encrypt(&reply);
|
||||||
self.client.borrow_mut()
|
self.client.borrow_mut()
|
||||||
.publish(&self.topic, mqtt::QoS::AtMostOnce, false, reply.as_bytes())
|
.publish(&self.topics.confirmation, mqtt::QoS::AtMostOnce, false, reply.as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
let wasm_inited_resolve;
|
let wasm_inited_resolve;
|
||||||
const wasm_inited = new Promise((resolve) => {wasm_inited_resolve = resolve;});
|
const wasm_inited = new Promise((resolve) => {
|
||||||
|
wasm_inited_resolve = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener("wasm-loaded", () => {
|
document.addEventListener("wasm-loaded", () => {
|
||||||
wasm_inited_resolve(wasm_bindgen)
|
wasm_inited_resolve(wasm_bindgen);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("alpine:init", () => {
|
document.addEventListener("alpine:init", () => {
|
||||||
Alpine.store("mqtt", {
|
Alpine.store("mqtt", {
|
||||||
connected: false,
|
connected: false,
|
||||||
_client: null,
|
_client: null,
|
||||||
_topic: null,
|
_topics: null,
|
||||||
_c: null,
|
_c: null,
|
||||||
|
|
||||||
_pendingPromises: {},
|
_pendingPromises: {},
|
||||||
|
@ -18,7 +20,9 @@ document.addEventListener("alpine:init", () => {
|
||||||
if (!this.connected) return null;
|
if (!this.connected) return null;
|
||||||
|
|
||||||
const id = uuidv4();
|
const id = uuidv4();
|
||||||
const promise = new Promise((resolve, reject) => {this._pendingPromises[id] = [resolve, reject]});
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
this._pendingPromises[id] = [resolve, reject];
|
||||||
|
});
|
||||||
this._publish({
|
this._publish({
|
||||||
id: id, // used to prevent replay attacks and to identify confirm messages
|
id: id, // used to prevent replay attacks and to identify confirm messages
|
||||||
kind: "Time", // can be "time" or "confirm"
|
kind: "Time", // can be "time" or "confirm"
|
||||||
|
@ -30,7 +34,7 @@ document.addEventListener("alpine:init", () => {
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
if (this.connected) return;
|
if (this.connected) return;
|
||||||
|
|
||||||
const password = Alpine.store("localState").password;
|
const password = Alpine.store("localState").password;
|
||||||
const that = this;
|
const that = this;
|
||||||
const brokerDomain = "broker.emqx.io";
|
const brokerDomain = "broker.emqx.io";
|
||||||
|
@ -38,7 +42,7 @@ document.addEventListener("alpine:init", () => {
|
||||||
|
|
||||||
if (!password) return false;
|
if (!password) return false;
|
||||||
|
|
||||||
const {Crypto} = await wasm_inited;
|
const { Crypto } = await wasm_inited;
|
||||||
|
|
||||||
Alpine.store("localState")._state = 5;
|
Alpine.store("localState")._state = 5;
|
||||||
|
|
||||||
|
@ -47,12 +51,18 @@ document.addEventListener("alpine:init", () => {
|
||||||
|
|
||||||
console.log("Test", this._encrypt("test"));
|
console.log("Test", this._encrypt("test"));
|
||||||
|
|
||||||
this._topic = Crypto.sha256(
|
this._topics = {
|
||||||
this._encrypt(`org.speedclimbing.ok-ready-go.${password}`)
|
time: Crypto.sha256(
|
||||||
).toString();
|
this._encrypt(`org.speedclimbing.ok-ready-go.${password}.time`)
|
||||||
|
).toString(),
|
||||||
|
confirmation: Crypto.sha256(
|
||||||
|
this._encrypt(
|
||||||
|
`org.speedclimbing.ok-ready-go.${password}.confirmation`
|
||||||
|
)
|
||||||
|
).toString(),
|
||||||
|
};
|
||||||
|
|
||||||
console.log("Connecting to MQTT broker...");
|
console.log("Connecting to MQTT broker...");
|
||||||
console.log("topic:", this._topic);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
// Clean session
|
// Clean session
|
||||||
|
@ -65,7 +75,7 @@ document.addEventListener("alpine:init", () => {
|
||||||
this._client.on("connect", () => {
|
this._client.on("connect", () => {
|
||||||
Alpine.store("localState")._state = 0;
|
Alpine.store("localState")._state = 0;
|
||||||
|
|
||||||
that._client.subscribe(that._topic);
|
that._client.subscribe(that._topics.confirmation);
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -74,7 +84,12 @@ document.addEventListener("alpine:init", () => {
|
||||||
message = that._decrypt(message.toString());
|
message = that._decrypt(message.toString());
|
||||||
const data = JSON.parse(message);
|
const data = JSON.parse(message);
|
||||||
|
|
||||||
if (topic !== that._topic || data.kind !== "Confirm" || Object.keys(this._pendingPromises).indexOf(data.id) === -1) return;
|
if (
|
||||||
|
topic !== that._topics.confirmation ||
|
||||||
|
data.kind !== "Confirm" ||
|
||||||
|
Object.keys(this._pendingPromises).indexOf(data.id) === -1
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
console.log("<<< ", data);
|
console.log("<<< ", data);
|
||||||
this._pendingPromises[data.id][0]();
|
this._pendingPromises[data.id][0]();
|
||||||
|
@ -82,13 +97,13 @@ document.addEventListener("alpine:init", () => {
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnect() {
|
disconnect() {
|
||||||
if(!this.connected) return;
|
if (!this.connected) return;
|
||||||
|
|
||||||
this._client.end(true);
|
this._client.end(true);
|
||||||
|
|
||||||
this._client = null;
|
this._client = null;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this._topic = null;
|
this._topics = null;
|
||||||
|
|
||||||
for (const promiseId in this._pendingPromises) {
|
for (const promiseId in this._pendingPromises) {
|
||||||
this._pendingPromises[promiseId][1]();
|
this._pendingPromises[promiseId][1]();
|
||||||
|
@ -100,7 +115,7 @@ document.addEventListener("alpine:init", () => {
|
||||||
_publish(data) {
|
_publish(data) {
|
||||||
const encryptedData = this._encrypt(JSON.stringify(data));
|
const encryptedData = this._encrypt(JSON.stringify(data));
|
||||||
console.log(">>> ", data);
|
console.log(">>> ", data);
|
||||||
this._client.publish(this._topic, encryptedData, {
|
this._client.publish(this._topics.time, encryptedData, {
|
||||||
qos: 1,
|
qos: 1,
|
||||||
retain: false,
|
retain: false,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue