@annadata/capacitor-mqtt-quic 0.1.8 → 0.1.9
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.
- package/android/build-wolfssl.sh +8 -2
- package/android/install/nghttp3-android/arm64-v8a/lib/libnghttp3.a +0 -0
- package/android/install/nghttp3-android/arm64-v8a/lib/libnghttp3.so +0 -0
- package/android/install/nghttp3-android/arm64-v8a/lib/pkgconfig/libnghttp3.pc +4 -4
- package/android/install/nghttp3-android/armeabi-v7a/lib/libnghttp3.a +0 -0
- package/android/install/nghttp3-android/armeabi-v7a/lib/libnghttp3.so +0 -0
- package/android/install/nghttp3-android/armeabi-v7a/lib/pkgconfig/libnghttp3.pc +4 -4
- package/android/install/nghttp3-android/x86_64/lib/libnghttp3.a +0 -0
- package/android/install/nghttp3-android/x86_64/lib/libnghttp3.so +0 -0
- package/android/install/nghttp3-android/x86_64/lib/pkgconfig/libnghttp3.pc +4 -4
- package/android/install/ngtcp2-android/arm64-v8a/lib/libngtcp2.a +0 -0
- package/android/install/ngtcp2-android/arm64-v8a/lib/libngtcp2.so +0 -0
- package/android/install/ngtcp2-android/arm64-v8a/lib/libngtcp2_crypto_wolfssl.a +0 -0
- package/android/install/ngtcp2-android/arm64-v8a/lib/libngtcp2_crypto_wolfssl.so +0 -0
- package/android/install/ngtcp2-android/arm64-v8a/lib/pkgconfig/libngtcp2.pc +4 -4
- package/android/install/ngtcp2-android/arm64-v8a/lib/pkgconfig/libngtcp2_crypto_wolfssl.pc +4 -4
- package/android/install/ngtcp2-android/armeabi-v7a/lib/libngtcp2.a +0 -0
- package/android/install/ngtcp2-android/armeabi-v7a/lib/libngtcp2.so +0 -0
- package/android/install/ngtcp2-android/armeabi-v7a/lib/libngtcp2_crypto_wolfssl.a +0 -0
- package/android/install/ngtcp2-android/armeabi-v7a/lib/libngtcp2_crypto_wolfssl.so +0 -0
- package/android/install/ngtcp2-android/armeabi-v7a/lib/pkgconfig/libngtcp2.pc +4 -4
- package/android/install/ngtcp2-android/armeabi-v7a/lib/pkgconfig/libngtcp2_crypto_wolfssl.pc +4 -4
- package/android/install/ngtcp2-android/x86_64/lib/libngtcp2.a +0 -0
- package/android/install/ngtcp2-android/x86_64/lib/libngtcp2.so +0 -0
- package/android/install/ngtcp2-android/x86_64/lib/libngtcp2_crypto_wolfssl.a +0 -0
- package/android/install/ngtcp2-android/x86_64/lib/libngtcp2_crypto_wolfssl.so +0 -0
- package/android/install/ngtcp2-android/x86_64/lib/pkgconfig/libngtcp2.pc +4 -4
- package/android/install/ngtcp2-android/x86_64/lib/pkgconfig/libngtcp2_crypto_wolfssl.pc +4 -4
- package/android/install/wolfssl-android/arm64-v8a/bin/wolfssl-config +1 -1
- package/android/install/wolfssl-android/arm64-v8a/lib/libwolfssl.a +0 -0
- package/android/install/wolfssl-android/arm64-v8a/lib/libwolfssl.la +1 -1
- package/android/install/wolfssl-android/arm64-v8a/lib/pkgconfig/wolfssl.pc +1 -1
- package/android/install/wolfssl-android/armeabi-v7a/bin/wolfssl-config +1 -1
- package/android/install/wolfssl-android/armeabi-v7a/lib/libwolfssl.a +0 -0
- package/android/install/wolfssl-android/armeabi-v7a/lib/libwolfssl.la +1 -1
- package/android/install/wolfssl-android/armeabi-v7a/lib/pkgconfig/wolfssl.pc +1 -1
- package/android/install/wolfssl-android/x86_64/bin/wolfssl-config +1 -1
- package/android/install/wolfssl-android/x86_64/lib/libwolfssl.a +0 -0
- package/android/install/wolfssl-android/x86_64/lib/libwolfssl.la +1 -1
- package/android/install/wolfssl-android/x86_64/lib/pkgconfig/wolfssl.pc +1 -1
- package/android/src/main/cpp/ngtcp2_jni.cpp +94 -19
- package/android/src/main/kotlin/ai/annadata/mqttquic/MqttQuicPlugin.kt +58 -3
- package/android/src/main/kotlin/ai/annadata/mqttquic/client/MQTTClient.kt +230 -80
- package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTTProtocol.kt +33 -2
- package/android/src/main/kotlin/ai/annadata/mqttquic/quic/NGTCP2Client.kt +25 -15
- package/android/src/main/kotlin/ai/annadata/mqttquic/quic/QuicClientStub.kt +1 -1
- package/android/src/main/kotlin/ai/annadata/mqttquic/quic/QuicTypes.kt +1 -1
- package/android/src/main/kotlin/ai/annadata/mqttquic/transport/QUICStreamAdapter.kt +80 -5
- package/android/src/main/kotlin/ai/annadata/mqttquic/transport/StreamTransport.kt +4 -0
- package/docs/diff-node_modules-vs-standalone-android-src.patch +1031 -0
- package/ios/build-wolfssl.sh +8 -3
- package/ios/libs/libnghttp3.a +0 -0
- package/ios/libs/libngtcp2.a +0 -0
- package/ios/libs/libngtcp2_crypto_wolfssl.a +0 -0
- package/ios/libs/libwolfssl.a +0 -0
- package/ios/libs-simulator/libnghttp3.a +0 -0
- package/ios/libs-simulator/libngtcp2.a +0 -0
- package/ios/libs-simulator/libngtcp2_crypto_wolfssl.a +0 -0
- package/ios/libs-simulator/libwolfssl.a +0 -0
- package/ios/libs-simulator-x86_64/libnghttp3.a +0 -0
- package/ios/libs-simulator-x86_64/libngtcp2.a +0 -0
- package/ios/libs-simulator-x86_64/libngtcp2_crypto_wolfssl.a +0 -0
- package/ios/libs-simulator-x86_64/libwolfssl.a +0 -0
- package/package.json +1 -1
- package/ios/libs/MqttQuicLibs.xcframework/Info.plist +0 -44
- package/ios/libs/MqttQuicLibs.xcframework/ios-arm64/libmqttquic_native_device.a +0 -0
- package/ios/libs/MqttQuicLibs.xcframework/ios-arm64_x86_64-simulator/libmqttquic_native_simulator.a +0 -0
|
@@ -1,21 +1,96 @@
|
|
|
1
1
|
package ai.annadata.mqttquic.transport
|
|
2
2
|
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import ai.annadata.mqttquic.mqtt.MQTTProtocol
|
|
3
5
|
import ai.annadata.mqttquic.quic.QuicStream
|
|
6
|
+
import kotlinx.coroutines.delay
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
|
-
* MQTTStreamReader over QUIC stream.
|
|
9
|
+
* MQTTStreamReader over QUIC stream. Buffers excess bytes so readexactly(n)
|
|
10
|
+
* and read(maxBytes) get exactly the requested amount; native may return
|
|
11
|
+
* a full CONNACK (e.g. 18 bytes) in one read, so we must not lose the remainder.
|
|
12
|
+
*
|
|
13
|
+
* Efficient CONNACK/packet read: call [drain] to read until the stream has no more
|
|
14
|
+
* data, then [tryConsumeNextPacket] to take the first complete MQTT packet from
|
|
15
|
+
* the buffer. Repeat drain + tryConsumeNextPacket (with short delay) until you
|
|
16
|
+
* get a packet or timeout.
|
|
7
17
|
*/
|
|
8
18
|
class QUICStreamReader(private val stream: QuicStream) : MQTTStreamReader {
|
|
9
19
|
|
|
10
|
-
|
|
20
|
+
private val buffer = mutableListOf<Byte>()
|
|
21
|
+
|
|
22
|
+
override suspend fun available(): Int = buffer.size
|
|
23
|
+
|
|
24
|
+
/** Read from stream until no more data is available (drained). Call before tryConsumeNextPacket. */
|
|
25
|
+
suspend fun drain() {
|
|
26
|
+
while (true) {
|
|
27
|
+
val chunk = stream.read(8192)
|
|
28
|
+
if (chunk.isEmpty()) break
|
|
29
|
+
Log.i("MQTTClient", "QUICStreamReader: drain got ${chunk.size} bytes bufferTotal=${buffer.size + chunk.size}")
|
|
30
|
+
buffer.addAll(chunk.toList())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Consume the first n bytes from buffer and return them. Caller must ensure buffer.size >= n. */
|
|
35
|
+
fun consume(n: Int): ByteArray {
|
|
36
|
+
if (buffer.size < n) throw IllegalArgumentException("buffer has ${buffer.size} < $n")
|
|
37
|
+
val out = buffer.take(n).toByteArray()
|
|
38
|
+
repeat(n) { buffer.removeAt(0) }
|
|
39
|
+
return out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* If buffer contains at least one complete MQTT packet (fixed header + payload), consume and return it; else return null.
|
|
44
|
+
* Call after [drain]; if null, delay and drain again (or timeout).
|
|
45
|
+
*/
|
|
46
|
+
fun tryConsumeNextPacket(): ByteArray? {
|
|
47
|
+
val buf = buffer.toByteArray()
|
|
48
|
+
val totalLen = MQTTProtocol.getNextPacketLength(buf)
|
|
49
|
+
if (totalLen == null) {
|
|
50
|
+
if (buf.isNotEmpty()) {
|
|
51
|
+
Log.w("MQTTClient", "QUICStreamReader: getNextPacketLength returned null bufferSize=${buf.size} firstByte=0x${Integer.toHexString(buf[0].toInt() and 0xFF)}")
|
|
52
|
+
}
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
if (buffer.size < totalLen) {
|
|
56
|
+
Log.i("MQTTClient", "QUICStreamReader: buffer.size=${buffer.size} < totalLen=$totalLen waiting for more")
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
val packet = consume(totalLen)
|
|
60
|
+
Log.i("MQTTClient", "QUICStreamReader: tryConsumeNextPacket consumed $totalLen bytes type=0x${Integer.toHexString(packet[0].toInt() and 0xFF)}")
|
|
61
|
+
return packet
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override suspend fun read(maxBytes: Int): ByteArray {
|
|
65
|
+
while (buffer.size < maxBytes) {
|
|
66
|
+
val chunk = stream.read(maxBytes - buffer.size)
|
|
67
|
+
if (chunk.isEmpty()) break
|
|
68
|
+
Log.i("MQTTClient", "QUICStreamReader: got chunk=${chunk.size} bufferSize=${buffer.size + chunk.size}")
|
|
69
|
+
buffer.addAll(chunk.toList())
|
|
70
|
+
}
|
|
71
|
+
val n = minOf(maxBytes, buffer.size)
|
|
72
|
+
if (n == 0) return ByteArray(0)
|
|
73
|
+
val result = buffer.subList(0, n).toByteArray()
|
|
74
|
+
repeat(n) { buffer.removeAt(0) }
|
|
75
|
+
Log.i("MQTTClient", "QUICStreamReader: returning $n bytes bufferRemain=${buffer.size}")
|
|
76
|
+
return result
|
|
77
|
+
}
|
|
11
78
|
|
|
12
79
|
override suspend fun readexactly(n: Int): ByteArray {
|
|
80
|
+
Log.i("MQTTClient", "QUICStreamReader: readexactly($n) bufferHas=${buffer.size}")
|
|
13
81
|
val acc = mutableListOf<Byte>()
|
|
14
82
|
while (acc.size < n) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
83
|
+
drain()
|
|
84
|
+
val fromBuffer = minOf(n - acc.size, buffer.size)
|
|
85
|
+
if (fromBuffer > 0) {
|
|
86
|
+
acc.addAll(buffer.subList(0, fromBuffer).toList())
|
|
87
|
+
repeat(fromBuffer) { buffer.removeAt(0) }
|
|
88
|
+
} else {
|
|
89
|
+
// No data yet (e.g. message loop waiting for SUBACK/PUBLISH). Wait and retry instead of throwing.
|
|
90
|
+
delay(20L)
|
|
91
|
+
}
|
|
18
92
|
}
|
|
93
|
+
Log.i("MQTTClient", "QUICStreamReader: readexactly($n) done")
|
|
19
94
|
return acc.toByteArray()
|
|
20
95
|
}
|
|
21
96
|
}
|
|
@@ -7,6 +7,8 @@ import kotlinx.coroutines.delay
|
|
|
7
7
|
* Phase 2 implements over QUIC stream.
|
|
8
8
|
*/
|
|
9
9
|
interface MQTTStreamReader {
|
|
10
|
+
/** Number of bytes currently buffered (without reading from stream). Used to skip unwanted packets only when safe. */
|
|
11
|
+
suspend fun available(): Int
|
|
10
12
|
suspend fun read(maxBytes: Int): ByteArray
|
|
11
13
|
suspend fun readexactly(n: Int): ByteArray
|
|
12
14
|
}
|
|
@@ -50,6 +52,8 @@ class MockStreamBuffer(initialReadData: ByteArray = ByteArray(0)) {
|
|
|
50
52
|
*/
|
|
51
53
|
class MockStreamReader(private val buffer: MockStreamBuffer) : MQTTStreamReader {
|
|
52
54
|
|
|
55
|
+
override suspend fun available(): Int = buffer.readBuffer.size
|
|
56
|
+
|
|
53
57
|
override suspend fun read(maxBytes: Int): ByteArray {
|
|
54
58
|
if (buffer.isClosed && buffer.readBuffer.isEmpty()) return ByteArray(0)
|
|
55
59
|
val n = minOf(maxBytes, buffer.readBuffer.size)
|