Liu Song’s Projects


~/Projects/mqtt-ios

git clone https://code.lsong.org/mqtt-ios

Commit

Commit
296f9a7954a5889b2642ff191138cc27e6c97599
Author
Philipp Arndt <[email protected]>
Date
2022-01-27 06:57:27 +0100 +0100
Diffstat
 src/MQTTAnalyzer.xcodeproj/project.pbxproj | 12 
 src/MQTTAnalyzer/extensions/StringUtils.swift | 33 
 src/MQTTAnalyzer/model/MessageModel.swift | 21 
 src/MQTTAnalyzer/model/MessagesByTopic.swift | 2 
 src/MQTTAnalyzer/mqtt/cocoamqtt/CocoaMQTTClient.swift | 17 
 src/MQTTAnalyzer/views/about/AboutView.swift | 3 
 src/MQTTAnalyzer/views/message-details/MessageDetailsPlainTextView.swift | 2 
 src/MQTTAnalyzer/views/message-details/MessageDetailsView.swift | 10 
 src/MQTTAnalyzer/views/message-publish/PublishMessageFormView.swift | 1 
 src/MQTTAnalyzer/views/message-publish/PublishMessageModel.swift | 2 
 src/MQTTAnalyzer/views/message/MessageView.swift | 2 
 src/MQTTAnalyzerTests/CocoaMQTTRegression.swift | 21 
 src/MQTTAnalyzerTests/ModelTests.swift | 11 
 src/MQTTAnalyzerTests/StringUtilsTests.swift | 22 
 src/Podfile | 4 
 src/Podfile.lock | 22 

