diff --git a/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift b/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift index 2441ebc9..604cb01f 100644 --- a/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift +++ b/Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift @@ -22,6 +22,20 @@ public struct CRTError: Equatable { self.message = String(cString: aws_error_str(self.code)) self.name = String(cString: aws_error_name(self.code)) } + + public init(code: T, context: String?) { + if code > INT32_MAX || code <= 0 { + self.code = Int32(AWS_ERROR_UNKNOWN.rawValue) + } else { + self.code = Int32(code) + } + var message = String(cString: aws_error_str(self.code)) + if let context { + message += ": " + context + } + self.message = message + self.name = String(cString: aws_error_name(self.code)) + } public static func makeFromLastError() -> CRTError { return CRTError(code: aws_last_error()) diff --git a/Source/AwsCommonRuntimeKit/crt/Utilities.swift b/Source/AwsCommonRuntimeKit/crt/Utilities.swift index 28201a9e..e9cb973b 100644 --- a/Source/AwsCommonRuntimeKit/crt/Utilities.swift +++ b/Source/AwsCommonRuntimeKit/crt/Utilities.swift @@ -231,14 +231,6 @@ extension Optional { } return validPointer.pointee } - - /// convert UnsafePointer to optional String - func toString() -> String? where Wrapped == (UnsafePointer) { - guard let validPointer = self?.pointee else { - return nil - } - return validPointer.toString() - } } extension Bool { diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift index 78e464fd..77cb62e5 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift @@ -142,7 +142,7 @@ public class Mqtt5Client { internal var callbackFlag = true /// Creates a Mqtt5Client instance using the provided Mqtt5ClientOptions. Once the Mqtt5Client is created, - /// changing the settings will not cause a change in already created Mqtt5Client's. + /// changing the settings will not cause a change in already created Mqtt5Client's. /// Once created, it is MANDATORY to call `close()` to clean up the Mqtt5Client resource /// /// - Parameters: @@ -179,15 +179,10 @@ public class Mqtt5Client { /// - Throws: CommonRuntimeError.crtError public func start() throws { try self.rwlock.read { - // validate the client in case close() is called. - guard let rawValue = self.rawValue else { - // TODO add new error type for client closed - throw CommonRunTimeError.crtError(CRTError.makeFromLastError()) - } let errorCode = aws_mqtt5_client_start(rawValue) if errorCode != AWS_OP_SUCCESS { - throw CommonRunTimeError.crtError(CRTError(code: errorCode)) + throw CommonRunTimeError.crtError(CRTError.makeFromLastError()) } } } @@ -202,11 +197,6 @@ public class Mqtt5Client { /// - Throws: CommonRuntimeError.crtError public func stop(disconnectPacket: DisconnectPacket? = nil) throws { try self.rwlock.read { - // validate the client in case close() is called. - guard let rawValue = self.rawValue else { - throw CommonRunTimeError.crtError(CRTError.makeFromLastError()) - } - var errorCode: Int32 = 0 if let disconnectPacket { @@ -242,11 +232,6 @@ public class Mqtt5Client { callbackOptions.completion_callback = subscribeCompletionCallback callbackOptions.completion_user_data = continuationCore.passRetained() self.rwlock.read { - // validate the client in case close() is called. - guard let rawValue = self.rawValue else { - continuationCore.release() - return continuation.resume(throwing: CommonRunTimeError.crtError(CRTError.makeFromLastError())) - } let result = aws_mqtt5_client_subscribe(rawValue, subscribePacketPointer, &callbackOptions) guard result == AWS_OP_SUCCESS else { continuationCore.release() @@ -279,12 +264,6 @@ public class Mqtt5Client { callbackOptions.completion_user_data = continuationCore.passRetained() self.rwlock.read { - // validate the client in case close() is called. - guard let rawValue = self.rawValue else { - continuationCore.release() - return continuation.resume(throwing: CommonRunTimeError.crtError(CRTError.makeFromLastError())) - } - let result = aws_mqtt5_client_publish(rawValue, publishPacketPointer, &callbackOptions) if result != AWS_OP_SUCCESS { continuationCore.release() @@ -314,11 +293,6 @@ public class Mqtt5Client { callbackOptions.completion_callback = unsubscribeCompletionCallback callbackOptions.completion_user_data = continuationCore.passRetained() self.rwlock.read { - // validate the client in case close() is called. - guard let rawValue = self.rawValue else { - continuationCore.release() - return continuation.resume(throwing: CommonRunTimeError.crtError(CRTError.makeFromLastError())) - } let result = aws_mqtt5_client_unsubscribe(rawValue, unsubscribePacketPointer, &callbackOptions) guard result == AWS_OP_SUCCESS else { continuationCore.release() diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Enums.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Enums.swift index 4268831c..ddecb5be 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Enums.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Enums.swift @@ -3,11 +3,6 @@ import AwsCMqtt -// TODO this is temporary. We will replace this with aws-crt-swift error codes. -enum MqttError: Error { - case validation(message: String) -} - /// MQTT message delivery quality of service. /// Enum values match `MQTT5 spec `__ encoding values. public enum QoS { diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift index 0a09271c..0f6aecc9 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift @@ -110,20 +110,23 @@ public class MqttConnectOptions: CStruct { func validateConversionToNative() throws { if let keepAliveInterval { if keepAliveInterval < 0 || keepAliveInterval > Double(UInt16.max) { - throw MqttError.validation(message: "Invalid keepAliveInterval value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid keepAliveInterval value")) } } do { _ = try sessionExpiryInterval?.secondUInt32() } catch { - throw MqttError.validation(message: "Invalid sessionExpiryInterval value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid sessionExpiryInterval value")) } do { _ = try willDelayInterval?.secondUInt32() } catch { - throw MqttError.validation(message: "Invalid willDelayInterval value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid willDelayInterval value")) } } @@ -339,36 +342,42 @@ public class MqttClientOptions: CStructWithUserData { do { _ = try minReconnectDelay?.millisecondUInt64() } catch { - throw MqttError.validation(message: "Invalid minReconnectDelay value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid minReconnectDelay value")) } do { _ = try maxReconnectDelay?.millisecondUInt64() } catch { - throw MqttError.validation(message: "Invalid maxReconnectDelay value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid maxReconnectDelay value")) } do { _ = try minConnectedTimeToResetReconnectDelay?.millisecondUInt64() } catch { - throw MqttError.validation(message: "Invalid minConnectedTimeToResetReconnectDelay value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid minConnectedTimeToResetReconnectDelay value")) } do { _ = try pingTimeout?.millisecondUInt32() } catch { - throw MqttError.validation(message: "Invalid pingTimeout value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid pingTimeout value")) } do { _ = try connackTimeout?.millisecondUInt32() } catch { - throw MqttError.validation(message: "Invalid connackTimeout value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid connackTimeout value")) } if let ackTimeout { if ackTimeout < 0 || ackTimeout > Double(UInt32.max) { - throw MqttError.validation(message: "Invalid ackTimeout value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid ackTimeout value")) } } } diff --git a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift index e1681aee..b5ef772a 100644 --- a/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift +++ b/Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift @@ -178,7 +178,7 @@ public class PublishPacket: CStruct { PayloadFormatIndicator(publishView.payload_format.pointee) : nil self.messageExpiryInterval = publishView.message_expiry_interval_seconds.unwrap().map { TimeInterval($0) } self.topicAlias = publishView.topic_alias.unwrap() - self.responseTopic = publishView.response_topic.toString() + self.responseTopic = publishView.response_topic?.pointee.toString() self.correlationData = publishView.correlation_data != nil ? Data(bytes: publishView.correlation_data!.pointee.ptr, count: publishView.correlation_data!.pointee.len) : nil var identifier: [UInt32]? = [] @@ -187,7 +187,7 @@ public class PublishPacket: CStruct { identifier?.append(subscription_identifier) } self.subscriptionIdentifiers = identifier - self.contentType = publishView.content_type.toString() + self.contentType = publishView.content_type?.pointee.toString() self.userProperties = convertOptionalUserProperties( count: publishView.user_property_count, userPropertiesPointer: publishView.user_properties) @@ -204,7 +204,8 @@ public class PublishPacket: CStruct { func validateConversionToNative() throws { if let messageExpiryInterval { if messageExpiryInterval < 0 || messageExpiryInterval > Double(UInt32.max) { - throw MqttError.validation(message: "Invalid sessionExpiryInterval value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid sessionExpiryInterval value")) } } } @@ -628,8 +629,8 @@ public class DisconnectPacket: CStruct { self.reasonCode = DisconnectReasonCode(rawValue: Int(disconnectView.reason_code.rawValue))! self.sessionExpiryInterval = disconnectView.session_expiry_interval_seconds.unwrap().map { TimeInterval($0) } - self.reasonString = disconnectView.reason_string.toString() - self.serverReference = disconnectView.reason_string.toString() + self.reasonString = disconnectView.reason_string?.pointee.toString() + self.serverReference = disconnectView.reason_string?.pointee.toString() self.userProperties = convertOptionalUserProperties( count: disconnectView.user_property_count, userPropertiesPointer: disconnectView.user_properties) @@ -638,7 +639,8 @@ public class DisconnectPacket: CStruct { func validateConversionToNative() throws { if let sessionExpiryInterval { if sessionExpiryInterval < 0 || sessionExpiryInterval > Double(UInt32.max) { - throw MqttError.validation(message: "Invalid sessionExpiryInterval value") + throw CommonRunTimeError.crtError(CRTError(code: AWS_ERROR_INVALID_ARGUMENT.rawValue, + context: "Invalid sessionExpiryInterval value")) } } } @@ -782,15 +784,15 @@ public class ConnackPacket { } self.retainAvailable = connackView.retain_available.unwrap() self.maximumPacketSize = connackView.maximum_packet_size.unwrap() - self.assignedClientIdentifier = connackView.assigned_client_identifier.toString() + self.assignedClientIdentifier = connackView.assigned_client_identifier?.pointee.toString() self.topicAliasMaximum = connackView.topic_alias_maximum.unwrap() - self.reasonString = connackView.reason_string.toString() + self.reasonString = connackView.reason_string?.pointee.toString() self.wildcardSubscriptionsAvailable = connackView.wildcard_subscriptions_available.unwrap() self.subscriptionIdentifiersAvailable = connackView.subscription_identifiers_available.unwrap() self.sharedSubscriptionAvailable = connackView.shared_subscriptions_available.unwrap() self.serverKeepAlive = connackView.server_keep_alive.unwrap().map { TimeInterval($0) } - self.responseInformation = connackView.response_information.toString() - self.serverReference = connackView.server_reference.toString() + self.responseInformation = connackView.response_information?.pointee.toString() + self.serverReference = connackView.server_reference?.pointee.toString() self.userProperties = convertOptionalUserProperties( count: connackView.user_property_count, userPropertiesPointer: connackView.user_properties)