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); }, }); });