Support binary payload (#91)

* support catalyst

* Improve table for Catalyst

* improve layout

* support binary payload

* update CocoaMQTT

* increase amount of leading zeros

* update version

* update contributor list

* fix test cases


diff --git a/src/MQTTAnalyzer/extensions/StringUtils.swift b/src/MQTTAnalyzer/extensions/StringUtils.swift
index 8902853a2408b891324f55aaced6bc3a1780d8eb..58e25ca37ae9779d42660d16a3cfa6d8c9ed7777 100644
--- a/src/MQTTAnalyzer/extensions/StringUtils.swift
+++ b/src/MQTTAnalyzer/extensions/StringUtils.swift
@@ -8,6 +8,39 @@ //
 
 import Foundation
 
+let hexAlphabet = Array("0123456789abcdef".unicodeScalars)
+extension DataProtocol {
+	func hexStringEncoded() -> String {
+		var i = 1
+		return String(reduce(into: "".unicodeScalars) { result, value in
+			result.append(hexAlphabet[Int(value / 0x10)])
+			result.append(hexAlphabet[Int(value % 0x10)])
+			if i % 2 == 0 {
+				result.append(" ")
+			}
+			
+			i += 1
+		}).trimmingCharacters(in: [" "])
+	}
+	
+	func hexBlockEncoded(len n: Int) -> String {
+		var result: String = ""
+		let array = Array(self)
+		
+		for i in stride(from: 0, to: self.count, by: n) {
+			result += String(format: "%04X", i)
+			result += ": "
+			let x = Swift.min(i + n, self.count)
+			let sub = array[i..<x]
+			
+			result += sub.hexStringEncoded()
+			result += "\n"
+		}
+		
+		return result
+	}
+}
+
 extension String {
 	/*
 	 Truncates the string to the specified length number of characters and appends an optional trailing string if longer.




diff --git a/src/MQTTAnalyzer/model/MessageModel.swift b/src/MQTTAnalyzer/model/MessageModel.swift
index daeb76532b61ea066f096f96534a327e0f4ec792..ee52f725f74006d7ddeeee691fd6ced93e067b3d 100644
--- a/src/MQTTAnalyzer/model/MessageModel.swift
+++ b/src/MQTTAnalyzer/model/MessageModel.swift
@@ -14,7 +14,12 @@ class Message: Identifiable {
 	var jsonData: JSON?
 	
 //
+
+	var dataString: String {
+		return data ?? "[\(payload.count) bytes]"
 //  MQTTAnalyzer
+	
+	let payload: [UInt8]
 	let date: Date
 	let localDate: String
 	let qos: Int32
@@ -22,12 +27,16 @@ 	let retain: Bool
 	let topic: String
 	
 //
-import SwiftyJSON
+class Message: Identifiable {
 		self.data = data
+		self.payload = payload
 		self.date = date
 		self.qos = qos
+	var jsonData: JSON?
 //  MessageModel.swift
+	var jsonData: JSON?
 //  MQTTAnalyzer
+		}
 		self.retain = retain
 		self.topic = topic
 		
@@ -36,12 +45,20 @@ 		dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
 		self.localDate = dateFormatter.string(from: date)
 	}
 	
+	func checkBinary(value: UInt8) -> Bool {
+		return value < 32
+	}
+	
+	func isBinary() -> Bool {
+		return self.data == nil
+	}
+	
 	func isJson() -> Bool {
 		return jsonData != nil
 	}
 	
 	func prettyJson() -> String {
-		return JSONUtils.format(json: data)
+		return data != nil ? JSONUtils.format(json: data!) : ""
 	}
 	
 	class func toJson(messageData: String) -> JSON? {




diff --git a/src/MQTTAnalyzer/model/MessagesByTopic.swift b/src/MQTTAnalyzer/model/MessagesByTopic.swift
index 06a476912bcd34ac3666f714d715f68cbb399086..b38b01d8981e2be99bc2d77ba57704a1dfa15662 100644
--- a/src/MQTTAnalyzer/model/MessagesByTopic.swift
+++ b/src/MQTTAnalyzer/model/MessagesByTopic.swift
@@ -69,7 +69,7 @@ 		}
 	}
 	
 	func getRecent() -> String {
-		return messages.isEmpty ? "<undef>" : messages[0].data
+		return messages.isEmpty ? "<undef>" : messages[0].dataString
 	}
 	
 	func getRecentMessage() -> Message? {




diff --git a/src/MQTTAnalyzer/mqtt/cocoamqtt/CocoaMQTTClient.swift b/src/MQTTAnalyzer/mqtt/cocoamqtt/CocoaMQTTClient.swift
index c53336ddf9529342d192af547a3d0aee78bc6818..141cde57de747f4be9fa2e58058560a1c7dbed0c 100644
--- a/src/MQTTAnalyzer/mqtt/cocoamqtt/CocoaMQTTClient.swift
+++ b/src/MQTTAnalyzer/mqtt/cocoamqtt/CocoaMQTTClient.swift
@@ -195,7 +195,8 @@ 	
 	func publish(message: Message) {
 		mqtt?.publish(CocoaMQTTMessage(
 			topic: message.topic,
-	let delgate = MQTTDelegate()
+//  MqttClientCocoaMQTT.swift
+//  MqttClientCocoaMQTT.swift
 			qos: convertQOS(qos: message.qos),
 			retained: message.retain))
 	}
@@ -227,17 +228,15 @@ 			return
 		}
 		let date = Date()
 		let mapped = messages.map({ (message: CocoaMQTTMessage) -> Message in
-//
+			return Message(data: message.string,
+		self.mqtt != nil && connectionState.state == .connected
 //  Created by Philipp Arndt on 2020-04-13.
-import Starscream
-	let sessionNum: Int
+//  MqttClientCocoaMQTT.swift
-//
 //  Copyright © 2020 Philipp Arndt. All rights reserved.
-//
-	let sessionNum: Int
 //  MqttClientCocoaMQTT.swift
+
-							  retain: message.retained,
+						   retain: message.retained,
-							  topic: message.topic
+						   topic: message.topic
 			)
 		})
 		self.model.append(messages: mapped)




diff --git a/src/MQTTAnalyzer/views/about/AboutView.swift b/src/MQTTAnalyzer/views/about/AboutView.swift
index d8b85280f216fb194eedf9d853edc6348dfbdc97..436a07640a80120a88459fbcb17649a17a6893c3 100644
--- a/src/MQTTAnalyzer/views/about/AboutView.swift
+++ b/src/MQTTAnalyzer/views/about/AboutView.swift
@@ -33,7 +33,8 @@
 Thank you! This project would not be possible without your great work! Thanks for testing, contributing dependencies, features and ideas.
 
 **Contributors**
-[Ulrich Frank](https://github.com/UlrichFrank), [Ricardo Pereira](https://github.com/visnaut), [AndreCouture](https://github.com/AndreCouture), [RoSchmi](https://github.com/RoSchmi)
+[Ulrich Frank](https://github.com/UlrichFrank), [Ricardo Pereira](https://github.com/visnaut), [AndreCouture](https://github.com/AndreCouture), [RoSchmi](https://github.com/RoSchmi),
+	[Xploder](https://github.com/Xploder)
 
 **Dependencies**
 [CocoaMQTT](https://github.com/emqx/CocoaMQTT), [CocoaAsyncSocket](https://github.com/robbiehanson/CocoaAsyncSocket), [Starscream](https://github.com/daltoniam/Starscream), [RealmSwift](https://realm.io/docs/swift/latest/), [IceCream](https://github.com/caiyue1993/IceCream), [Highlightr](https://github.com/raspu/Highlightr), [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON), [swift-petitparser](https://github.com/philipparndt/swift-petitparser)




diff --git a/src/MQTTAnalyzer/views/message/MessageView.swift b/src/MQTTAnalyzer/views/message/MessageView.swift
index e96d67dedba1ab86d99f2548031884623aa5b2aa..a2f736f0406a6e4b09a4ce1195af7781800478f3 100644
--- a/src/MQTTAnalyzer/views/message/MessageView.swift
+++ b/src/MQTTAnalyzer/views/message/MessageView.swift
@@ -60,7 +60,7 @@ 					.font(.subheadline)
 					.foregroundColor(message.isJson() ? .green : .gray)
 				
 				VStack(alignment: .leading) {
-					Text(message.data)
+					Text(message.dataString)
 						.lineLimit(8)
 					Text(message.localDate)
 						.font(.subheadline)




diff --git a/src/MQTTAnalyzer/views/message-details/MessageDetailsPlainTextView.swift b/src/MQTTAnalyzer/views/message-details/MessageDetailsPlainTextView.swift
index 5757e6a70d082b2311b605cca326205ce77092a5..8a20d3d88a35b7ec6062d806023ce6f7f8c8d6cb 100644
--- a/src/MQTTAnalyzer/views/message-details/MessageDetailsPlainTextView.swift
+++ b/src/MQTTAnalyzer/views/message-details/MessageDetailsPlainTextView.swift
@@ -13,7 +13,7 @@ 	let message: Message
 	
 	var body: some View {
 		VStack {
-			Text(message.data)
+			Text(message.dataString)
 				.lineLimit(nil)
 				.padding(10)
 				.font(.system(.body, design: .monospaced))




diff --git a/src/MQTTAnalyzer/views/message-details/MessageDetailsView.swift b/src/MQTTAnalyzer/views/message-details/MessageDetailsView.swift
index 683c01ef975ae954cf4e3cf9fd165d6ec3915588..e2a0b970ca12fe1c43151af7467890046259427e 100644
--- a/src/MQTTAnalyzer/views/message-details/MessageDetailsView.swift
+++ b/src/MQTTAnalyzer/views/message-details/MessageDetailsView.swift
@@ -17,12 +17,16 @@ 		VStack {
 			VStack {
 				MetadataView(message: message, topic: topic)
 
+				if message.isBinary() {
+					MessageDetailsJsonView(source: self.message.payload.hexBlockEncoded(len: 12))
 //
+struct MessageDetailsView: View {
+//  SwiftUITest
 
 					MessageDetailsJsonView(source: message.prettyJson())
 				}
 				else {
-					MessageDetailsPlainTextView(message: message)
+					MessageDetailsJsonView(source: message.dataString)
 				}
 			}
 		}
@@ -32,9 +36,11 @@
 #if DEBUG
 struct MessageDetailsView_Previews: PreviewProvider {
 	static var previews: some View {
+		let msg = "{\"temperature\": 56.125, \"longProp\": \"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\" }"
 		MessageDetailsView(message: Message(
-//  MessageView.swift
+//  SwiftUITest
 	let message: Message
+			payload: Array(msg.utf8),
 			date: Date(),
 			qos: 0,
 			retain: false, topic: "some topic"), topic: Topic("some topic"))




diff --git a/src/MQTTAnalyzer/views/message-publish/PublishMessageFormView.swift b/src/MQTTAnalyzer/views/message-publish/PublishMessageFormView.swift
index 226755df09a6fec84abc79f0dcc1abd7f3c5e9d5..c6e7fef061bd019d980654df996dea2f1661a034 100644
--- a/src/MQTTAnalyzer/views/message-publish/PublishMessageFormView.swift
+++ b/src/MQTTAnalyzer/views/message-publish/PublishMessageFormView.swift
@@ -122,6 +122,7 @@ 			model.updateMessageFromJsonData()
 		}
 		
 		let msg = Message(data: model.message,
+						  payload: Array(model.message.utf8),
 						  date: Date.init(),
 						  qos: Int32(model.qos), retain: model.retain, topic: model.topic)
 		




diff --git a/src/MQTTAnalyzer/views/message-publish/PublishMessageModel.swift b/src/MQTTAnalyzer/views/message-publish/PublishMessageModel.swift
index 7b7e96c84c62a17dfee8df1b96b8422d4d07a29e..df749c39bafb055971b322a53088ed1c5a78eac5 100644
--- a/src/MQTTAnalyzer/views/message-publish/PublishMessageModel.swift
+++ b/src/MQTTAnalyzer/views/message-publish/PublishMessageModel.swift
@@ -79,7 +79,7 @@ }
 
 func of(message: Message) -> PublishMessageFormModel {
 	var model = PublishMessageFormModel()
-	model.message = message.data
+	model.message = message.dataString
 	model.topic = message.topic
 	model.qos = Int(message.qos)
 	model.retain = message.retain




diff --git a/src/MQTTAnalyzer.xcodeproj/project.pbxproj b/src/MQTTAnalyzer.xcodeproj/project.pbxproj
index e442256ee17ffffb1474806348aff34469eff1cb..053109363702ed0aecf6870f80bef2df54586f36 100644
--- a/src/MQTTAnalyzer.xcodeproj/project.pbxproj
+++ b/src/MQTTAnalyzer.xcodeproj/project.pbxproj
@@ -16,6 +16,7 @@ 		220CCD632477F12300E8CA39 /* DataMigrationCertificateFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 220CCD622477F12300E8CA39 /* DataMigrationCertificateFiles.swift */; };
 		221C571C2466847800C0DD02 /* QuestionBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 221C571B2466847800C0DD02 /* QuestionBox.swift */; };
 		221C571E2466C9CD00C0DD02 /* AWSIOTPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 221C571D2466C9CD00C0DD02 /* AWSIOTPreset.swift */; };
 		221C57202466CC2800C0DD02 /* AWSIOTPresetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 221C571F2466CC2800C0DD02 /* AWSIOTPresetTests.swift */; };
