From 2bd612e47a0b875f5b61bfa2720f46c965b597e0 Mon Sep 17 00:00:00 2001 From: Lukas Schmidt Date: Mon, 7 Sep 2015 15:08:10 +0200 Subject: [PATCH] refactor, make use of try catch --- GenericSocketParser.swift | 48 ++++++++ .../project.pbxproj | 6 + SocketIO-iOSTests/SocketParserTest.swift | 32 +++-- SocketIOClientSwift/SocketParser.swift | 112 +++++++----------- 4 files changed, 109 insertions(+), 89 deletions(-) create mode 100644 GenericSocketParser.swift diff --git a/GenericSocketParser.swift b/GenericSocketParser.swift new file mode 100644 index 0000000..4ab7d9c --- /dev/null +++ b/GenericSocketParser.swift @@ -0,0 +1,48 @@ +// +// GenericSocketParser.swift +// Socket.IO-Client-Swift +// +// Created by Lukas Schmidt on 07.09.15. +// +// + +import Foundation + +struct GenericParser { + let message: String + var currentIndex:Int + var messageCharacters: Array { + get { + return Array(message.characters) + } + } + var currentCharacter: String? { + get{ + if currentIndex >= messageCharacters.count { + return nil + } + return String(messageCharacters[currentIndex]) + } + } + + mutating func read(characterLength:Int) -> String? { + let startIndex = message.startIndex.advancedBy(currentIndex) + let range = Range(start: startIndex, end: startIndex.advancedBy(characterLength)) + currentIndex = currentIndex + characterLength + + return message.substringWithRange(range) + } + + mutating func readUntilStringOccurence(string:String) -> String? { + let startIndex = message.startIndex.advancedBy(currentIndex) + let range = Range(start: startIndex, end: message.endIndex) + let subString = message.substringWithRange(range) as NSString + let foundRange = subString.rangeOfString(string) + if foundRange.location == Int.max { + return nil + } + currentIndex = currentIndex + foundRange.location + + return subString.substringToIndex(foundRange.location) + } +} \ No newline at end of file diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index 7eb4cd2..d49cac7 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -43,6 +43,8 @@ 74781D5C1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; }; 74781D5D1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */; }; 941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A4AB91B67A56C00C42318 /* TestKind.swift */; }; + 9421F5D01B9DBF5900D625BB /* GenericSocketParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9421F5CF1B9DBF5900D625BB /* GenericSocketParser.swift */; settings = {ASSET_TAGS = (); }; }; + 9421F5D11B9DBF5900D625BB /* GenericSocketParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9421F5CF1B9DBF5900D625BB /* GenericSocketParser.swift */; settings = {ASSET_TAGS = (); }; }; 94242BB81B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */; }; 945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7C1B51F254004FF46E /* SocketAckManager.swift */; }; 945B65361B5FCEEA0081E995 /* SocketAnyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5764DF7D1B51F254004FF46E /* SocketAnyEvent.swift */; }; @@ -110,6 +112,7 @@ 5764DF881B51F254004FF46E /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = SocketIOClientSwift/WebSocket.swift; sourceTree = ""; }; 74781D591B7E83930042CACA /* SocketIOClientStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientStatus.swift; path = SocketIOClientSwift/SocketIOClientStatus.swift; sourceTree = ""; }; 941A4AB91B67A56C00C42318 /* TestKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestKind.swift; sourceTree = ""; }; + 9421F5CF1B9DBF5900D625BB /* GenericSocketParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericSocketParser.swift; sourceTree = ""; }; 94242BB71B67B0E500AAAC9D /* SocketNamespaceAcknowledgementTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespaceAcknowledgementTest.swift; sourceTree = ""; }; 945B65421B63D9DB0081E995 /* SocketEmitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEmitTest.swift; sourceTree = ""; }; 949FAE8C1B9B94E600073BE9 /* SocketParserTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = ""; }; @@ -267,6 +270,7 @@ 5764DF831B51F254004FF46E /* SocketLogger.swift */, 5764DF841B51F254004FF46E /* SocketPacket.swift */, 5764DF851B51F254004FF46E /* SocketParser.swift */, + 9421F5CF1B9DBF5900D625BB /* GenericSocketParser.swift */, 5764DF861B51F254004FF46E /* SocketTypes.swift */, 5764DF871B51F254004FF46E /* SwiftRegex.swift */, 5764DF881B51F254004FF46E /* WebSocket.swift */, @@ -454,6 +458,7 @@ 5764DF911B51F254004FF46E /* SocketEventHandler.swift in Sources */, 5764DF931B51F254004FF46E /* SocketFixUTF8.swift in Sources */, 5764DF951B51F254004FF46E /* SocketIOClient.swift in Sources */, + 9421F5D01B9DBF5900D625BB /* GenericSocketParser.swift in Sources */, 5764DF8B1B51F254004FF46E /* SocketAnyEvent.swift in Sources */, 5764DF971B51F254004FF46E /* SocketLogger.swift in Sources */, 74781D5A1B7E83930042CACA /* SocketIOClientStatus.swift in Sources */, @@ -475,6 +480,7 @@ 94CB8F0B1B6E48B90019ED53 /* SocketTestCases.swift in Sources */, 945B65371B5FCEEA0081E995 /* SocketEngine.swift in Sources */, 945B65351B5FCEEA0081E995 /* SocketAckManager.swift in Sources */, + 9421F5D11B9DBF5900D625BB /* GenericSocketParser.swift in Sources */, 941A4ABA1B67A56C00C42318 /* TestKind.swift in Sources */, 94CB8F0D1B6E66E60019ED53 /* AbstractSocketTest.swift in Sources */, 945B65431B63D9DB0081E995 /* SocketEmitTest.swift in Sources */, diff --git a/SocketIO-iOSTests/SocketParserTest.swift b/SocketIO-iOSTests/SocketParserTest.swift index 362c71f..83ffc05 100644 --- a/SocketIO-iOSTests/SocketParserTest.swift +++ b/SocketIO-iOSTests/SocketParserTest.swift @@ -17,8 +17,7 @@ class SocketParserTest: XCTestCase { "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], -1), "3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"]], [], 0), "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", [ [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], 19), - "4/swift,": ("/swift", [], [], -1), - "10": ("/swift", [], [], -1)] + "4/swift,": ("/swift", [], [], -1)] func testDisconnect() { let message = "1" @@ -57,8 +56,12 @@ class SocketParserTest: XCTestCase { func testInvalidInput() { let message = "8" - let packet = SocketParser.parseString(message) - XCTAssertNil(packet) + do { + try SocketParser.parseString(message) + XCTFail("Should throw exeption") + } catch { + + } } func testGenericParser() { @@ -66,32 +69,27 @@ class SocketParserTest: XCTestCase { XCTAssertEqual(parser.read(1), "6") XCTAssertEqual(parser.currentCharacter, "1") XCTAssertEqual(parser.readUntilStringOccurence("-"), "1") - XCTAssertEqual(parser.currentCharacter, "-") + XCTAssertEqual(parser.currentCharacter, "-") } func validateParseResult(message:String) { let validValues = SocketParserTest.packetTypes[message]! - let packet = SocketParser.parseString(message) + let packet = try! SocketParser.parseString(message) let type = message.substringWithRange(Range(start: message.startIndex, end: message.startIndex.advancedBy(1))) - if let packet = packet { - XCTAssertEqual(packet.type, SocketPacket.PacketType(str:type)!) - XCTAssertEqual(packet.nsp, validValues.0) - XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1)) - XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2)) - XCTAssertEqual(packet.id, validValues.3) - }else { - XCTFail() - } + XCTAssertEqual(packet.type, SocketPacket.PacketType(str:type)!) + XCTAssertEqual(packet.nsp, validValues.0) + XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1)) + XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2)) + XCTAssertEqual(packet.id, validValues.3) } func testParsePerformance() { let keys = Array(SocketParserTest.packetTypes.keys) measureBlock({ for item in keys.enumerate() { - SocketParser.parseString(item.element) + try! SocketParser.parseString(item.element) } }) - } } diff --git a/SocketIOClientSwift/SocketParser.swift b/SocketIOClientSwift/SocketParser.swift index 31db9db..05c0658 100644 --- a/SocketIOClientSwift/SocketParser.swift +++ b/SocketIOClientSwift/SocketParser.swift @@ -22,43 +22,8 @@ import Foundation -struct GenericParser { - let message: String - var currentIndex:Int - var messageCharacters: Array { - get { - return Array(message.characters) - } - } - var currentCharacter: String? { - get{ - if currentIndex >= messageCharacters.count { - return nil - } - return String(messageCharacters[currentIndex]) - } - } - - mutating func read(characterLength:Int) -> String? { - let startIndex = message.startIndex.advancedBy(currentIndex) - let range = Range(start: startIndex, end: startIndex.advancedBy(characterLength)) - currentIndex = currentIndex + characterLength - - return message.substringWithRange(range) - } - - mutating func readUntilStringOccurence(string:String) -> String? { - let startIndex = message.startIndex.advancedBy(currentIndex) - let range = Range(start: startIndex, end: message.endIndex) - let subString = message.substringWithRange(range) as NSString - let foundRange = subString.rangeOfString(string) - if foundRange.location == Int.max { - return nil - } - currentIndex = currentIndex + foundRange.location - - return subString.substringToIndex(foundRange.location) - } +enum SocketParserError: ErrorType { + case InvalidMessageType, InvalidBinaryPalceholder } class SocketParser { @@ -111,12 +76,12 @@ class SocketParser { } // Translation of socket.io-client#decodeString - static func parseString(str: String) -> SocketPacket? { + static func parseString(str: String) throws -> SocketPacket { var parser = GenericParser(message: str, currentIndex: 0) let messageCharacters = Array(str.characters) guard let typeString = parser.read(1), let type = SocketPacket.PacketType(str: typeString) else { - NSLog("Error parsing \(str)") - return nil} + throw SocketParserError.InvalidMessageType + } if messageCharacters.count == 1 { return SocketPacket(type: type, nsp: "/") @@ -129,8 +94,7 @@ class SocketParser { if let buffer = parser.readUntilStringOccurence("-"), let holders = Int(buffer) where parser.read(1)! == "-" { placeholders = holders } else { - NSLog("Error parsing \(str)") - return nil + throw SocketParserError.InvalidBinaryPalceholder } } if parser.currentCharacter == "/" { @@ -154,16 +118,12 @@ class SocketParser { } } - if parser.currentIndex < messageCharacters.count { - let d = str[str.startIndex.advancedBy(parser.currentIndex + 1)...str.startIndex.advancedBy(str.characters.count-1)] - let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\"" - let data = SocketParser.parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders] - - return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, - nsp: nsp ?? "/", placeholders: placeholders) - } + let d = str[str.startIndex.advancedBy(parser.currentIndex + 1)...str.startIndex.advancedBy(str.characters.count - 1)] + let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\"" + let data = SocketParser.parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders] - return nil + return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, + nsp: nsp ?? "/", placeholders: placeholders) } // Parses data for events @@ -184,29 +144,37 @@ class SocketParser { Logger.log("Parsing %@", type: "SocketParser", args: stringMessage) - guard let pack = parseString(stringMessage) else { - socket.didError("Error parsing packet") - return + do { + let pack = try parseString(stringMessage) + Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description) + + switch pack.type { + case .Event: + handleEvent(pack, socket: socket) + case .Ack: + handleAck(pack, socket: socket) + case .BinaryEvent: + handleBinaryEvent(pack, socket: socket) + case .BinaryAck: + handleBinaryAck(pack, socket: socket) + case .Connect: + handleConnect(pack, socket: socket) + case .Disconnect: + socket.didDisconnect("Got Disconnect") + case .Error: + socket.didError("Error: \(pack.data)") + } + + }catch SocketParserError.InvalidBinaryPalceholder { + Logger.error("Parsed Invalid Binary Placeholder", type: "SocketParser") } - - Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description) - - switch pack.type { - case .Event: - handleEvent(pack, socket: socket) - case .Ack: - handleAck(pack, socket: socket) - case .BinaryEvent: - handleBinaryEvent(pack, socket: socket) - case .BinaryAck: - handleBinaryAck(pack, socket: socket) - case .Connect: - handleConnect(pack, socket: socket) - case .Disconnect: - socket.didDisconnect("Got Disconnect") - case .Error: - socket.didError("Error: \(pack.data)") + catch SocketParserError.InvalidMessageType { + Logger.error("Parsed Invalid Binary Placeholder", type: "SocketParser") } + catch { + + } + } static func parseBinaryData(data: NSData, socket: SocketIOClient) {