@annadata/capacitor-mqtt-quic 0.1.2 → 0.1.3
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.gradle +2 -1
- package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTT5Properties.kt +2 -2
- package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTT5ReasonCodes.kt +76 -64
- package/ios/MqttQuicPlugin.podspec +1 -1
- package/ios/Sources/MqttQuicPlugin/MQTT/MQTT5Properties.swift +2 -2
- package/ios/Sources/MqttQuicPlugin/MQTT/MQTT5ReasonCodes.swift.rej +131 -0
- package/ios/Sources/MqttQuicPlugin/MqttQuicPlugin.swift +11 -0
- package/ios/Sources/MqttQuicPlugin/Transport/StreamTransport.swift +5 -1
- package/ios/build-nghttp3.sh +13 -4
- package/ios/build-ngtcp2.sh +6 -2
- package/ios/libs/libcrypto.a +0 -0
- package/ios/libs/libnghttp3.a +0 -0
- package/ios/libs/libngtcp2.a +0 -0
- package/ios/libs/libngtcp2_crypto_quictls.a +0 -0
- package/ios/libs/libssl.a +0 -0
- package/package.json +1 -1
package/android/build.gradle
CHANGED
|
@@ -22,6 +22,7 @@ apply plugin: 'org.jetbrains.kotlin.android'
|
|
|
22
22
|
android {
|
|
23
23
|
namespace "ai.annadata.mqttquic"
|
|
24
24
|
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
|
25
|
+
ndkVersion "26.1.10909125"
|
|
25
26
|
defaultConfig {
|
|
26
27
|
minSdk project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
|
27
28
|
targetSdk project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
|
@@ -66,7 +67,7 @@ repositories {
|
|
|
66
67
|
|
|
67
68
|
dependencies {
|
|
68
69
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
69
|
-
|
|
70
|
+
compileOnly 'com.getcapacitor:core:6.0.0'
|
|
70
71
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
71
72
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
|
72
73
|
testImplementation "junit:junit:$junitVersion"
|
|
@@ -58,7 +58,7 @@ object MQTT5PropertyEncoder {
|
|
|
58
58
|
|
|
59
59
|
when (propId) {
|
|
60
60
|
MQTT5PropertyType.PAYLOAD_FORMAT_INDICATOR.toInt() -> {
|
|
61
|
-
result.add(((value as? Int) ?: 0).toByte())
|
|
61
|
+
result.add((((value as? Int) ?: 0) and 0xFF).toByte())
|
|
62
62
|
}
|
|
63
63
|
MQTT5PropertyType.MESSAGE_EXPIRY_INTERVAL.toInt(),
|
|
64
64
|
MQTT5PropertyType.SESSION_EXPIRY_INTERVAL.toInt(),
|
|
@@ -104,7 +104,7 @@ object MQTT5PropertyEncoder {
|
|
|
104
104
|
MQTT5PropertyType.WILDCARD_SUBSCRIPTION_AVAILABLE.toInt(),
|
|
105
105
|
MQTT5PropertyType.SUBSCRIPTION_IDENTIFIER_AVAILABLE.toInt(),
|
|
106
106
|
MQTT5PropertyType.SHARED_SUBSCRIPTION_AVAILABLE.toInt() -> {
|
|
107
|
-
result.add(((value as? Int) ?: 0).toByte())
|
|
107
|
+
result.add((((value as? Int) ?: 0) and 0xFF).toByte())
|
|
108
108
|
}
|
|
109
109
|
MQTT5PropertyType.USER_PROPERTY.toInt() -> {
|
|
110
110
|
if (value is Pair<*, *>) {
|
|
@@ -2,14 +2,24 @@ package ai.annadata.mqttquic.mqtt
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* MQTT 5.0 Reason Codes. Matches MQTTD mqttd/reason_codes.py.
|
|
5
|
+
* MQTT 5.0 reuses byte values across packet types; we keep one constant per unique byte.
|
|
6
|
+
* Context-specific aliases are provided as properties for semantic clarity.
|
|
5
7
|
*/
|
|
6
8
|
object MQTT5ReasonCode {
|
|
7
|
-
// Success
|
|
9
|
+
// 0x00 - Success (CONNACK), Granted QoS 0 (SUBACK), Success (UNSUBACK), Normal disconnection (DISCONNECT)
|
|
8
10
|
const val SUCCESS: Int = 0x00
|
|
9
|
-
|
|
11
|
+
// 0x01 - Granted QoS 1 (SUBACK)
|
|
12
|
+
const val GRANTED_QOS_1: Int = 0x01
|
|
13
|
+
// 0x02 - Granted QoS 2 (SUBACK)
|
|
14
|
+
const val GRANTED_QOS_2: Int = 0x02
|
|
15
|
+
// 0x04 - Disconnect with will message
|
|
10
16
|
const val DISCONNECT_WITH_WILL_MESSAGE: Int = 0x04
|
|
17
|
+
// 0x10 - No matching subscribers (PUBACK/PUBREC/PUBREL/PUBCOMP)
|
|
18
|
+
const val NO_MATCHING_SUBSCRIBERS: Int = 0x10
|
|
19
|
+
// 0x11 - No subscription existed (UNSUBACK)
|
|
20
|
+
const val NO_SUBSCRIPTION_EXISTED: Int = 0x11
|
|
11
21
|
|
|
12
|
-
// CONNACK
|
|
22
|
+
// CONNACK / generic errors (0x80+)
|
|
13
23
|
const val UNSPECIFIED_ERROR: Int = 0x80
|
|
14
24
|
const val MALFORMED_PACKET: Int = 0x81
|
|
15
25
|
const val PROTOCOL_ERROR: Int = 0x82
|
|
@@ -21,81 +31,83 @@ object MQTT5ReasonCode {
|
|
|
21
31
|
const val SERVER_UNAVAILABLE: Int = 0x88
|
|
22
32
|
const val SERVER_BUSY: Int = 0x89
|
|
23
33
|
const val BANNED: Int = 0x8A
|
|
34
|
+
const val SERVER_SHUTTING_DOWN: Int = 0x8B
|
|
24
35
|
const val BAD_AUTHENTICATION_METHOD: Int = 0x8C
|
|
36
|
+
const val KEEP_ALIVE_TIMEOUT: Int = 0x8D
|
|
37
|
+
const val SESSION_TAKEN_OVER: Int = 0x8E
|
|
38
|
+
const val TOPIC_FILTER_INVALID: Int = 0x8F
|
|
25
39
|
const val TOPIC_NAME_INVALID: Int = 0x90
|
|
40
|
+
const val PACKET_IDENTIFIER_IN_USE: Int = 0x91
|
|
41
|
+
const val RECEIVE_MAXIMUM_EXCEEDED: Int = 0x93
|
|
42
|
+
const val TOPIC_ALIAS_INVALID: Int = 0x94
|
|
26
43
|
const val PACKET_TOO_LARGE: Int = 0x95
|
|
44
|
+
const val MESSAGE_RATE_TOO_HIGH: Int = 0x96
|
|
27
45
|
const val QUOTA_EXCEEDED: Int = 0x97
|
|
46
|
+
const val ADMINISTRATIVE_ACTION: Int = 0x98
|
|
28
47
|
const val PAYLOAD_FORMAT_INVALID: Int = 0x99
|
|
29
48
|
const val RETAIN_NOT_SUPPORTED: Int = 0x9A
|
|
30
49
|
const val QOS_NOT_SUPPORTED: Int = 0x9B
|
|
31
50
|
const val USE_ANOTHER_SERVER: Int = 0x9C
|
|
32
51
|
const val SERVER_MOVED: Int = 0x9D
|
|
33
|
-
const val CONNECTION_RATE_EXCEEDED: Int = 0x9F
|
|
34
|
-
|
|
35
|
-
// PUBACK, PUBREC, PUBREL, PUBCOMP Reason Codes
|
|
36
|
-
const val NO_MATCHING_SUBSCRIBERS: Int = 0x10
|
|
37
|
-
const val UNSPECIFIED_ERROR_PUB: Int = 0x80
|
|
38
|
-
const val IMPLEMENTATION_SPECIFIC_ERROR_PUB: Int = 0x83
|
|
39
|
-
const val NOT_AUTHORIZED_PUB: Int = 0x87
|
|
40
|
-
const val TOPIC_NAME_INVALID_PUB: Int = 0x90
|
|
41
|
-
const val PACKET_IDENTIFIER_IN_USE: Int = 0x91
|
|
42
|
-
const val QUOTA_EXCEEDED_PUB: Int = 0x97
|
|
43
|
-
const val PAYLOAD_FORMAT_INVALID_PUB: Int = 0x99
|
|
44
|
-
|
|
45
|
-
// SUBACK Reason Codes
|
|
46
|
-
const val GRANTED_QOS_0: Int = 0x00
|
|
47
|
-
const val GRANTED_QOS_1: Int = 0x01
|
|
48
|
-
const val GRANTED_QOS_2: Int = 0x02
|
|
49
|
-
const val UNSPECIFIED_ERROR_SUB: Int = 0x80
|
|
50
|
-
const val IMPLEMENTATION_SPECIFIC_ERROR_SUB: Int = 0x83
|
|
51
|
-
const val NOT_AUTHORIZED_SUB: Int = 0x87
|
|
52
|
-
const val TOPIC_FILTER_INVALID: Int = 0x8F
|
|
53
|
-
const val PACKET_IDENTIFIER_IN_USE_SUB: Int = 0x91
|
|
54
|
-
const val QUOTA_EXCEEDED_SUB: Int = 0x97
|
|
55
52
|
const val SHARED_SUBSCRIPTIONS_NOT_SUPPORTED: Int = 0x9E
|
|
53
|
+
const val CONNECTION_RATE_EXCEEDED: Int = 0x9F
|
|
54
|
+
const val MAXIMUM_CONNECT_TIME: Int = 0xA0
|
|
56
55
|
const val SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED: Int = 0xA1
|
|
57
56
|
const val WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED: Int = 0xA2
|
|
58
57
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
const val
|
|
62
|
-
const val UNSPECIFIED_ERROR_UNSUB: Int = 0x80
|
|
63
|
-
const val IMPLEMENTATION_SPECIFIC_ERROR_UNSUB: Int = 0x83
|
|
64
|
-
const val NOT_AUTHORIZED_UNSUB: Int = 0x87
|
|
65
|
-
const val TOPIC_FILTER_INVALID_UNSUB: Int = 0x8F
|
|
66
|
-
const val PACKET_IDENTIFIER_IN_USE_UNSUB: Int = 0x91
|
|
58
|
+
// Context-specific aliases (all map to the same underlying values)
|
|
59
|
+
// SUBACK aliases
|
|
60
|
+
const val GRANTED_QOS_0: Int = SUCCESS // 0x00
|
|
67
61
|
|
|
68
|
-
//
|
|
69
|
-
const val
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const val
|
|
73
|
-
const val
|
|
74
|
-
const val
|
|
75
|
-
const val
|
|
76
|
-
const val
|
|
77
|
-
const val
|
|
78
|
-
const val
|
|
79
|
-
const val
|
|
80
|
-
const val
|
|
81
|
-
const val
|
|
82
|
-
const val
|
|
83
|
-
const val
|
|
84
|
-
const val
|
|
85
|
-
const val
|
|
86
|
-
const val
|
|
87
|
-
const val
|
|
88
|
-
const val
|
|
89
|
-
const val
|
|
90
|
-
const val
|
|
91
|
-
const val
|
|
92
|
-
const val
|
|
93
|
-
const val
|
|
94
|
-
const val
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const val
|
|
98
|
-
const val
|
|
62
|
+
// UNSUBACK aliases
|
|
63
|
+
const val SUCCESS_UNSUB: Int = SUCCESS // 0x00
|
|
64
|
+
|
|
65
|
+
// DISCONNECT aliases
|
|
66
|
+
const val NORMAL_DISCONNECTION: Int = SUCCESS // 0x00
|
|
67
|
+
const val NORMAL_DISCONNECTION_DISC: Int = SUCCESS // 0x00
|
|
68
|
+
const val DISCONNECT_WITH_WILL_MESSAGE_DISC: Int = DISCONNECT_WITH_WILL_MESSAGE // 0x04
|
|
69
|
+
const val UNSPECIFIED_ERROR_DISC: Int = UNSPECIFIED_ERROR // 0x80
|
|
70
|
+
const val MALFORMED_PACKET_DISC: Int = MALFORMED_PACKET // 0x81
|
|
71
|
+
const val PROTOCOL_ERROR_DISC: Int = PROTOCOL_ERROR // 0x82
|
|
72
|
+
const val IMPLEMENTATION_SPECIFIC_ERROR_DISC: Int = IMPLEMENTATION_SPECIFIC_ERROR // 0x83
|
|
73
|
+
const val NOT_AUTHORIZED_DISC: Int = NOT_AUTHORIZED // 0x87
|
|
74
|
+
const val SERVER_BUSY_DISC: Int = SERVER_BUSY // 0x89
|
|
75
|
+
const val BAD_AUTHENTICATION_METHOD_DISC: Int = BAD_AUTHENTICATION_METHOD // 0x8C
|
|
76
|
+
const val TOPIC_FILTER_INVALID_DISC: Int = TOPIC_FILTER_INVALID // 0x8F
|
|
77
|
+
const val TOPIC_NAME_INVALID_DISC: Int = TOPIC_NAME_INVALID // 0x90
|
|
78
|
+
const val PACKET_TOO_LARGE_DISC: Int = PACKET_TOO_LARGE // 0x95
|
|
79
|
+
const val QUOTA_EXCEEDED_DISC: Int = QUOTA_EXCEEDED // 0x97
|
|
80
|
+
const val PAYLOAD_FORMAT_INVALID_DISC: Int = PAYLOAD_FORMAT_INVALID // 0x99
|
|
81
|
+
const val RETAIN_NOT_SUPPORTED_DISC: Int = RETAIN_NOT_SUPPORTED // 0x9A
|
|
82
|
+
const val QOS_NOT_SUPPORTED_DISC: Int = QOS_NOT_SUPPORTED // 0x9B
|
|
83
|
+
const val USE_ANOTHER_SERVER_DISC: Int = USE_ANOTHER_SERVER // 0x9C
|
|
84
|
+
const val SERVER_MOVED_DISC: Int = SERVER_MOVED // 0x9D
|
|
85
|
+
const val SHARED_SUBSCRIPTIONS_NOT_SUPPORTED_DISC: Int = SHARED_SUBSCRIPTIONS_NOT_SUPPORTED // 0x9E
|
|
86
|
+
const val CONNECTION_RATE_EXCEEDED_DISC: Int = CONNECTION_RATE_EXCEEDED // 0x9F
|
|
87
|
+
const val SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED_DISC: Int = SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED // 0xA1
|
|
88
|
+
const val WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED_DISC: Int = WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED // 0xA2
|
|
89
|
+
|
|
90
|
+
// PUBACK/PUBREC/PUBREL/PUBCOMP aliases
|
|
91
|
+
const val UNSPECIFIED_ERROR_PUB: Int = UNSPECIFIED_ERROR // 0x80
|
|
92
|
+
const val IMPLEMENTATION_SPECIFIC_ERROR_PUB: Int = IMPLEMENTATION_SPECIFIC_ERROR // 0x83
|
|
93
|
+
const val NOT_AUTHORIZED_PUB: Int = NOT_AUTHORIZED // 0x87
|
|
94
|
+
const val TOPIC_NAME_INVALID_PUB: Int = TOPIC_NAME_INVALID // 0x90
|
|
95
|
+
const val QUOTA_EXCEEDED_PUB: Int = QUOTA_EXCEEDED // 0x97
|
|
96
|
+
const val PAYLOAD_FORMAT_INVALID_PUB: Int = PAYLOAD_FORMAT_INVALID // 0x99
|
|
97
|
+
|
|
98
|
+
// SUBACK aliases
|
|
99
|
+
const val UNSPECIFIED_ERROR_SUB: Int = UNSPECIFIED_ERROR // 0x80
|
|
100
|
+
const val IMPLEMENTATION_SPECIFIC_ERROR_SUB: Int = IMPLEMENTATION_SPECIFIC_ERROR // 0x83
|
|
101
|
+
const val NOT_AUTHORIZED_SUB: Int = NOT_AUTHORIZED // 0x87
|
|
102
|
+
const val PACKET_IDENTIFIER_IN_USE_SUB: Int = PACKET_IDENTIFIER_IN_USE // 0x91
|
|
103
|
+
const val QUOTA_EXCEEDED_SUB: Int = QUOTA_EXCEEDED // 0x97
|
|
104
|
+
|
|
105
|
+
// UNSUBACK aliases
|
|
106
|
+
const val UNSPECIFIED_ERROR_UNSUB: Int = UNSPECIFIED_ERROR // 0x80
|
|
107
|
+
const val IMPLEMENTATION_SPECIFIC_ERROR_UNSUB: Int = IMPLEMENTATION_SPECIFIC_ERROR // 0x83
|
|
108
|
+
const val NOT_AUTHORIZED_UNSUB: Int = NOT_AUTHORIZED // 0x87
|
|
109
|
+
const val TOPIC_FILTER_INVALID_UNSUB: Int = TOPIC_FILTER_INVALID // 0x8F
|
|
110
|
+
const val PACKET_IDENTIFIER_IN_USE_UNSUB: Int = PACKET_IDENTIFIER_IN_USE // 0x91
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
// Compatibility mapping for MQTT 3.1.1 return codes
|
|
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.source = { :git => 'https://github.com/annadata/capacitor-mqtt-quic', :tag => s.version.to_s }
|
|
13
13
|
s.source_files = 'Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
14
|
s.resources = ['Sources/MqttQuicPlugin/Resources/*.pem']
|
|
15
|
-
s.ios.deployment_target = '
|
|
15
|
+
s.ios.deployment_target = '14.0'
|
|
16
16
|
s.dependency 'Capacitor'
|
|
17
17
|
s.swift_version = '5.1'
|
|
18
18
|
s.vendored_libraries = [
|
|
@@ -71,7 +71,7 @@ public final class MQTT5PropertyEncoder {
|
|
|
71
71
|
|
|
72
72
|
switch propId {
|
|
73
73
|
case MQTT5PropertyType.payloadFormatIndicator.rawValue:
|
|
74
|
-
result.append((value as? Int ?? 0) & 0xFF)
|
|
74
|
+
result.append(UInt8((value as? Int ?? 0) & 0xFF))
|
|
75
75
|
|
|
76
76
|
case MQTT5PropertyType.messageExpiryInterval.rawValue,
|
|
77
77
|
MQTT5PropertyType.sessionExpiryInterval.rawValue,
|
|
@@ -117,7 +117,7 @@ public final class MQTT5PropertyEncoder {
|
|
|
117
117
|
MQTT5PropertyType.wildcardSubscriptionAvailable.rawValue,
|
|
118
118
|
MQTT5PropertyType.subscriptionIdentifierAvailable.rawValue,
|
|
119
119
|
MQTT5PropertyType.sharedSubscriptionAvailable.rawValue:
|
|
120
|
-
result.append((value as? Int ?? 0) & 0xFF)
|
|
120
|
+
result.append(UInt8((value as? Int ?? 0) & 0xFF))
|
|
121
121
|
|
|
122
122
|
case MQTT5PropertyType.userProperty.rawValue:
|
|
123
123
|
if let pair = value as? (String, String) {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
@@ -3,17 +3,27 @@
|
|
2
|
+
// MqttQuicPlugin
|
|
3
|
+
//
|
|
4
|
+
// MQTT 5.0 Reason Codes. Matches MQTTD mqttd/reason_codes.py.
|
|
5
|
+
+// Swift requires unique raw values; MQTT 5.0 reuses byte values across packet types.
|
|
6
|
+
+// We keep one case per unique byte; semantic aliases documented in comments.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
public enum MQTT5ReasonCode: UInt8 {
|
|
12
|
+
- // Success
|
|
13
|
+
+ // 0x00 - Success (CONNACK), Granted QoS 0 (SUBACK), Success (UNSUBACK), Normal disconnection (DISCONNECT)
|
|
14
|
+
case success = 0x00
|
|
15
|
+
- case normalDisconnection = 0x00
|
|
16
|
+
+ // 0x01 - Granted QoS 1 (SUBACK)
|
|
17
|
+
+ case grantedQoS1 = 0x01
|
|
18
|
+
+ // 0x02 - Granted QoS 2 (SUBACK)
|
|
19
|
+
+ case grantedQoS2 = 0x02
|
|
20
|
+
+ // 0x04 - Disconnect with will message
|
|
21
|
+
case disconnectWithWillMessage = 0x04
|
|
22
|
+
+ // 0x10 - No matching subscribers (PUBACK/PUBREC/PUBREL/PUBCOMP)
|
|
23
|
+
+ case noMatchingSubscribers = 0x10
|
|
24
|
+
+ // 0x11 - No subscription existed (UNSUBACK)
|
|
25
|
+
+ case noSubscriptionExisted = 0x11
|
|
26
|
+
|
|
27
|
+
- // CONNACK Reason Codes
|
|
28
|
+
+ // CONNACK / generic errors (0x80+)
|
|
29
|
+
case unspecifiedError = 0x80
|
|
30
|
+
case malformedPacket = 0x81
|
|
31
|
+
case protocolError = 0x82
|
|
32
|
+
@@ -25,81 +35,37 @@
|
|
33
|
+
case serverUnavailable = 0x88
|
|
34
|
+
case serverBusy = 0x89
|
|
35
|
+
case banned = 0x8A
|
|
36
|
+
+ case serverShuttingDown = 0x8B
|
|
37
|
+
case badAuthenticationMethod = 0x8C
|
|
38
|
+
+ case keepAliveTimeout = 0x8D
|
|
39
|
+
+ case sessionTakenOver = 0x8E
|
|
40
|
+
+ case topicFilterInvalid = 0x8F
|
|
41
|
+
case topicNameInvalid = 0x90
|
|
42
|
+
+ case packetIdentifierInUse = 0x91
|
|
43
|
+
+ case receiveMaximumExceeded = 0x93
|
|
44
|
+
+ case topicAliasInvalid = 0x94
|
|
45
|
+
case packetTooLarge = 0x95
|
|
46
|
+
+ case messageRateTooHigh = 0x96
|
|
47
|
+
case quotaExceeded = 0x97
|
|
48
|
+
+ case administrativeAction = 0x98
|
|
49
|
+
case payloadFormatInvalid = 0x99
|
|
50
|
+
case retainNotSupported = 0x9A
|
|
51
|
+
case qosNotSupported = 0x9B
|
|
52
|
+
case useAnotherServer = 0x9C
|
|
53
|
+
case serverMoved = 0x9D
|
|
54
|
+
- case connectionRateExceeded = 0x9F
|
|
55
|
+
-
|
|
56
|
+
- // PUBACK, PUBREC, PUBREL, PUBCOMP Reason Codes
|
|
57
|
+
- case noMatchingSubscribers = 0x10
|
|
58
|
+
- case unspecifiedErrorPub = 0x80
|
|
59
|
+
- case implementationSpecificErrorPub = 0x83
|
|
60
|
+
- case notAuthorizedPub = 0x87
|
|
61
|
+
- case topicNameInvalidPub = 0x90
|
|
62
|
+
- case packetIdentifierInUse = 0x91
|
|
63
|
+
- case quotaExceededPub = 0x97
|
|
64
|
+
- case payloadFormatInvalidPub = 0x99
|
|
65
|
+
-
|
|
66
|
+
- // SUBACK Reason Codes
|
|
67
|
+
- case grantedQoS0 = 0x00
|
|
68
|
+
- case grantedQoS1 = 0x01
|
|
69
|
+
- case grantedQoS2 = 0x02
|
|
70
|
+
- case unspecifiedErrorSub = 0x80
|
|
71
|
+
- case implementationSpecificErrorSub = 0x83
|
|
72
|
+
- case notAuthorizedSub = 0x87
|
|
73
|
+
- case topicFilterInvalid = 0x8F
|
|
74
|
+
- case packetIdentifierInUseSub = 0x91
|
|
75
|
+
- case quotaExceededSub = 0x97
|
|
76
|
+
case sharedSubscriptionsNotSupported = 0x9E
|
|
77
|
+
+ case connectionRateExceeded = 0x9F
|
|
78
|
+
+ case maximumConnectTime = 0xA0
|
|
79
|
+
case subscriptionIdentifiersNotSupported = 0xA1
|
|
80
|
+
case wildcardSubscriptionsNotSupported = 0xA2
|
|
81
|
+
+}
|
|
82
|
+
|
|
83
|
+
- // UNSUBACK Reason Codes
|
|
84
|
+
- case successUnsub = 0x00
|
|
85
|
+
- case noSubscriptionExisted = 0x11
|
|
86
|
+
- case unspecifiedErrorUnsub = 0x80
|
|
87
|
+
- case implementationSpecificErrorUnsub = 0x83
|
|
88
|
+
- case notAuthorizedUnsub = 0x87
|
|
89
|
+
- case topicFilterInvalidUnsub = 0x8F
|
|
90
|
+
- case packetIdentifierInUseUnsub = 0x91
|
|
91
|
+
-
|
|
92
|
+
- // DISCONNECT Reason Codes
|
|
93
|
+
- case normalDisconnectionDisc = 0x00
|
|
94
|
+
- case disconnectWithWillMessageDisc = 0x04
|
|
95
|
+
- case unspecifiedErrorDisc = 0x80
|
|
96
|
+
- case malformedPacketDisc = 0x81
|
|
97
|
+
- case protocolErrorDisc = 0x82
|
|
98
|
+
- case implementationSpecificErrorDisc = 0x83
|
|
99
|
+
- case notAuthorizedDisc = 0x87
|
|
100
|
+
- case serverBusyDisc = 0x89
|
|
101
|
+
- case serverShuttingDown = 0x8B
|
|
102
|
+
- case badAuthenticationMethodDisc = 0x8C
|
|
103
|
+
- case keepAliveTimeout = 0x8D
|
|
104
|
+
- case sessionTakenOver = 0x8E
|
|
105
|
+
- case topicFilterInvalidDisc = 0x8F
|
|
106
|
+
- case topicNameInvalidDisc = 0x90
|
|
107
|
+
- case receiveMaximumExceeded = 0x93
|
|
108
|
+
- case topicAliasInvalid = 0x94
|
|
109
|
+
- case packetTooLargeDisc = 0x95
|
|
110
|
+
- case messageRateTooHigh = 0x96
|
|
111
|
+
- case quotaExceededDisc = 0x97
|
|
112
|
+
- case administrativeAction = 0x98
|
|
113
|
+
- case payloadFormatInvalidDisc = 0x99
|
|
114
|
+
- case retainNotSupportedDisc = 0x9A
|
|
115
|
+
- case qosNotSupportedDisc = 0x9B
|
|
116
|
+
- case useAnotherServerDisc = 0x9C
|
|
117
|
+
- case serverMovedDisc = 0x9D
|
|
118
|
+
- case sharedSubscriptionsNotSupportedDisc = 0x9E
|
|
119
|
+
- case connectionRateExceededDisc = 0x9F
|
|
120
|
+
- case maximumConnectTime = 0xA0
|
|
121
|
+
- case subscriptionIdentifiersNotSupportedDisc = 0xA1
|
|
122
|
+
- case wildcardSubscriptionsNotSupportedDisc = 0xA2
|
|
123
|
+
+// Aliases for context clarity (same raw values)
|
|
124
|
+
+extension MQTT5ReasonCode {
|
|
125
|
+
+ /// SUBACK granted QoS 0 (rawValue 0x00, same as success)
|
|
126
|
+
+ public static let grantedQoS0: MQTT5ReasonCode = .success
|
|
127
|
+
+ /// DISCONNECT normal disconnection (rawValue 0x00)
|
|
128
|
+
+ public static let normalDisconnectionDisc: MQTT5ReasonCode = .success
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Compatibility mapping for MQTT 3.1.1 return codes
|
|
@@ -11,6 +11,17 @@ import Capacitor
|
|
|
11
11
|
@objc(MqttQuicPlugin)
|
|
12
12
|
public class MqttQuicPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
13
13
|
|
|
14
|
+
public let identifier = "MqttQuicPlugin"
|
|
15
|
+
public let jsName = "MqttQuic"
|
|
16
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
17
|
+
CAPPluginMethod(name: "connect", returnType: CAPPluginReturnPromise),
|
|
18
|
+
CAPPluginMethod(name: "disconnect", returnType: CAPPluginReturnPromise),
|
|
19
|
+
CAPPluginMethod(name: "publish", returnType: CAPPluginReturnPromise),
|
|
20
|
+
CAPPluginMethod(name: "subscribe", returnType: CAPPluginReturnPromise),
|
|
21
|
+
CAPPluginMethod(name: "unsubscribe", returnType: CAPPluginReturnPromise),
|
|
22
|
+
CAPPluginMethod(name: "testHarness", returnType: CAPPluginReturnPromise)
|
|
23
|
+
]
|
|
24
|
+
|
|
14
25
|
private var client = MQTTClient(protocolVersion: .auto)
|
|
15
26
|
|
|
16
27
|
@objc override public func load() {}
|
|
@@ -46,6 +46,10 @@ public final class MockStreamBuffer {
|
|
|
46
46
|
return Data(out)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
public func appendWrite(_ data: Data) {
|
|
50
|
+
writeBuffer.append(data)
|
|
51
|
+
}
|
|
52
|
+
|
|
49
53
|
public func consumeWrite() -> Data {
|
|
50
54
|
let d = writeBuffer
|
|
51
55
|
writeBuffer = Data()
|
|
@@ -94,7 +98,7 @@ public final class MockStreamWriter: MQTTStreamWriterProtocol {
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
public func write(_ data: Data) async throws {
|
|
97
|
-
buffer.
|
|
101
|
+
buffer.appendWrite(data)
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
public func drain() async throws {}
|
package/ios/build-nghttp3.sh
CHANGED
|
@@ -23,7 +23,12 @@ if [ -z "$PROJECT_DIR" ] && [ -f "$SCRIPT_DIR/../package.json" ]; then
|
|
|
23
23
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
24
24
|
fi
|
|
25
25
|
if [ -n "$PROJECT_DIR" ]; then
|
|
26
|
-
|
|
26
|
+
if [ -d "$PROJECT_DIR/ref-code" ]; then
|
|
27
|
+
REF_CODE_DIR="$(cd "$PROJECT_DIR/ref-code" && pwd)"
|
|
28
|
+
else
|
|
29
|
+
# Plugin run from repo: use parent as ref-code (e.g. ref-code/capacitor-mqtt-quic -> ref-code)
|
|
30
|
+
REF_CODE_DIR="$(cd "$PROJECT_DIR/.." && pwd)"
|
|
31
|
+
fi
|
|
27
32
|
else
|
|
28
33
|
if [ -d "$SCRIPT_DIR/../ref-code" ]; then
|
|
29
34
|
REF_CODE_DIR="$(cd "$SCRIPT_DIR/../ref-code" && pwd)"
|
|
@@ -35,6 +40,10 @@ NGHTTP3_SOURCE_DIR="${NGHTTP3_SOURCE_DIR:-$REF_CODE_DIR/nghttp3}"
|
|
|
35
40
|
if [[ "$NGHTTP3_SOURCE_DIR" != /* ]]; then
|
|
36
41
|
NGHTTP3_SOURCE_DIR="$REF_CODE_DIR/$NGHTTP3_SOURCE_DIR"
|
|
37
42
|
fi
|
|
43
|
+
# If default path does not exist, try sibling ref-code/nghttp3 (e.g. when plugin has ref-code/ but nghttp3 lives in repo ref-code/)
|
|
44
|
+
if [ -n "$PROJECT_DIR" ] && [ ! -d "$NGHTTP3_SOURCE_DIR" ] && [ -d "$(cd "$PROJECT_DIR/.." && pwd)/nghttp3" ]; then
|
|
45
|
+
NGHTTP3_SOURCE_DIR="$(cd "$PROJECT_DIR/../nghttp3" && pwd)"
|
|
46
|
+
fi
|
|
38
47
|
ARCH="${ARCH:-arm64}"
|
|
39
48
|
SDK="${SDK:-iphoneos}"
|
|
40
49
|
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
|
@@ -100,8 +109,8 @@ if [ ! -d "$NGHTTP3_SOURCE_DIR" ]; then
|
|
|
100
109
|
exit 1
|
|
101
110
|
fi
|
|
102
111
|
|
|
103
|
-
# Ensure required
|
|
104
|
-
if [ ! -f "$NGHTTP3_SOURCE_DIR/sfparse/sfparse.c" ]
|
|
112
|
+
# Ensure required sources are present (sfparse: top-level or lib/sfparse)
|
|
113
|
+
if [ ! -f "$NGHTTP3_SOURCE_DIR/sfparse/sfparse.c" ] && [ ! -f "$NGHTTP3_SOURCE_DIR/lib/sfparse/sfparse.c" ]; then
|
|
105
114
|
if [ -d "$NGHTTP3_SOURCE_DIR/.git" ]; then
|
|
106
115
|
echo "Initializing nghttp3 submodules..."
|
|
107
116
|
(cd "$NGHTTP3_SOURCE_DIR" && git submodule update --init --recursive) || {
|
|
@@ -109,7 +118,7 @@ if [ ! -f "$NGHTTP3_SOURCE_DIR/sfparse/sfparse.c" ] || [ ! -f "$NGHTTP3_SOURCE_D
|
|
|
109
118
|
exit 1
|
|
110
119
|
}
|
|
111
120
|
else
|
|
112
|
-
echo "Error: nghttp3 submodules are missing (sfparse
|
|
121
|
+
echo "Error: nghttp3 submodules are missing (sfparse)"
|
|
113
122
|
echo "Please clone with submodules:"
|
|
114
123
|
echo " git clone --recurse-submodules https://github.com/ngtcp2/nghttp3.git $NGHTTP3_SOURCE_DIR"
|
|
115
124
|
echo "Or if already cloned:"
|
package/ios/build-ngtcp2.sh
CHANGED
|
@@ -36,6 +36,10 @@ NGTCP2_SOURCE_DIR="${NGTCP2_SOURCE_DIR:-$REF_CODE_DIR/ngtcp2}"
|
|
|
36
36
|
if [[ "$NGTCP2_SOURCE_DIR" != /* ]]; then
|
|
37
37
|
NGTCP2_SOURCE_DIR="$REF_CODE_DIR/$NGTCP2_SOURCE_DIR"
|
|
38
38
|
fi
|
|
39
|
+
# If default path does not exist, try sibling ref-code/ngtcp2 (e.g. when plugin has ref-code/ but ngtcp2 lives in repo ref-code/)
|
|
40
|
+
if [ -n "$PROJECT_DIR" ] && [ ! -d "$NGTCP2_SOURCE_DIR" ] && [ -d "$(cd "$PROJECT_DIR/.." && pwd)/ngtcp2" ]; then
|
|
41
|
+
NGTCP2_SOURCE_DIR="$(cd "$PROJECT_DIR/../ngtcp2" && pwd)"
|
|
42
|
+
fi
|
|
39
43
|
OPENSSL_PATH="${OPENSSL_PATH:-}"
|
|
40
44
|
USE_QUICTLS="${USE_QUICTLS:-0}"
|
|
41
45
|
ARCH="${ARCH:-arm64}"
|
|
@@ -111,8 +115,8 @@ if [ ! -d "$NGTCP2_SOURCE_DIR" ]; then
|
|
|
111
115
|
exit 1
|
|
112
116
|
fi
|
|
113
117
|
|
|
114
|
-
# Ensure required
|
|
115
|
-
if [ ! -f "$NGTCP2_SOURCE_DIR/munit/munit.c" ]; then
|
|
118
|
+
# Ensure required sources are present (munit: top-level or tests/munit)
|
|
119
|
+
if [ ! -f "$NGTCP2_SOURCE_DIR/munit/munit.c" ] && [ ! -f "$NGTCP2_SOURCE_DIR/tests/munit/munit.c" ]; then
|
|
116
120
|
if [ -d "$NGTCP2_SOURCE_DIR/.git" ]; then
|
|
117
121
|
echo "Initializing ngtcp2 submodules..."
|
|
118
122
|
(cd "$NGTCP2_SOURCE_DIR" && git submodule update --init --recursive) || {
|
package/ios/libs/libcrypto.a
CHANGED
|
Binary file
|
package/ios/libs/libnghttp3.a
CHANGED
|
Binary file
|
package/ios/libs/libngtcp2.a
CHANGED
|
Binary file
|
|
Binary file
|
package/ios/libs/libssl.a
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@annadata/capacitor-mqtt-quic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MQTT-over-QUIC client for Capacitor (iOS/Android). Uses ngtcp2 for QUIC; MQTT over WebSocket fallback on web.",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|