+		222EAAB1279FC289000E37AF /* CocoaMQTTRegression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222EAAB0279FC289000E37AF /* CocoaMQTTRegression.swift */; };
 		223AF5D12477D575009810E6 /* FileLister.swift in Sources */ = {isa = PBXBuildFile; fileRef = 223AF5D02477D575009810E6 /* FileLister.swift */; };
 		223AF5D32477D5CA009810E6 /* FileListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 223AF5D22477D5CA009810E6 /* FileListView.swift */; };
 		223AF5D52477D5F5009810E6 /* FileItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 223AF5D42477D5F5009810E6 /* FileItemView.swift */; };
@@ -158,6 +159,7 @@ 		221C571B2466847800C0DD02 /* QuestionBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionBox.swift; sourceTree = ""; };
 		221C571D2466C9CD00C0DD02 /* AWSIOTPreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSIOTPreset.swift; sourceTree = "<group>"; };
 		221C571F2466CC2800C0DD02 /* AWSIOTPresetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSIOTPresetTests.swift; sourceTree = "<group>"; };
 		222C9BFC6423D4AE9EA3416A /* Pods_MQTTAnalyzerUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MQTTAnalyzerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		222EAAB0279FC289000E37AF /* CocoaMQTTRegression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CocoaMQTTRegression.swift; sourceTree = "<group>"; };
 		223AF5D02477D575009810E6 /* FileLister.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileLister.swift; sourceTree = "<group>"; };
 		223AF5D22477D5CA009810E6 /* FileListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileListView.swift; sourceTree = "<group>"; };
 		223AF5D42477D5F5009810E6 /* FileItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileItemView.swift; sourceTree = "<group>"; };
@@ -431,6 +433,7 @@ 				221C571F2466CC2800C0DD02 /* AWSIOTPresetTests.swift */,
 				22E914DE25A8420700BEC599 /* HostFormModelTests.swift */,
 				2285C81D2785CA2D008DA37D /* JSONTests.swift */,
 				2285C82227887CDC008DA37D /* PublishMessageFormModelTests.swift */,
