ok-ready-go/js/mqtt.js

118 lines
2.9 KiB
JavaScript

let wasm_inited_resolve;
const wasm_inited = new Promise((resolve) => {wasm_inited_resolve = resolve;});
document.addEventListener("wasm-loaded", () => {
wasm_inited_resolve(wasm_bindgen)
});
document.addEventListener("alpine:init", () => {
Alpine.store("mqtt", {
connected: false,
_client: null,
_topic: null,
_c: null,
_pendingPromises: {},
sendTime(time) {
if (!this.connected) return null;
const id = uuidv4();
const promise = new Promise((resolve, reject) => {this._pendingPromises[id] = [resolve, reject]});
this._publish({
id: id, // used to prevent replay attacks and to identify confirm messages
kind: "Time", // can be "time" or "confirm"
time: time, // only used for "time"
});
return promise;
},
async connect() {
if (this.connected) return;
const password = Alpine.store("localState").password;
const that = this;
const brokerDomain = "broker.emqx.io";
const url = `wss://${brokerDomain}:8084/mqtt`;
if (!password) return false;
const {Crypto} = await wasm_inited;
Alpine.store("localState")._state = 5;
// derive key from password
this._c = new Crypto(password, brokerDomain);
console.log("Test", this._encrypt("test"));
this._topic = Crypto.sha256(
this._encrypt(`org.speedclimbing.ok-ready-go.${password}`)
).toString();
console.log("Connecting to MQTT broker...");
console.log("topic:", this._topic);
const options = {
// Clean session
clean: true,
connectTimeout: 4000,
};
this._client = mqtt.connect(url, options);
this._client.on("connect", () => {
Alpine.store("localState")._state = 0;
that._client.subscribe(that._topic);
this.connected = true;
});
this._client.on("message", (topic, message) => {
// message is Buffer
message = that._decrypt(message.toString());
const data = JSON.parse(message);
if (topic !== that._topic || data.kind !== "Confirm" || Object.keys(this._pendingPromises).indexOf(data.id) === -1) return;
console.log("<<< ", data);
this._pendingPromises[data.id][0]();
});
},
disconnect() {
if(!this.connected) return;
this._client.end(true);
this._client = null;
this.connected = false;
this._topic = null;
for (const promiseId in this._pendingPromises) {
this._pendingPromises[promiseId][1]();
}
this._pendingPromises = {};
},
_publish(data) {
const encryptedData = this._encrypt(JSON.stringify(data));
console.log(">>> ", data);
this._client.publish(this._topic, encryptedData, {
qos: 1,
retain: false,
});
},
_encrypt(data) {
return this._c.encrypt(data);
},
_decrypt(data) {
return this._c.decrypt(data);
},
});
});