From 605cc26ae8e0be9590fe9bb39ac48c0150010e50 Mon Sep 17 00:00:00 2001 From: Steve Kim <86316075+sbSteveK@users.noreply.github.com> Date: Tue, 7 May 2024 09:15:10 -0700 Subject: [PATCH] Mqtt5 Init From Pointer (#262) --- .../mqtt/Mqtt5Client.swift | 176 ++++++------ .../mqtt/Mqtt5Options.swift | 101 ++----- .../mqtt/Mqtt5Packets.swift | 270 ++++++------------ 3 files changed, 202 insertions(+), 345 deletions(-) diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift index b67faedb..c590de62 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift @@ -278,111 +278,111 @@ public class Mqtt5Client { // MARK: - Internal/Private /// Handles lifecycle events from native Mqtt Client -internal func MqttClientLifeycyleEvents(_ lifecycleEvent: UnsafePointer?) { +internal func MqttClientHandleLifecycleEvent(_ lifecycleEvent: UnsafePointer?) { guard let lifecycleEvent: UnsafePointer = lifecycleEvent else { fatalError("MqttClientLifecycleEvents was called from native without an aws_mqtt5_client_lifecycle_event.") } - + let callbackCore = Unmanaged.fromOpaque(lifecycleEvent.pointee.user_data).takeUnretainedValue() let crtError = CRTError(code: lifecycleEvent.pointee.error_code) - if let userData = lifecycleEvent.pointee.user_data { - let callbackCore: MqttCallbackCore = Unmanaged.fromOpaque(userData).takeUnretainedValue() + // validate the callback flag, if flag is false, return + callbackCore.rwlock.read { + if callbackCore.callbackFlag == false { return } - // validate the callback flag, if flag is false, return - callbackCore.rwlock.read { - if callbackCore.callbackFlag == false { return } + switch lifecycleEvent.pointee.event_type { + case AWS_MQTT5_CLET_ATTEMPTING_CONNECT: - switch lifecycleEvent.pointee.event_type { - case AWS_MQTT5_CLET_ATTEMPTING_CONNECT: + let lifecycleAttemptingConnectData = LifecycleAttemptingConnectData() + callbackCore.onLifecycleEventAttemptingConnect(lifecycleAttemptingConnectData) - let lifecycleAttemptingConnectData = LifecycleAttemptingConnectData() - callbackCore.onLifecycleEventAttemptingConnect(lifecycleAttemptingConnectData) + case AWS_MQTT5_CLET_CONNECTION_SUCCESS: - case AWS_MQTT5_CLET_CONNECTION_SUCCESS: + guard let connackView = lifecycleEvent.pointee.connack_data else { + fatalError("ConnackPacket missing in a Connection Success lifecycle event.") + } + let connackPacket = ConnackPacket(connackView) - guard let connackPacket = ConnackPacket.convertFromNative(lifecycleEvent.pointee.connack_data) else { - fatalError("ConnackPacket missing in a Connection Success lifecycle event.") - } + guard let negotiatedSettings = lifecycleEvent.pointee.settings else { + fatalError("NegotiatedSettings missing in a Connection Success lifecycle event.") + } - guard let negotiatedSettings = NegotiatedSettings.convertFromNative(lifecycleEvent.pointee.settings) else { - fatalError("NegotiatedSettings missing in a Connection Success lifecycle event.") - } + let lifecycleConnectionSuccessData = LifecycleConnectionSuccessData( + connackPacket: connackPacket, + negotiatedSettings: NegotiatedSettings(negotiatedSettings)) + callbackCore.onLifecycleEventConnectionSuccess(lifecycleConnectionSuccessData) - let lifecycleConnectionSuccessData = LifecycleConnectionSuccessData( - connackPacket: connackPacket, - negotiatedSettings: negotiatedSettings) - callbackCore.onLifecycleEventConnectionSuccess(lifecycleConnectionSuccessData) + case AWS_MQTT5_CLET_CONNECTION_FAILURE: - case AWS_MQTT5_CLET_CONNECTION_FAILURE: + var connackPacket: ConnackPacket? + if let connackView = lifecycleEvent.pointee.connack_data { + connackPacket = ConnackPacket(connackView) + } - let connackPacket = ConnackPacket.convertFromNative(lifecycleEvent.pointee.connack_data) + let lifecycleConnectionFailureData = LifecycleConnectionFailureData( + crtError: crtError, + connackPacket: connackPacket) + callbackCore.onLifecycleEventConnectionFailure(lifecycleConnectionFailureData) - let lifecycleConnectionFailureData = LifecycleConnectionFailureData( - crtError: crtError, - connackPacket: connackPacket) - callbackCore.onLifecycleEventConnectionFailure(lifecycleConnectionFailureData) + case AWS_MQTT5_CLET_DISCONNECTION: - case AWS_MQTT5_CLET_DISCONNECTION: + var disconnectPacket: DisconnectPacket? - guard let disconnectPacket = DisconnectPacket.convertFromNative(lifecycleEvent.pointee.disconnect_data) else { - let lifecycleDisconnectData = LifecycleDisconnectData(crtError: crtError) - callbackCore.onLifecycleEventDisconnection(lifecycleDisconnectData) - return - } + if let disconnectView: UnsafePointer = lifecycleEvent.pointee.disconnect_data { + disconnectPacket = DisconnectPacket(disconnectView) + } - let lifecycleDisconnectData = LifecycleDisconnectData( - crtError: crtError, - disconnectPacket: disconnectPacket) - callbackCore.onLifecycleEventDisconnection(lifecycleDisconnectData) + let lifecycleDisconnectData = LifecycleDisconnectData( + crtError: crtError, + disconnectPacket: disconnectPacket) + callbackCore.onLifecycleEventDisconnection(lifecycleDisconnectData) - case AWS_MQTT5_CLET_STOPPED: + case AWS_MQTT5_CLET_STOPPED: - callbackCore.onLifecycleEventStoppedCallback(LifecycleStoppedData()) + callbackCore.onLifecycleEventStoppedCallback(LifecycleStoppedData()) - default: - fatalError("A lifecycle event with an invalid event type was encountered.") - } + default: + fatalError("A lifecycle event with an invalid event type was encountered.") } - } } -internal func MqttClientPublishRecievedEvents( - _ publishPacketView: UnsafePointer?, - _ userData: UnsafeMutableRawPointer?) { - let callbackCore = Unmanaged.fromOpaque(userData!).takeUnretainedValue() +internal func MqttClientHandlePublishRecieved( + _ publish: UnsafePointer?, + _ user_data: UnsafeMutableRawPointer?) { + let callbackCore = Unmanaged.fromOpaque(user_data!).takeUnretainedValue() // validate the callback flag, if flag is false, return callbackCore.rwlock.read { if callbackCore.callbackFlag == false { return } - - guard let publish_packet = PublishPacket.convertFromNative(publishPacketView) else { - fatalError("NegotiatedSettings missing in a Connection Success lifecycle event.") + if let publish { + let publishPacket = PublishPacket(publish) + let publishReceivedData = PublishReceivedData(publishPacket: publishPacket) + callbackCore.onPublishReceivedCallback(publishReceivedData) + } else { + fatalError("MqttClientHandlePublishRecieved called with null publish") } - let puback = PublishReceivedData(publishPacket: publish_packet) - callbackCore.onPublishReceivedCallback(puback) } } internal func MqttClientWebsocketTransform( - _ rawHttpMessage: OpaquePointer?, - _ userData: UnsafeMutableRawPointer?, - _ completeFn: (@convention(c) (OpaquePointer?, Int32, UnsafeMutableRawPointer?) -> Void)?, - _ completeCtx: UnsafeMutableRawPointer?) { + _ request: OpaquePointer?, + _ user_data: UnsafeMutableRawPointer?, + _ complete_fn: (@convention(c) (OpaquePointer?, Int32, UnsafeMutableRawPointer?) -> Void)?, + _ complete_ctx: UnsafeMutableRawPointer?) { - let callbackCore = Unmanaged.fromOpaque(userData!).takeUnretainedValue() + let callbackCore = Unmanaged.fromOpaque(user_data!).takeUnretainedValue() // validate the callback flag, if flag is false, return callbackCore.rwlock.read { if callbackCore.callbackFlag == false { return } - guard let rawHttpMessage else { + guard let request else { fatalError("Null HttpRequeset in websocket transform function.") } - let httpRequest = HTTPRequest(nativeHttpMessage: rawHttpMessage) + let httpRequest = HTTPRequest(nativeHttpMessage: request) @Sendable func signerTransform(request: HTTPRequestBase, errorCode: Int32) { - completeFn?(request.rawValue, errorCode, completeCtx) + complete_fn?(request.rawValue, errorCode, complete_ctx) } if callbackCore.onWebsocketInterceptor != nil { @@ -399,44 +399,46 @@ internal func MqttClientTerminationCallback(_ userData: UnsafeMutableRawPointer? } /// The completion callback to invoke when subscribe operation completes in native -private func subscribeCompletionCallback(subackPacket: UnsafePointer?, - errorCode: Int32, - userData: UnsafeMutableRawPointer?) { - let continuationCore = Unmanaged>.fromOpaque(userData!).takeRetainedValue() +private func subscribeCompletionCallback(suback: UnsafePointer?, + error_code: Int32, + complete_ctx: UnsafeMutableRawPointer?) { + let continuationCore = Unmanaged>.fromOpaque(complete_ctx!).takeRetainedValue() - guard errorCode == AWS_OP_SUCCESS else { - return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: errorCode))) + guard error_code == AWS_OP_SUCCESS else { + return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: error_code))) } - guard let suback = SubackPacket.convertFromNative(subackPacket) else { + if let suback { + continuationCore.continuation.resume(returning: SubackPacket(suback)) + } else { fatalError("Suback missing in the subscription completion callback.") } - - continuationCore.continuation.resume(returning: suback) } /// The completion callback to invoke when publish operation completes in native private func publishCompletionCallback(packet_type: aws_mqtt5_packet_type, - navtivePublishResult: UnsafeRawPointer?, - errorCode: Int32, - userData: UnsafeMutableRawPointer?) { - let continuationCore = Unmanaged>.fromOpaque(userData!).takeRetainedValue() + packet: UnsafeRawPointer?, + error_code: Int32, + complete_ctx: UnsafeMutableRawPointer?) { + let continuationCore = Unmanaged>.fromOpaque(complete_ctx!).takeRetainedValue() - if errorCode != AWS_OP_SUCCESS { - return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: errorCode))) + if error_code != AWS_OP_SUCCESS { + return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: error_code))) } switch packet_type { case AWS_MQTT5_PT_NONE: // QoS0 return continuationCore.continuation.resume(returning: PublishResult()) + case AWS_MQTT5_PT_PUBACK: // QoS1 - guard let puback = navtivePublishResult?.assumingMemoryBound( + guard let puback = packet?.assumingMemoryBound( to: aws_mqtt5_packet_puback_view.self) else { return continuationCore.continuation.resume( throwing: CommonRunTimeError.crtError(CRTError.makeFromLastError())) } - let publishResult = PublishResult(puback: PubackPacket.convertFromNative(puback)) + let publishResult = PublishResult(puback: PubackPacket(puback)) return continuationCore.continuation.resume(returning: publishResult) + default: return continuationCore.continuation.resume( throwing: CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_UNKNOWN.rawValue))) @@ -444,20 +446,20 @@ private func publishCompletionCallback(packet_type: aws_mqtt5_packet_type, } /// The completion callback to invoke when unsubscribe operation completes in native -private func unsubscribeCompletionCallback(unsubackPacket: UnsafePointer?, - errorCode: Int32, - userData: UnsafeMutableRawPointer?) { - let continuationCore = Unmanaged>.fromOpaque(userData!).takeRetainedValue() +private func unsubscribeCompletionCallback(unsuback: UnsafePointer?, + error_code: Int32, + complete_ctx: UnsafeMutableRawPointer?) { + let continuationCore = Unmanaged>.fromOpaque(complete_ctx!).takeRetainedValue() - guard errorCode == AWS_OP_SUCCESS else { - return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: errorCode))) + guard error_code == AWS_OP_SUCCESS else { + return continuationCore.continuation.resume(throwing: CommonRunTimeError.crtError(CRTError(code: error_code))) } - guard let unsuback = UnsubackPacket.convertFromNative(unsubackPacket) else { + if let unsuback { + continuationCore.continuation.resume(returning: UnsubackPacket(unsuback)) + } else { fatalError("Unsuback missing in the Unsubscribe completion callback.") } - - continuationCore.continuation.resume(returning: unsuback) } /// When the native client calls swift callbacks they are processed through the MqttCallbackCore diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift index ae080f80..0f89ae1a 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift @@ -147,9 +147,12 @@ public class MqttConnectOptions: CStruct { _requestProblemInformation, _willDelayIntervalSec, self.receiveMaximum, - self.maximumPacketSize) { (sessionExpiryIntervalSecPointer, requestResponseInformationPointer, - requestProblemInformationPointer, willDelayIntervalSecPointer, - receiveMaximumPointer, maximumPacketSizePointer) in + self.maximumPacketSize) { sessionExpiryIntervalSecPointer, + requestResponseInformationPointer, + requestProblemInformationPointer, + willDelayIntervalSecPointer, + receiveMaximumPointer, + maximumPacketSizePointer in raw_connect_options.session_expiry_interval_seconds = sessionExpiryIntervalSecPointer raw_connect_options.request_response_information = requestResponseInformationPointer @@ -434,9 +437,11 @@ public class MqttClientOptions: CStructWithUserData { tls_options, self.httpProxyOptions, self.topicAliasingOptions, - connnectOptions) { (socketOptionsCPointer, tlsOptionsCPointer, - httpProxyOptionsCPointer, topicAliasingOptionsCPointer, - connectOptionsCPointer) in + connnectOptions) { socketOptionsCPointer, + tlsOptionsCPointer, + httpProxyOptionsCPointer, + topicAliasingOptionsCPointer, + connectOptionsCPointer in raw_options.socket_options = socketOptionsCPointer raw_options.tls_options = tlsOptionsCPointer @@ -457,9 +462,9 @@ public class MqttClientOptions: CStructWithUserData { raw_options.websocket_handshake_transform_user_data = _userData } - raw_options.lifecycle_event_handler = MqttClientLifeycyleEvents + raw_options.lifecycle_event_handler = MqttClientHandleLifecycleEvent raw_options.lifecycle_event_handler_user_data = _userData - raw_options.publish_received_handler = MqttClientPublishRecievedEvents + raw_options.publish_received_handler = MqttClientHandlePublishRecieved raw_options.publish_received_handler_user_data = _userData raw_options.client_termination_handler = MqttClientTerminationCallback raw_options.client_termination_handler_user_data = _userData @@ -519,70 +524,20 @@ public class NegotiatedSettings { /// The final client id in use by the newly-established connection. This will be the configured client id if one was given in the configuration, otherwise, if no client id was specified, this will be the client id assigned by the server. Reconnection attempts will always use the auto-assigned client id, allowing for auto-assigned session resumption. public let clientId: String - public init (maximumQos: QoS, - sessionExpiryInterval: TimeInterval, - receiveMaximumFromServer: UInt16, - maximumPacketSizeToServer: UInt32, - topicAliasMaximumToServer: UInt16, - topicAliasMaximumToClient: UInt16, - serverKeepAlive: TimeInterval, - retainAvailable: Bool, - wildcardSubscriptionsAvailable: Bool, - subscriptionIdentifiersAvailable: Bool, - sharedSubscriptionsAvailable: Bool, - rejoinedSession: Bool, - clientId: String) { - self.maximumQos = maximumQos - self.sessionExpiryInterval = sessionExpiryInterval - self.receiveMaximumFromServer = receiveMaximumFromServer - self.maximumPacketSizeToServer = maximumPacketSizeToServer - self.topicAliasMaximumToServer = topicAliasMaximumToServer - self.topicAliasMaximumToClient = topicAliasMaximumToClient - self.serverKeepAlive = serverKeepAlive - self.retainAvailable = retainAvailable - self.wildcardSubscriptionsAvailable = wildcardSubscriptionsAvailable - self.subscriptionIdentifiersAvailable = subscriptionIdentifiersAvailable - self.sharedSubscriptionsAvailable = sharedSubscriptionsAvailable - self.rejoinedSession = rejoinedSession - self.clientId = clientId - } - - static func convertFromNative(_ from: UnsafePointer?) -> NegotiatedSettings? { - - guard let from else { - return nil - } - - let _negotiatedSettings = from.pointee - let negotiatedMaximumQos = QoS(_negotiatedSettings.maximum_qos) - let negotiatedSessionExpiryInterval: TimeInterval = TimeInterval(_negotiatedSettings.session_expiry_interval) - let negotiatedReceiveMaximumFromServer = _negotiatedSettings.receive_maximum_from_server - let negotiatedMaximumPacketSizeToServer = _negotiatedSettings.maximum_packet_size_to_server - let negotiatedTopicAliasMaximumToServer = _negotiatedSettings.topic_alias_maximum_to_server - let negotiatedTopicAliasMaximumToClient = _negotiatedSettings.topic_alias_maximum_to_client - let negotiatedServerKeepAlive: TimeInterval = TimeInterval(_negotiatedSettings.server_keep_alive) - let negotiatedRetainAvailable = _negotiatedSettings.retain_available - let negotiatedWildcardSubscriptionsAvailable = _negotiatedSettings.wildcard_subscriptions_available - let negotiatedSubscriptionIdentifiersAvailable = _negotiatedSettings.subscription_identifiers_available - let negotiatedSharedSubscriptionsAvailable = _negotiatedSettings.shared_subscriptions_available - let negotiatedRejoinedSession = _negotiatedSettings.rejoined_session - let negotiatedClientId = _negotiatedSettings.client_id_storage.toString() - - let negotiatedSettings = NegotiatedSettings( - maximumQos: negotiatedMaximumQos, - sessionExpiryInterval: negotiatedSessionExpiryInterval, - receiveMaximumFromServer: negotiatedReceiveMaximumFromServer, - maximumPacketSizeToServer: negotiatedMaximumPacketSizeToServer, - topicAliasMaximumToServer: negotiatedTopicAliasMaximumToServer, - topicAliasMaximumToClient: negotiatedTopicAliasMaximumToClient, - serverKeepAlive: negotiatedServerKeepAlive, - retainAvailable: negotiatedRetainAvailable, - wildcardSubscriptionsAvailable: negotiatedWildcardSubscriptionsAvailable, - subscriptionIdentifiersAvailable: negotiatedSubscriptionIdentifiersAvailable, - sharedSubscriptionsAvailable: negotiatedSharedSubscriptionsAvailable, - rejoinedSession: negotiatedRejoinedSession, - clientId: negotiatedClientId) - - return negotiatedSettings + internal init(_ settings: UnsafePointer){ + let negotiatedSettings = settings.pointee + self.maximumQos = QoS(negotiatedSettings.maximum_qos) + self.sessionExpiryInterval = TimeInterval(negotiatedSettings.session_expiry_interval) + self.receiveMaximumFromServer = negotiatedSettings.receive_maximum_from_server + self.maximumPacketSizeToServer = negotiatedSettings.maximum_packet_size_to_server + self.topicAliasMaximumToServer = negotiatedSettings.topic_alias_maximum_to_server + self.topicAliasMaximumToClient = negotiatedSettings.topic_alias_maximum_to_client + self.serverKeepAlive = TimeInterval(negotiatedSettings.server_keep_alive) + self.retainAvailable = negotiatedSettings.retain_available + self.wildcardSubscriptionsAvailable = negotiatedSettings.wildcard_subscriptions_available + self.subscriptionIdentifiersAvailable = negotiatedSettings.subscription_identifiers_available + self.sharedSubscriptionsAvailable = negotiatedSettings.shared_subscriptions_available + self.rejoinedSession = negotiatedSettings.rejoined_session + self.clientId = negotiatedSettings.client_id_storage.toString() } } diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift index 5c0e4461..a746bd20 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift @@ -168,10 +168,35 @@ public class PublishPacket: CStruct { self.userProperties = userProperties } + internal init(_ publish_view: UnsafePointer) { + let publishView = publish_view.pointee + self.qos = QoS(publishView.qos) + self.topic = publishView.topic.toString() + self.payload = Data(bytes: publishView.payload.ptr, count: publishView.payload.len) + self.retain = publishView.retain + self.payloadFormatIndicator = publishView.payload_format != nil ? + PayloadFormatIndicator(publishView.payload_format.pointee) : nil + self.messageExpiryInterval = convertOptionalUInt32(publishView.message_expiry_interval_seconds).map { TimeInterval($0) } + self.topicAlias = convertOptionalUInt16(publishView.topic_alias) + self.responseTopic = convertAwsByteCursorToOptionalString(publishView.response_topic) + self.correlationData = publishView.correlation_data != nil ? + Data(bytes: publishView.correlation_data!.pointee.ptr, count: publishView.correlation_data!.pointee.len) : nil + var identifier: [UInt32]? = [] + for i in 0.. String? { - if let data = payload { - return String(data: data, encoding: .utf8) ?? nil + if let payload{ + return String(data: payload, encoding: .utf8) ?? nil } return nil } @@ -239,50 +264,6 @@ public class PublishPacket: CStruct { } } } - - static func convertFromNative(_ from: UnsafePointer?) -> PublishPacket? { - guard let from else { - return nil - } - let publishView = from.pointee - - let qos = QoS(publishView.qos) - let payload = Data(bytes: publishView.payload.ptr, count: publishView.payload.len) - - let payloadFormatIndicator: PayloadFormatIndicator? = publishView.payload_format != nil ? - PayloadFormatIndicator(publishView.payload_format.pointee) : nil - - let messageExpiryInterval = convertOptionalUInt32(publishView.message_expiry_interval_seconds) - let messageExpiryIntervalTimeInterval: TimeInterval? = messageExpiryInterval.map { TimeInterval($0) } - - let correlationDataPointer: Data? = publishView.correlation_data != nil ? - Data(bytes: publishView.correlation_data!.pointee.ptr, count: publishView.correlation_data!.pointee.len) : nil - - var identifier: [UInt32]? = [] - for i in 0..?) -> PubackPacket? { - guard let from = from else { - return nil - } - let pubackPointer = from.pointee - - guard let reasonCode = PubackReasonCode(rawValue: Int(pubackPointer.reason_code.rawValue)) - else {fatalError("SubackPacket from native has an invalid reason code.")} - - let reasonString = pubackPointer.reason_string?.pointee.toString() - - let userProperties = convertOptionalUserProperties( - count: pubackPointer.user_property_count, - userPropertiesPointer: pubackPointer.user_properties) - - return PubackPacket(reasonCode: reasonCode, reasonString: reasonString, userProperties: userProperties) + internal init(_ puback_view: UnsafePointer) { + let pubackView = puback_view.pointee + self.reasonCode = PubackReasonCode(rawValue: Int(pubackView.reason_code.rawValue))! + self.reasonString = pubackView.reason_string?.pointee.toString() + self.userProperties = convertOptionalUserProperties( + count: pubackView.user_property_count, + userPropertiesPointer: pubackView.user_properties) } } @@ -514,35 +486,15 @@ public class SubackPacket { self.userProperties = userProperties } - public static func convertFromNative(_ from: UnsafePointer?) -> SubackPacket? { - - guard let from else { - return nil - } - - let subackPointer = from.pointee - - var subackReasonCodes: [SubackReasonCode] = [] - for i in 0..) { + let subackView = suback_view.pointee + let reasonCodeBuffer = UnsafeBufferPointer(start: subackView.reason_codes, count: subackView.reason_code_count) + self.reasonCodes = reasonCodeBuffer.compactMap { SubackReasonCode(rawValue: Int($0.rawValue)) } + self.reasonString = subackView.reason_string?.pointee.toString() + self.userProperties = convertOptionalUserProperties( + count: subackView.user_property_count, + userPropertiesPointer: subackView.user_properties) } - } /// Data model of an `MQTT5 UNSUBSCRIBE `_ packet. @@ -630,23 +582,14 @@ public class UnsubackPacket { self.userProperties = userProperties } - public static func convertFromNative(_ from: UnsafePointer?) -> UnsubackPacket? { - if let _from = from { - let unsubackPointer = _from.pointee - - let reasonCodeBuffer = UnsafeBufferPointer(start: unsubackPointer.reason_codes, count: unsubackPointer.reason_code_count) - let unsubackReasonCodes = reasonCodeBuffer.compactMap { UnsubackReasonCode(rawValue: Int($0.rawValue)) } - let reasonString = unsubackPointer.reason_string?.pointee.toString() - let userProperties = convertOptionalUserProperties( - count: unsubackPointer.user_property_count, - userPropertiesPointer: unsubackPointer.user_properties) - let unsuback = UnsubackPacket(reasonCodes: unsubackReasonCodes, - reasonString: reasonString, - userProperties: userProperties) - return unsuback - } - - return nil + internal init(_ unsuback_view: UnsafePointer){ + let unsubackView = unsuback_view.pointee + let reasonCodeBuffer = UnsafeBufferPointer(start: unsubackView.reason_codes, count: unsubackView.reason_code_count) + self.reasonCodes = reasonCodeBuffer.compactMap { UnsubackReasonCode(rawValue: Int($0.rawValue)) } + self.reasonString = unsubackView.reason_string?.pointee.toString() + self.userProperties = convertOptionalUserProperties( + count: unsubackView.user_property_count, + userPropertiesPointer: unsubackView.user_properties) } } @@ -678,7 +621,20 @@ public class DisconnectPacket: CStruct { self.reasonString = reasonString self.serverReference = serverReference self.userProperties = userProperties - } + } + + internal init(_ disconnect_view: UnsafePointer){ + let disconnectView = disconnect_view.pointee + + self.reasonCode = DisconnectReasonCode(rawValue: Int(disconnectView.reason_code.rawValue))! + self.sessionExpiryInterval = convertOptionalUInt32(disconnectView.session_expiry_interval_seconds).map { TimeInterval($0) } + self.reasonString = convertAwsByteCursorToOptionalString(disconnectView.reason_string) + self.serverReference = convertAwsByteCursorToOptionalString(disconnectView.reason_string) + self.userProperties = convertOptionalUserProperties( + count: disconnectView.user_property_count, + userPropertiesPointer: disconnectView.user_properties) + } + func validateConversionToNative() throws { if let sessionExpiryInterval { if sessionExpiryInterval < 0 || sessionExpiryInterval > Double(UInt32.max) { @@ -719,34 +675,6 @@ public class DisconnectPacket: CStruct { } } } - - static func convertFromNative(_ from: UnsafePointer?) -> DisconnectPacket? { - guard let from else { - return nil - } - let disconnectView = from.pointee - guard let reasonCode = DisconnectReasonCode(rawValue: Int(disconnectView.reason_code.rawValue)) else { - fatalError("aws_mqtt5_packet_disconnect_view from native missing a reason code.") - } - - let sessionExpiryInterval = convertOptionalUInt32(disconnectView.session_expiry_interval_seconds) - let sessionExpiryIntervalSeconds: TimeInterval? = sessionExpiryInterval.map { TimeInterval($0) } - let reasonString = convertAwsByteCursorToOptionalString(disconnectView.reason_string) - let serverReference = convertAwsByteCursorToOptionalString(disconnectView.reason_string) - let userProperties = convertOptionalUserProperties( - count: disconnectView.user_property_count, - userPropertiesPointer: disconnectView.user_properties) - - let disconnectPacket = DisconnectPacket( - reasonCode: reasonCode, - sessionExpiryInterval: sessionExpiryIntervalSeconds, - reasonString: reasonString, - serverReference: serverReference, - userProperties: userProperties - ) - return disconnectPacket - - } } /// Data model of an `MQTT5 CONNACK `_ packet. @@ -840,59 +768,31 @@ public class ConnackPacket { self.serverReference = serverReference } - static func convertFromNative(_ from: UnsafePointer?) -> ConnackPacket? { - guard let from else { - return nil - } - let connackView = from.pointee - - let sessionPresent = connackView.session_present - guard let reasonCode = ConnectReasonCode(rawValue: Int(connackView.reason_code.rawValue)) else { - fatalError("aws_mqtt5_packet_connack_view from native missing a reason code.") - } - let sessionExpiryInterval = (connackView.session_expiry_interval?.pointee).map { TimeInterval($0) } - let receiveMaximum = convertOptionalUInt16(connackView.receive_maximum) + internal init(_ connack_view: UnsafePointer){ + let connackView = connack_view.pointee - var maximumQos: QoS? + self.sessionPresent = connackView.session_present + self.reasonCode = ConnectReasonCode(rawValue: Int(connackView.reason_code.rawValue))! + self.sessionExpiryInterval = (connackView.session_expiry_interval?.pointee).map { TimeInterval($0) } + self.receiveMaximum = convertOptionalUInt16(connackView.receive_maximum) if let maximumQosValue = connackView.maximum_qos { - maximumQos = QoS(maximumQosValue.pointee) + self.maximumQos = QoS(maximumQosValue.pointee) + } else { + self.maximumQos = nil } - - let retainAvailable = convertOptionalBool(connackView.retain_available) - let maximumPacketSize = convertOptionalUInt32(connackView.maximum_packet_size) - let assignedClientIdentifier = convertAwsByteCursorToOptionalString(connackView.assigned_client_identifier) - let topicAliasMaximum = convertOptionalUInt16(connackView.topic_alias_maximum) - let reasonString = convertAwsByteCursorToOptionalString(connackView.reason_string) - let wildcardSubscriptionsAvailable = convertOptionalBool(connackView.wildcard_subscriptions_available) - let subscriptionIdentifiersAvailable = convertOptionalBool(connackView.subscription_identifiers_available) - let sharedSubscriptionAvailable = convertOptionalBool(connackView.shared_subscriptions_available) - let serverKeepAlive = convertOptionalUInt16(connackView.server_keep_alive) - let serverKeepAliveInSeconds: TimeInterval? = serverKeepAlive.map { TimeInterval($0) } - let responseInformation = convertAwsByteCursorToOptionalString(connackView.response_information) - let serverReference = convertAwsByteCursorToOptionalString(connackView.server_reference) - let userProperties = convertOptionalUserProperties( + self.retainAvailable = convertOptionalBool(connackView.retain_available) + self.maximumPacketSize = convertOptionalUInt32(connackView.maximum_packet_size) + self.assignedClientIdentifier = convertAwsByteCursorToOptionalString(connackView.assigned_client_identifier) + self.topicAliasMaximum = convertOptionalUInt16(connackView.topic_alias_maximum) + self.reasonString = convertAwsByteCursorToOptionalString(connackView.reason_string) + self.wildcardSubscriptionsAvailable = convertOptionalBool(connackView.wildcard_subscriptions_available) + self.subscriptionIdentifiersAvailable = convertOptionalBool(connackView.subscription_identifiers_available) + self.sharedSubscriptionAvailable = convertOptionalBool(connackView.shared_subscriptions_available) + self.serverKeepAlive = convertOptionalUInt16(connackView.server_keep_alive).map { TimeInterval($0) } + self.responseInformation = convertAwsByteCursorToOptionalString(connackView.response_information) + self.serverReference = convertAwsByteCursorToOptionalString(connackView.server_reference) + self.userProperties = convertOptionalUserProperties( count: connackView.user_property_count, userPropertiesPointer: connackView.user_properties) - - let connackPacket = ConnackPacket( - sessionPresent: sessionPresent, - reasonCode: reasonCode, - sessionExpiryInterval: sessionExpiryInterval, - receiveMaximum: receiveMaximum, - maximumQos: maximumQos, - retainAvailable: retainAvailable, - maximumPacketSize: maximumPacketSize, - assignedClientIdentifier: assignedClientIdentifier, - topicAliasMaximum: topicAliasMaximum, - reasonString: reasonString, - userProperties: userProperties, - wildcardSubscriptionsAvailable: wildcardSubscriptionsAvailable, - subscriptionIdentifiersAvailable: subscriptionIdentifiersAvailable, - sharedSubscriptionAvailable: sharedSubscriptionAvailable, - serverKeepAlive: serverKeepAliveInSeconds, - responseInformation: responseInformation, - serverReference: serverReference) - - return connackPacket } }