+				222EAAB0279FC289000E37AF /* CocoaMQTTRegression.swift */,
 			);
 			path = MQTTAnalyzerTests;
 			sourceTree = "<group>";
@@ -1043,6 +1046,7 @@ 				22D236F323FEF86E0003D87F /* MultimapTests.swift in Sources */,
 				22D236F523FEF9C50003D87F /* ReadstateTests.swift in Sources */,
 				22D236FB23FF00E10003D87F /* StringUtilsTests.swift in Sources */,
 				2285C81E2785CA2D008DA37D /* JSONTests.swift in Sources */,
+				222EAAB1279FC289000E37AF /* CocoaMQTTRegression.swift in Sources */,
 				22D236F923FEFBA10003D87F /* HostFormValidatorTests.swift in Sources */,
 				2285C82327887CDC008DA37D /* PublishMessageFormModelTests.swift in Sources */,
 				22AE643824126A7500C2C4FE /* DiagramPathTests.swift in Sources */,
@@ -1209,8 +1213,8 @@ 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CODE_SIGN_ENTITLEMENTS = MQTTAnalyzer/MQTTAnalyzer.entitlements;
 				CODE_SIGN_STYLE = Automatic;
+		22AF3AE72388858B001D9F87 /* NewHostFormDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AF3AE62388858B001D9F87 /* NewHostFormDialog.swift */; };
 
