import Foundation import NIOCore /** Encapsulates a response from a device. */ struct DeviceResponse { /// Shorthand property for a timeout event. static var deviceTimedOut: DeviceResponse { .init(event: .deviceTimedOut) } /// Shorthand property for a disconnected event. static var deviceNotConnected: DeviceResponse { .init(event: .deviceNotConnected) } /// Shorthand property for a connected event. static var deviceConnected: DeviceResponse { .init(event: .deviceConnected) } /// Shorthand property for an unexpected socket event. static var unexpectedSocketEvent: DeviceResponse { .init(event: .unexpectedSocketEvent) } /// Shorthand property for an invalid message. static var invalidMessageData: DeviceResponse { .init(event: .invalidMessageData) } /// Shorthand property for missing body data. static var noBodyData: DeviceResponse { .init(event: .noBodyData) } /// Shorthand property for a busy connection static var operationInProgress: DeviceResponse { .init(event: .operationInProgress) } /// The response to a key from the server let event: MessageResult /// The index of the next key to use let response: Message? /** Decode a message from a buffer. The buffer must contain `Message.length+1` bytes. The first byte denotes the event type, the remaining bytes contain the message. - Parameter buffer: The buffer where the message bytes are stored */ init?(_ data: Data, request: String) { guard let byte = data.first else { log("\(request): No bytes received from device") return nil } guard let event = MessageResult(rawValue: byte) else { log("\(request): Unknown response \(byte) received from device") return nil } self.event = event let messageData = data.dropFirst() guard !messageData.isEmpty else { // TODO: Check if event should have response message self.response = nil return } guard messageData.count == Message.length else { log("\(request): Insufficient message data received from device (expected \(Message.length), got \(messageData.count))") self.response = nil return } self.response = Message(decodeFrom: data) } /** Create a response from an event without a message from the device. - Parameter event: The response from the device. */ init(event: MessageResult) { self.event = event self.response = nil } /// Get the reponse encoded in bytes. var encoded: Data { guard let message = response else { return Data([event.rawValue]) } return Data([event.rawValue]) + message.encoded } }