jsdw_ios/Pods/CocoaMQTT/Source/CocoaMQTTStorage.swift

162 lines
4.1 KiB
Swift

//
// CocoaMQTTStorage.swift
// CocoaMQTT
//
// Created by JianBo on 2019/10/6.
// Copyright © 2019 emqtt.io. All rights reserved.
//
import Foundation
protocol CocoaMQTTStorageProtocol {
var clientId: String { get set }
init?(by clientId: String)
func write(_ frame: FramePublish) -> Bool
func write(_ frame: FramePubRel) -> Bool
func remove(_ frame: FramePublish)
func remove(_ frame: FramePubRel)
func synchronize() -> Bool
/// Read all stored messages by saving order
func readAll() -> [Frame]
}
final class CocoaMQTTStorage: CocoaMQTTStorageProtocol {
var clientId: String = ""
var userDefault: UserDefaults = UserDefaults()
var versionDefault: UserDefaults = UserDefaults()
init?() {
versionDefault = UserDefaults()
}
init?(by clientId: String) {
guard let userDefault = UserDefaults(suiteName: CocoaMQTTStorage.name(clientId)) else {
return nil
}
self.clientId = clientId
self.userDefault = userDefault
}
deinit {
userDefault.synchronize()
versionDefault.synchronize()
}
func setMQTTVersion(_ version: String) {
versionDefault.set(version, forKey: "cocoamqtt.emqx.version")
}
func queryMQTTVersion() -> String {
return versionDefault.string(forKey: "cocoamqtt.emqx.version") ?? "3.1.1"
}
func write(_ frame: FramePublish) -> Bool {
guard frame.qos > .qos0 else {
return false
}
userDefault.set(frame.bytes(version: queryMQTTVersion()), forKey: key(frame.msgid))
return true
}
func write(_ frame: FramePubRel) -> Bool {
userDefault.set(frame.bytes( version: queryMQTTVersion()), forKey: key(frame.msgid))
return true
}
func remove(_ frame: FramePublish) {
userDefault.removeObject(forKey: key(frame.msgid))
}
func remove(_ frame: FramePubRel) {
userDefault.removeObject(forKey: key(frame.msgid))
}
func remove(_ frame: Frame) {
if let pub = frame as? FramePublish {
userDefault.removeObject(forKey: key(pub.msgid))
} else if let rel = frame as? FramePubRel {
userDefault.removeObject(forKey: key(rel.msgid))
}
}
func synchronize() -> Bool {
return userDefault.synchronize()
}
func readAll() -> [Frame] {
return __read(needDelete: false)
}
func takeAll() -> [Frame] {
return __read(needDelete: true)
}
private func key(_ msgid: UInt16) -> String {
return "\(msgid)"
}
private static func name(_ clientId: String) -> String {
return "cocomqtt-\(clientId)"
}
private func parse(_ bytes: [UInt8]) -> (UInt8, [UInt8])? {
// FramePubRel is 4 bytes long
guard bytes.count > 3 else {
return nil
}
// bytes 1..<5 may be 'Remaining Length'
for i in 1 ..< min(5, bytes.count) where (bytes[i] & 0x80) == 0 {
return (bytes[0], Array(bytes.suffix(from: i + 1)))
}
return nil
}
private func __read(needDelete: Bool) -> [Frame] {
var frames = [Frame]()
let allObjs = userDefault.dictionaryRepresentation().sorted { (k1, k2) in
let left = UInt16(k1.key)
let right = UInt16(k2.key)
switch (left, right) {
case let (l?, r?):
return l < r
case (_?, nil):
return true
case (nil, _?):
return false
case (nil, nil):
return k1.key < k2.key
}
}
for (k, v) in allObjs {
guard let bytes = v as? [UInt8] else { continue }
guard let parsed = parse(bytes) else { continue }
if needDelete {
userDefault.removeObject(forKey: k)
}
if let f = FramePublish(packetFixedHeaderType: parsed.0, bytes: parsed.1) {
frames.append(f)
} else if let f = FramePubRel(packetFixedHeaderType: parsed.0, bytes: parsed.1) {
frames.append(f)
}
}
return frames
}
}