@annadata/capacitor-mqtt-quic 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -233,6 +233,20 @@ class QuicClient {
233
233
  state.recv_buf.insert(state.recv_buf.end(), data, data + datalen);
234
234
  LOGI("recv stream data stream_id=%" PRId64 " len=%zu recv_buf_total=%zu",
235
235
  (int64_t)stream_id, datalen, state.recv_buf.size());
236
+ if (datalen > 2 && datalen <= 32) {
237
+ char hex[128];
238
+ size_t n = datalen < 16 ? datalen : 16u;
239
+ char *p = hex;
240
+ for (size_t i = 0; i < n && p < hex + sizeof(hex) - 4; i++)
241
+ p += snprintf(p, (size_t)(hex + sizeof(hex) - p), "%02x", data[i]);
242
+ LOGI("recv first bytes (type 0x%02x = %s) hex=%s",
243
+ (unsigned)data[0],
244
+ (data[0] & 0xF0) == 0x30 ? "PUBLISH" : (data[0] == (uint8_t)0xd0 ? "PINGRESP" : "other"),
245
+ hex);
246
+ } else if (datalen > 32) {
247
+ LOGI("recv large chunk len=%zu first_byte=0x%02x (PUBLISH=0x30)",
248
+ datalen, (unsigned)data[0]);
249
+ }
236
250
  if (flags & NGTCP2_STREAM_DATA_FLAG_FIN) {
237
251
  state.fin_received = true;
238
252
  }
@@ -121,7 +121,10 @@ class MqttQuicPlugin : Plugin() {
121
121
  } catch (_: Exception) {
122
122
  Base64.encodeToString(payload, Base64.NO_WRAP)
123
123
  }
124
- val data = JSObject().put("topic", topic).put("payload", payloadStr)
124
+ // Ensure non-null strings so Capacitor bridge never receives undefined
125
+ val safeTopic = topic ?: ""
126
+ val safePayload = payloadStr ?: ""
127
+ val data = JSObject().put("topic", safeTopic).put("payload", safePayload)
125
128
  Handler(Looper.getMainLooper()).post {
126
129
  notifyListeners("message", data)
127
130
  }
@@ -613,30 +613,35 @@ class MQTTClient {
613
613
  }
614
614
  MQTTMessageType.PUBLISH -> {
615
615
  val qos = (msgType.toInt() shr 1) and 0x03
616
- val (topic, packetId, payload) = lock.withLock {
617
- if (activeProtocolVersion == MQTTProtocolLevel.V5) {
618
- MQTT5Protocol.parsePublishV5(rest, 0, qos, topicAliasMap)
619
- } else {
620
- MQTTProtocol.parsePublish(rest, 0, qos)
621
- }
622
- }
623
-
624
- val (cb, globalCb) = lock.withLock {
625
- subscribedTopics[topic] to onPublish
626
- }
627
- globalCb?.invoke(topic, payload)
628
- cb?.invoke(payload)
629
-
630
- if (qos >= 1 && packetId != null) {
631
- val w = lock.withLock { writer }
632
- w?.let {
633
- if (qos == 1) {
634
- it.write(MQTTProtocol.buildPuback(packetId))
616
+ try {
617
+ val (topic, packetId, payload) = lock.withLock {
618
+ if (activeProtocolVersion == MQTTProtocolLevel.V5) {
619
+ MQTT5Protocol.parsePublishV5(rest, 0, qos, topicAliasMap)
635
620
  } else {
636
- it.write(MQTTProtocol.buildPubrec(packetId))
621
+ MQTTProtocol.parsePublish(rest, 0, qos)
622
+ }
623
+ }
624
+ val (cb, globalCb) = lock.withLock {
625
+ subscribedTopics[topic] to onPublish
626
+ }
627
+ globalCb?.invoke(topic, payload)
628
+ cb?.invoke(payload)
629
+
630
+ if (qos >= 1 && packetId != null) {
631
+ val w = lock.withLock { writer }
632
+ w?.let {
633
+ if (qos == 1) {
634
+ it.write(MQTTProtocol.buildPuback(packetId))
635
+ } else {
636
+ it.write(MQTTProtocol.buildPubrec(packetId))
637
+ }
638
+ it.drain()
637
639
  }
638
- it.drain()
639
640
  }
641
+ } catch (e: Exception) {
642
+ // PUBLISH parse failed: log and skip this message (don't disconnect)
643
+ val hex = rest.take(64).joinToString("") { "%02x".format(it) }
644
+ Log.w("MQTTClient", "PUBLISH parse failed: ${e.message} restLen=${rest.size} hex=$hex", e)
640
645
  }
641
646
  }
642
647
  MQTTMessageType.PUBREL -> {
@@ -555,42 +555,48 @@ public final class MQTTClient {
555
555
  pingCont?.resume()
556
556
  case MQTTMessageType.PUBLISH.rawValue:
557
557
  let qos = (msgType >> 1) & 0x03
558
- let topic: String
559
- let packetId: UInt16?
560
- let payload: Data
561
- self.lock.lock()
562
- let version = self.activeProtocolVersion
563
- if version == MQTTProtocolLevel.v5 {
564
- var map = self.topicAliasMap
565
- self.lock.unlock()
566
- (topic, packetId, payload) = try MQTT5Protocol.parsePublishV5(Data(rest), offset: 0, qos: UInt8(qos), topicAliasMap: &map)
558
+ do {
559
+ let topic: String
560
+ let packetId: UInt16?
561
+ let payload: Data
567
562
  self.lock.lock()
568
- self.topicAliasMap = map
569
- self.lock.unlock()
570
- } else {
571
- self.lock.unlock()
572
- let (t, pid, pl, _) = try MQTTProtocol.parsePublish(Data(rest), offset: 0, qos: UInt8(qos))
573
- topic = t
574
- packetId = pid
575
- payload = pl
576
- }
577
-
578
- self.lock.lock()
579
- let cb = self.subscribedTopics[topic]
580
- let globalCb = self.onPublish
581
- self.lock.unlock()
582
- globalCb?(topic, payload)
583
- cb?(payload)
563
+ let version = self.activeProtocolVersion
564
+ if version == MQTTProtocolLevel.v5 {
565
+ var map = self.topicAliasMap
566
+ self.lock.unlock()
567
+ (topic, packetId, payload) = try MQTT5Protocol.parsePublishV5(Data(rest), offset: 0, qos: UInt8(qos), topicAliasMap: &map)
568
+ self.lock.lock()
569
+ self.topicAliasMap = map
570
+ self.lock.unlock()
571
+ } else {
572
+ self.lock.unlock()
573
+ let (t, pid, pl, _) = try MQTTProtocol.parsePublish(Data(rest), offset: 0, qos: UInt8(qos))
574
+ topic = t
575
+ packetId = pid
576
+ payload = pl
577
+ }
584
578
 
585
- if qos >= 1, let pid = packetId {
586
579
  self.lock.lock()
587
- let wPuback = self.writer
580
+ let cb = self.subscribedTopics[topic]
581
+ let globalCb = self.onPublish
588
582
  self.lock.unlock()
589
- if let wPuback = wPuback {
590
- let puback = MQTTProtocol.buildPuback(packetId: pid)
591
- try await wPuback.write(Data(puback))
592
- try await wPuback.drain()
583
+ globalCb?(topic, payload)
584
+ cb?(payload)
585
+
586
+ if qos >= 1, let pid = packetId {
587
+ self.lock.lock()
588
+ let wPuback = self.writer
589
+ self.lock.unlock()
590
+ if let wPuback = wPuback {
591
+ let puback = MQTTProtocol.buildPuback(packetId: pid)
592
+ try await wPuback.write(Data(puback))
593
+ try await wPuback.drain()
594
+ }
593
595
  }
596
+ } catch {
597
+ // PUBLISH parse failed: log and skip this message (don't disconnect)
598
+ let hex = rest.prefix(64).map { String(format: "%02x", $0) }.joined()
599
+ print("[MqttQuic] PUBLISH parse failed: \(error) restLen=\(rest.count) hex=\(hex)")
594
600
  }
595
601
  default:
596
602
  break
@@ -139,7 +139,7 @@ public class MqttQuicPlugin: CAPPlugin, CAPBridgedPlugin {
139
139
  return payload.base64EncodedString()
140
140
  }()
141
141
  DispatchQueue.main.async {
142
- self.notifyListeners("message", data: ["topic": topic as String, "payload": payloadStr as String])
142
+ self.notifyListeners("message", data: ["topic": topic, "payload": payloadStr])
143
143
  }
144
144
  }
145
145
  try await client.connect(
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@annadata/capacitor-mqtt-quic",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "description": "MQTT-over-QUIC client for Capacitor (iOS, Android, Web). Native: ngtcp2+WolfSSL; Web: MQTT over WebSocket (WSS), same API.",
6
6
  "main": "dist/plugin.cjs.js",