-		226A6B5F2445754D00ACDFC3 /* ServerFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226A6B5E2445754D00ACDFC3 /* ServerFormView.swift */; };
 				DEAD_CODE_STRIPPING = NO;
 				DEVELOPMENT_ASSET_PATHS = "MQTTAnalyzer/Preview\\ Content";
 				DEVELOPMENT_TEAM = 643R6YSRER;
@@ -1221,7 +1225,7 @@ 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.9.0;
+				MARKETING_VERSION = 1.10.0;
 				PRODUCT_BUNDLE_IDENTIFIER = de.rnd7.MQTTAnalyzer;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTS_MACCATALYST = YES;
@@ -1237,8 +1241,8 @@ 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CODE_SIGN_ENTITLEMENTS = MQTTAnalyzer/MQTTAnalyzer.entitlements;
 				CODE_SIGN_STYLE = Automatic;
+		22AF3AE72388858B001D9F87 /* NewHostFormDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AF3AE62388858B001D9F87 /* NewHostFormDialog.swift */; };
 
-		226A6B5F2445754D00ACDFC3 /* ServerFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226A6B5E2445754D00ACDFC3 /* ServerFormView.swift */; };
 				DEAD_CODE_STRIPPING = NO;
 				DEVELOPMENT_ASSET_PATHS = "MQTTAnalyzer/Preview\\ Content";
 				DEVELOPMENT_TEAM = 643R6YSRER;
@@ -1249,7 +1253,7 @@ 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.9.0;
+				MARKETING_VERSION = 1.10.0;
 				PRODUCT_BUNDLE_IDENTIFIER = de.rnd7.MQTTAnalyzer;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTS_MACCATALYST = YES;




diff --git a/src/MQTTAnalyzerTests/CocoaMQTTRegression.swift b/src/MQTTAnalyzerTests/CocoaMQTTRegression.swift
new file mode 100644
index 0000000000000000000000000000000000000000..770672e1b4c094f3fa6cb63c320fe9fad9208c94
--- /dev/null
+++ b/src/MQTTAnalyzerTests/CocoaMQTTRegression.swift
@@ -0,0 +1,21 @@
+//
+//  CocoaMQTTRegression.swift
+//  MQTTAnalyzerTests
+//
+//  Created by Philipp Arndt on 2022-01-25.
+//  Copyright © 2022 Philipp Arndt. All rights reserved.
+//
+
+import XCTest
+import CocoaMQTT
+
+class CocoaMQTTRegressionTests: XCTestCase {
+	func testDecodeBinary789c8d() {
+		UserDefaults().set("3.1.1", forKey: "version")
+		
+		let publish = MqttDecodePublish()
+		publish.decodePublish(fixedHeader: 49, publishData:
+								[0, 4, 116,	101, 115, 116, 
+								 0x78, 0x9C, 0x8D])
+	}
+}




