Skip to content

Commit

Permalink
update error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
xiazhvera committed May 15, 2024
1 parent 01f10d7 commit e71722e
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 60 deletions.
14 changes: 14 additions & 0 deletions Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: BinaryInteger>(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())
Expand Down
8 changes: 0 additions & 8 deletions Source/AwsCommonRuntimeKit/crt/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,6 @@ extension Optional {
}
return validPointer.pointee
}

/// convert UnsafePointer<aws_byte_cursor> to optional String
func toString() -> String? where Wrapped == (UnsafePointer<aws_byte_cursor>) {
guard let validPointer = self?.pointee else {
return nil
}
return validPointer.toString()
}
}

extension Bool {
Expand Down
30 changes: 2 additions & 28 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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())
}
}
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
5 changes: 0 additions & 5 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901234>`__ encoding values.
public enum QoS {
Expand Down
27 changes: 18 additions & 9 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
}
}

Expand Down Expand Up @@ -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"))
}
}
}
Expand Down
22 changes: 12 additions & 10 deletions Source/AwsCommonRuntimeKit/mqtt/Mqtt5Packets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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]? = []
Expand All @@ -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)
Expand All @@ -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"))
}
}
}
Expand Down Expand Up @@ -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)
Expand All @@ -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"))
}
}
}
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit e71722e

Please sign in to comment.