import Foundation /** A result from sending a key to the device. */ enum MessageResult: UInt8 { /// The message was accepted. case messageAccepted = 0 /// The web socket received text while waiting for binary data. case textReceived = 1 /// An unexpected socket event occured while performing the exchange. case unexpectedSocketEvent = 2 /// The received message size is invalid. case invalidMessageSizeFromRemote = 3 /// The message signature was incorrect. case invalidSignatureByRemote = 4 /// The server challenge of the message did not match previous messages case serverChallengeMismatch = 5 /// The client challenge of the message did not match previous messages case clientChallengeMismatchFromRemote = 6 /// An unexpected or unsupported message type was received case invalidMessageTypeFromRemote = 7 /// A message is already being processed case tooManyRequests = 8 /// The received message result was not ``messageAccepted`` case invalidMessageResultFromRemote = 9 /// An invalid Url parameter was set sending a message to the device over a local connection case invalidUrlParameter = 10 /// The request took too long to complete case deviceTimedOut = 20 case noOrInvalidBodyDataInServerRequest = 21 /// The device is not connected to the server via web socket case deviceNotConnected = 22 case serverNotReached = 23 case serverUrlInvalid = 24 case invalidDeviceResponseSize = 25 case invalidSignatureByDevice = 26 case noKeyAvailable = 27 case unlocked = 28 case unknownMessageResultFromDevice = 29 /// The device sent a message with an invalid client challenge case clientChallengeMismatchFromDevice = 30 /// A valid server challenge was received case deviceAvailable = 31 case invalidMessageTypeFromDevice = 32 /// The url session request returned an unknown response case unexpectedUrlResponseType = 33 /// The request to the server returned an unhandled HTTP code case unexpectedServerResponseCode = 34 /// The server produced an internal error (500) case internalServerError = 35 /// The Sesame server behind the proxy could not be found (502) case serviceBehindProxyUnavailable = 36 /// The server url could not be found (404) case pathOnServerNotFound = 37 /// The header with the authentication token was missing or invalid (not a hex string) from a server request. case missingOrInvalidAuthenticationHeader = 38 /// The authentication token for the server was invalid case invalidServerAuthentication = 39 /// The device sent a response of invalid size case invalidMessageSizeFromDevice = 40 } extension MessageResult: Error { } extension MessageResult: CustomStringConvertible { var description: String { switch self { case .messageAccepted: return "Message accepted" case .textReceived: return "The device received unexpected text" case .unexpectedSocketEvent: return "Unexpected socket event for the device" case .invalidMessageSizeFromRemote: return "Invalid message data from remote" case .invalidSignatureByRemote: return "Message authentication failed" case .noOrInvalidBodyDataInServerRequest: return "Invalid body data in server request" case .deviceNotConnected: return "Device not connected to server" case .deviceTimedOut: return "The device did not respond" case .serverChallengeMismatch: return "Server challenge mismatch" case .clientChallengeMismatchFromRemote: return "Wrong client challenge sent" case .invalidMessageTypeFromRemote: return "Message type from remote invalid" case .tooManyRequests: return "Device busy" case .invalidUrlParameter: return "The url parameter could not be found" case .invalidMessageResultFromRemote: return "Invalid message result" case .serverNotReached: return "Server unavailable" case .serverUrlInvalid: return "Invalid server url" case .invalidDeviceResponseSize: return "Invalid Response size" case .invalidSignatureByDevice: return "Invalid device signature" case .noKeyAvailable: return "No key available" case .unlocked: return "Unlocked" case .unknownMessageResultFromDevice: return "Unknown message result" case .deviceAvailable: return "Device available" case .clientChallengeMismatchFromDevice: return "Device sent invalid client challenge" case .invalidMessageTypeFromDevice: return "Message type from device invalid" case .unexpectedUrlResponseType: return "Unexpected URL response" case .unexpectedServerResponseCode: return "Unexpected server response code" case .internalServerError: return "Internal server error" case .serviceBehindProxyUnavailable: return "Service behind proxy not found" case .pathOnServerNotFound: return "Invalid server path" case .missingOrInvalidAuthenticationHeader: return "Invalid server token format" case .invalidServerAuthentication: return "Invalid server token" case .invalidMessageSizeFromDevice: return "Invalid device message size" } } } extension MessageResult: Codable { } extension MessageResult { var encoded: Data { Data([rawValue]) } } extension MessageResult { init(httpCode: Int) { switch httpCode { case 200: self = .messageAccepted case 204: self = .noOrInvalidBodyDataInServerRequest case 403: self = .invalidServerAuthentication case 404: self = .pathOnServerNotFound case 408: self = .deviceTimedOut case 412: self = .deviceNotConnected case 413: self = .invalidMessageSizeFromDevice case 422: self = .missingOrInvalidAuthenticationHeader case 429: self = .tooManyRequests case 500: self = .internalServerError case 501: self = .unexpectedServerResponseCode case 502: self = .serviceBehindProxyUnavailable default: self = .unexpectedServerResponseCode } } var statusCode: Int { switch self { case .messageAccepted: return 200 // ok case .noOrInvalidBodyDataInServerRequest: return 204 // noContent case .invalidServerAuthentication: return 403 // forbidden case .pathOnServerNotFound: return 404 // notFound case .deviceTimedOut: return 408 // requestTimeout case .invalidMessageSizeFromRemote: return 411 // lengthRequired case .deviceNotConnected: return 412 // preconditionFailed case .invalidMessageSizeFromDevice: return 413 // payloadTooLarge case .missingOrInvalidAuthenticationHeader: return 422 // unprocessableEntity case .tooManyRequests: return 429 // tooManyRequests case .internalServerError: return 500 // internalServerError case .unexpectedServerResponseCode: return 501 // notImplemented case .serviceBehindProxyUnavailable: return 502 // badGateway default: return 501 // == unexpectedServerResponseCode } } }