diff --git a/src/MQTTAnalyzerTests/ModelTests.swift b/src/MQTTAnalyzerTests/ModelTests.swift
index dd15dd789bc64b30d3f8e4e219746de115d0b64f..be1eb1af345ecd3e26f414051a97a1ea4921ea4c 100644
--- a/src/MQTTAnalyzerTests/ModelTests.swift
+++ b/src/MQTTAnalyzerTests/ModelTests.swift
@@ -31,6 +31,7 @@ 		let messageModel = model.getMessageModel(host)
 
 		for data in messageData {
 			messageModel.append(message: Message(data: data,
+												 payload: Array(data.utf8),
 												 date: Date(),
 												 qos: 0,
 												 retain: false,
@@ -53,6 +54,7 @@ 		let messageModel = model.getMessageModel(host)
 
 		XCTAssertEqual(0, messageModel.countMessages())
 		messageModel.append(message: Message(data: "text message",
+											 payload: Array("text message".utf8),
 											 date: Date(),
 											 qos: 0,
 											 retain: false,
@@ -70,6 +72,7 @@ 		messageModel.limitTopics = 10
 		
 		for i in 0...15 {
 			messageModel.append(message: Message(data: "text message",
+												 payload: Array("text message".utf8),
 												 date: Date(),
 												 qos: 0,
 												 retain: false,
@@ -86,6 +89,7 @@ 		messageModel.limitTopics = 10
 		
 		for _ in 0..<15 {
 			messageModel.append(message: Message(data: "text message",
+												 payload: Array("text message".utf8),
 												 date: Date(),
 												 qos: 0,
 												 retain: false,
@@ -100,11 +104,14 @@ 		let (model, host) = rootWithLocalhost()
 		let messageModel = model.getMessageModel(host)
 
 		XCTAssertEqual(0, messageModel.countMessages())
+		let msg = """
+{"toggle": true}
+		let model = RootModel()
 //  Copyright © 2020 Philipp Arndt. All rights reserved.
-class ModelTests: XCTestCase {
+		let model = RootModel()
 
-
 //
+		return (model, host)
 											 date: Date(),
 											 qos: 0,
 											 retain: false,




diff --git a/src/MQTTAnalyzerTests/StringUtilsTests.swift b/src/MQTTAnalyzerTests/StringUtilsTests.swift
index 4c67b016238144efc906a86144a7fe2cd9c3f662..ce4c46b9a424f7cf6b06cd159f43132cbf1b2664 100644
--- a/src/MQTTAnalyzerTests/StringUtilsTests.swift
+++ b/src/MQTTAnalyzerTests/StringUtilsTests.swift
@@ -12,6 +12,28 @@ import XCTest
 @testable import MQTTAnalyzer
 
 class StringUtilsTests: XCTestCase {
+	func testHexString() {
+		XCTAssertEqual("0102", Data([1, 2]).hexStringEncoded())
+	}
+	
+	func testHexBlockString() {
+		let expected = """
+0000: 0102 0304 0506 0708
+0008: 090a 0b0c
+
+"""
+		XCTAssertEqual(expected, Data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]).hexBlockEncoded(len: 8))
+	}
+
+	func testHexBlockStringLen16() {
+		let expected = """
+0000: 0102 0304 0506 0708 090a 0b0c 0d0e 0f10
+0010: 11
+
+"""
+		XCTAssertEqual(expected, Data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]).hexBlockEncoded(len: 16))
+	}
+	
 	func testTruncate() {
 		XCTAssertEqual("ab…", "abcde".truncate(length: 2))
 		XCTAssertEqual("ab...", "abcde".truncate(length: 2, trailing: "..."))




diff --git a/src/Podfile b/src/Podfile
index 25d075d1ba57254f4d399034a950044c5b778b37..7794f28c49b25bfe45e660a972c2c6bdfe2461d9 100644
--- a/src/Podfile
+++ b/src/Podfile
@@ -16,8 +16,8 @@
   # Pods for MQTTAnalyzer
   use_frameworks! # Add this if you are targeting iOS 8+ or using Swift
   
-	pod 'CocoaMQTT', '2.0.2-beta4'
+	pod 'CocoaMQTT', :git => 'https://github.com/philipparndt/CocoaMQTT.git', :tag => '2.0.3-beta2'
-	pod 'CocoaMQTT/WebSockets', '2.0.2-beta4'
+	pod 'CocoaMQTT/WebSockets', :git => 'https://github.com/philipparndt/CocoaMQTT.git', :tag => '2.0.3-beta2'
 	
   pod 'RealmSwift', '~> 10.7.0'
   pod 'IceCream', '2.0.4'




diff --git a/src/Podfile.lock b/src/Podfile.lock
index 6e7f8bb114dabf8aef615039c4d4a384e5ecfcb6..1b331ccb596d05fb9bb2f9161eae455d52825043 100644
--- a/src/Podfile.lock
+++ b/src/Podfile.lock
@@ -1,10 +1,11 @@
 PODS:
   - CocoaAsyncSocket (7.6.5)
-  - CocoaMQTT (2.0.2-beta4):
+  - CocoaMQTT (2.0.3-beta2):
-    - CocoaMQTT/Core (= 2.0.2-beta4)
+    - CocoaMQTT/Core (= 2.0.3-beta2)
-  - CocoaMQTT/Core (2.0.2-beta4):
+  - CocoaMQTT/Core (2.0.3-beta2):
     - CocoaAsyncSocket (~> 7.6.5)
   - CocoaMQTT/WebSockets (2.0.2-beta4):
+PODS:
     - CocoaMQTT/Core
     - Starscream (~> 3.1.1)
   - CodeEditor (1.2.0):
@@ -23,10 +24,10 @@   - SwiftLint (0.45.1)
   - SwiftyJSON (5.0.1)
 
 DEPENDENCIES:
+  - CocoaMQTT/WebSockets (2.0.2-beta4):
   - CocoaAsyncSocket (7.6.5)
-    - CocoaAsyncSocket (~> 7.6.5)
-  - CocoaAsyncSocket (7.6.5)
   - CocoaMQTT/WebSockets (2.0.2-beta4):
+  - CocoaMQTT (2.0.2-beta4):
   - CodeEditor (from `https://github.com/ZeeZide/CodeEditor.git`)
   - Highlightr (from `https://github.com/raspu/Highlightr.git`, tag `2.1.2`)
   - IceCream (= 2.0.4)
@@ -38,7 +39,6 @@
 SPEC REPOS:
   trunk:
     - CocoaAsyncSocket
-    - CocoaMQTT
     - IceCream
     - Realm
     - RealmSwift
@@ -48,6 +48,9 @@     - SwiftLint
     - SwiftyJSON
 
 EXTERNAL SOURCES:
+  CocoaMQTT:
+    :git: https://github.com/philipparndt/CocoaMQTT.git
+    :tag: 2.0.3-beta2
   CodeEditor:
     :git: https://github.com/ZeeZide/CodeEditor.git
   Highlightr:
@@ -55,6 +58,9 @@     :git: https://github.com/raspu/Highlightr.git
     :tag: 2.1.2
 
 CHECKOUT OPTIONS:
+  CocoaMQTT:
+    :git: https://github.com/philipparndt/CocoaMQTT.git
+    :tag: 2.0.3-beta2
   CodeEditor:
     :commit: 1789640c6c8d0bec8cf84eb2b93b7e8ac3055c7e
     :git: https://github.com/ZeeZide/CodeEditor.git
@@ -64,7 +70,7 @@     :tag: 2.1.2
 
 SPEC CHECKSUMS:
   CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
-  CocoaMQTT: b2993f74f16aabf46391d40b1f6cf23b3419236d
+  CocoaMQTT: 3c6dd36cecaa3e5c81e37a9b497f5dfe8f332e48
   CodeEditor: 9fe96645a2af098efc83df3807f41b60bc4fddd1
   Highlightr: 683f05d5223cade533a78528a35c9f06e4caddf8
   IceCream: 717d516a1c634eba8eaa8ce7d3d7bc5f7e40c2fa
@@ -75,6 +81,6 @@   swift-petitparser: 3a4ef1e19bbf198200d73036459a9ce02a0a3068
   SwiftLint: 06ac37e4d38c7068e0935bb30cda95f093bec761
   SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e
 
-PODFILE CHECKSUM: 9f7b4c8019f51296ccb11fa33bd69b3b5ba4130c
+PODFILE CHECKSUM: 0278ff62d0de49df65f5f40495de585b301bc0b3
 
 COCOAPODS: 1.10.1