221 lines
7.2 KiB
Swift
221 lines
7.2 KiB
Swift
//
|
|
// CocoaMQTTReader.swift
|
|
// CocoaMQTT
|
|
//
|
|
// Created by HJianBo on 2019/5/21.
|
|
// Copyright © 2019 emqx.io. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// Read tag for AsyncSocket
|
|
enum CocoaMQTTReadTag: Int {
|
|
case header = 0
|
|
case length
|
|
case payload
|
|
}
|
|
|
|
///
|
|
protocol CocoaMQTTReaderDelegate: AnyObject {
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, connack: FrameConnAck)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, publish: FramePublish)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, puback: FramePubAck)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, pubrec: FramePubRec)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, pubrel: FramePubRel)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, pubcomp: FramePubComp)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, suback: FrameSubAck)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, unsuback: FrameUnsubAck)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, pingresp: FramePingResp)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, disconnect: FrameDisconnect)
|
|
|
|
func didReceive(_ reader: CocoaMQTTReader, auth: FrameAuth)
|
|
}
|
|
|
|
class CocoaMQTTReader {
|
|
|
|
private var socket: CocoaMQTTSocketProtocol
|
|
|
|
private weak var delegate: CocoaMQTTReaderDelegate?
|
|
|
|
private let timeout: TimeInterval = 30_000
|
|
|
|
/* -- Reader states -- */
|
|
private var header: UInt8 = 0
|
|
private var length: UInt = 0
|
|
private var data: [UInt8] = []
|
|
private var multiply = 1
|
|
/* -- Reader states -- */
|
|
|
|
init(socket: CocoaMQTTSocketProtocol, delegate: CocoaMQTTReaderDelegate?) {
|
|
self.socket = socket
|
|
self.delegate = delegate
|
|
}
|
|
|
|
func start() {
|
|
readHeader()
|
|
}
|
|
|
|
func headerReady(_ header: UInt8) {
|
|
self.header = header
|
|
readLength()
|
|
}
|
|
|
|
func lengthReady(_ byte: UInt8) {
|
|
length += (UInt)((Int)(byte & 127) * multiply)
|
|
// done
|
|
if byte & 0x80 == 0 {
|
|
if length == 0 {
|
|
frameReady()
|
|
} else {
|
|
readPayload()
|
|
}
|
|
// more
|
|
} else {
|
|
let result = multiply.multipliedReportingOverflow(by: 128)
|
|
if !result.overflow {
|
|
multiply = result.partialValue
|
|
} else {
|
|
reset()
|
|
}
|
|
readLength()
|
|
}
|
|
}
|
|
|
|
func payloadReady(_ data: Data) {
|
|
self.data = [UInt8](repeating: 0, count: data.count)
|
|
data.copyBytes(to: &(self.data), count: data.count)
|
|
frameReady()
|
|
}
|
|
|
|
private func readHeader() {
|
|
reset()
|
|
socket.readData(toLength: 1, withTimeout: -1, tag: CocoaMQTTReadTag.header.rawValue)
|
|
}
|
|
|
|
private func readLength() {
|
|
socket.readData(toLength: 1, withTimeout: timeout, tag: CocoaMQTTReadTag.length.rawValue)
|
|
}
|
|
|
|
private func readPayload() {
|
|
socket.readData(toLength: length, withTimeout: timeout, tag: CocoaMQTTReadTag.payload.rawValue)
|
|
}
|
|
|
|
private func frameReady() {
|
|
|
|
guard let frameType = FrameType(rawValue: UInt8(header & 0xF0)) else {
|
|
protocolError("Received unknown frame type, header: \(header), data:\(data)")
|
|
return
|
|
}
|
|
|
|
// XXX: stupid implement
|
|
|
|
switch frameType {
|
|
case .connack:
|
|
guard let connack = FrameConnAck(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, connack: connack)
|
|
case .publish:
|
|
guard let publish = FramePublish(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, publish: publish)
|
|
case .puback:
|
|
guard let puback = FramePubAck(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, puback: puback)
|
|
case .pubrec:
|
|
guard let pubrec = FramePubRec(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, pubrec: pubrec)
|
|
case .pubrel:
|
|
guard let pubrel = FramePubRel(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, pubrel: pubrel)
|
|
case .pubcomp:
|
|
guard let pubcomp = FramePubComp(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, pubcomp: pubcomp)
|
|
case .suback:
|
|
guard let frame = FrameSubAck(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, suback: frame)
|
|
case .unsuback:
|
|
guard let frame = FrameUnsubAck(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, unsuback: frame)
|
|
case .pingresp:
|
|
guard let frame = FramePingResp(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, pingresp: frame)
|
|
case .disconnect:
|
|
guard isMQTT5ProtocolVersion() else {
|
|
protocolError("Reader received MQTT5-only frame \(frameType) in non-MQTT5 mode, data: \(data)")
|
|
return
|
|
}
|
|
guard let frame = FrameDisconnect(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, disconnect: frame)
|
|
case .auth:
|
|
guard isMQTT5ProtocolVersion() else {
|
|
protocolError("Reader received MQTT5-only frame \(frameType) in non-MQTT5 mode, data: \(data)")
|
|
return
|
|
}
|
|
guard let frame = FrameAuth(packetFixedHeaderType: header, bytes: data) else {
|
|
protocolError("Reader parse \(frameType) failed, data: \(data)")
|
|
return
|
|
}
|
|
delegate?.didReceive(self, auth: frame)
|
|
default:
|
|
protocolError("Received unsupported frame type \(frameType), data: \(data)")
|
|
return
|
|
}
|
|
|
|
readHeader()
|
|
}
|
|
|
|
private func protocolError(_ reason: String) {
|
|
printError(reason)
|
|
socket.disconnect()
|
|
}
|
|
|
|
private func isMQTT5ProtocolVersion() -> Bool {
|
|
return CocoaMQTTStorage()?.queryMQTTVersion() == "5.0"
|
|
}
|
|
|
|
private func reset() {
|
|
length = 0
|
|
multiply = 1
|
|
header = 0
|
|
data = []
|
|
}
|
|
}
|