Merge pull request #192 from socketio/either

Either
This commit is contained in:
Erik Little 2015-09-25 09:29:02 -04:00
commit 4ae6489230
4 changed files with 82 additions and 81 deletions

View File

@ -68,7 +68,12 @@ class SocketParserTest: XCTestCase {
func testInvalidInput() {
let message = "8"
XCTAssertNil(SocketParser.parseString(message))
switch SocketParser.parseString(message) {
case .Left(_):
return
case .Right(_):
XCTFail("Created packet when shouldn't have")
}
}
func testGenericParser() {
@ -83,7 +88,7 @@ class SocketParserTest: XCTestCase {
let validValues = SocketParserTest.packetTypes[message]!
let packet = SocketParser.parseString(message)
let type = message.substringWithRange(Range<String.Index>(start: message.startIndex, end: message.startIndex.advancedBy(1)))
if let packet = packet {
if case let .Right(packet) = packet {
XCTAssertEqual(packet.type, SocketPacket.PacketType(str:type)!)
XCTAssertEqual(packet.nsp, validValues.0)
XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1))

View File

@ -65,8 +65,9 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
var cookies: [NSHTTPCookie]?
var sid = ""
var socketPath = ""
var urlPolling: String?
var urlWebSocket: String?
var urlPolling = ""
var urlWebSocket = ""
var ws: WebSocket?
@objc public enum PacketType: Int {
@ -129,7 +130,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
stopPolling()
}
private func createBinaryDataForSend(data: NSData) -> (NSData?, String?) {
private func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
byteArray[0] = 4
@ -137,23 +138,22 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
mutData.appendData(data)
return (mutData, nil)
return .Left(mutData)
} else {
var str = "b4"
str += data.base64EncodedStringWithOptions(
NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
return (nil, str)
return .Right(str)
}
}
private func createURLs(params: [String: AnyObject]?) -> (String?, String?) {
private func createURLs(params: [String: AnyObject]?) -> (String, String) {
if client == nil {
return (nil, nil)
return ("", "")
}
let path = socketPath == "" ? "/socket.io" : socketPath
let url = "\(client!.socketURL)\(path)/?transport="
var urlPolling: String
var urlWebSocket: String
@ -189,7 +189,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
}
private func createWebsocket(andConnect connect: Bool) {
let wsUrl = urlWebSocket! + (sid == "" ? "" : "&sid=\(sid)")
let wsUrl = urlWebSocket + (sid == "" ? "" : "&sid=\(sid)")
ws = WebSocket(url: NSURL(string: wsUrl)!,
cookies: cookies)
@ -228,7 +228,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
}
waitingForPoll = true
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)&b64=1")!)
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
@ -318,7 +318,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
postWait.removeAll(keepCapacity: false)
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!)
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!)
if let cookies = cookies {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
@ -468,7 +468,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
return
}
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&b64=1")!)
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
@ -581,9 +581,9 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
postWait.append(strMsg)
for data in datas ?? [] {
let (_, b64Data) = createBinaryDataForSend(data)
postWait.append(b64Data!)
if case let .Right(bin) = createBinaryDataForSend(data) {
postWait.append(bin)
}
}
if !waitingForPost {
@ -600,9 +600,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate {
ws?.writeString("\(type.rawValue)\(str)")
for data in datas ?? [] {
let (data, _) = createBinaryDataForSend(data)
if data != nil {
ws?.writeData(data!)
if case let Either.Left(bin) = createBinaryDataForSend(data) {
ws?.writeData(bin)
}
}
}

View File

@ -27,26 +27,7 @@ class SocketParser {
private static func isCorrectNamespace(nsp: String, _ socket: SocketIOClient) -> Bool {
return nsp == socket.nsp
}
private static func handleEvent(p: SocketPacket, socket: SocketIOClient) {
guard isCorrectNamespace(p.nsp, socket) else { return }
socket.handleEvent(p.event, data: p.args ?? [],
isInternalMessage: false, wantsAck: p.id)
}
private static func handleAck(p: SocketPacket, socket: SocketIOClient) {
guard isCorrectNamespace(p.nsp, socket) else { return }
socket.handleAck(p.id, data: p.data)
}
private static func handleBinary(p: SocketPacket, socket: SocketIOClient) {
guard isCorrectNamespace(p.nsp, socket) else { return }
socket.waitingData.append(p)
}
private static func handleConnect(p: SocketPacket, socket: SocketIOClient) {
if p.nsp == "/" && socket.nsp != "/" {
socket.joinNamespace()
@ -57,14 +38,37 @@ class SocketParser {
}
}
static func parseString(message: String) -> SocketPacket? {
private static func handlePacket(pack: SocketPacket, withSocket socket: SocketIOClient) {
guard isCorrectNamespace(pack.nsp, socket) else { return }
switch pack.type {
case .Event:
socket.handleEvent(pack.event, data: pack.args ?? [],
isInternalMessage: false, wantsAck: pack.id)
case .Ack:
socket.handleAck(pack.id, data: pack.data)
case .BinaryEvent:
socket.waitingData.append(pack)
case .BinaryAck:
socket.waitingData.append(pack)
case .Connect:
handleConnect(pack, socket: socket)
case .Disconnect:
socket.didDisconnect("Got Disconnect")
case .Error:
socket.didError("Error: \(pack.data)")
}
}
static func parseString(message: String) -> Either<String, SocketPacket> {
var parser = SocketStringReader(message: message)
guard let type = SocketPacket.PacketType(str: parser.read(1))
else {return nil}
guard let type = SocketPacket.PacketType(str: parser.read(1)) else {
return .Left("Invalid packet type")
}
if !parser.hasNext {
return SocketPacket(type: type, nsp: "/")
return .Right(SocketPacket(type: type, nsp: "/"))
}
var namespace: String?
@ -74,7 +78,7 @@ class SocketParser {
if let holders = Int(parser.readUntilStringOccurence("-")) {
placeholders = holders
} else {
return nil
return .Left("Invalid packet")
}
}
@ -83,8 +87,8 @@ class SocketParser {
}
if !parser.hasNext {
return SocketPacket(type: type, id: -1,
nsp: namespace ?? "/", placeholders: placeholders)
return .Right(SocketPacket(type: type, id: -1,
nsp: namespace ?? "/", placeholders: placeholders))
}
var idString = ""
@ -100,21 +104,28 @@ class SocketParser {
let d = message[parser.currentIndex.advancedBy(1)..<message.endIndex]
let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] ~= "\"~~$2\""
let data = parseData(noPlaceholders) as? [AnyObject] ?? [noPlaceholders]
return SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders)
switch parseData(noPlaceholders) {
case .Left(let err):
return .Left(err)
case .Right(let data):
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders))
}
}
// Parses data for events
static func parseData(data: String) -> AnyObject? {
private static func parseData(data: String) -> Either<String, [AnyObject]> {
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
do {
return try NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.MutableContainers)
if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] {
return .Right(arr)
} else {
return .Left("Expected data array")
}
} catch {
Logger.error("Parsing JSON: %@", type: "SocketParser", args: data)
return nil
return .Left("Error parsing data for packet")
}
}
@ -124,30 +135,13 @@ class SocketParser {
Logger.log("Parsing %@", type: "SocketParser", args: message)
guard let pack = parseString(message) else {
Logger.error("Parsing message: %@", type: "SocketParser", args: message)
return
switch parseString(message) {
case .Left(let err):
Logger.error("\(err): %@", type: "SocketParser", args: message)
case .Right(let pack):
Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
handlePacket(pack, withSocket: socket)
}
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:
handleBinary(pack, socket: socket)
case .BinaryAck:
handleBinary(pack, socket: socket)
case .Connect:
handleConnect(pack, socket: socket)
case .Disconnect:
socket.didDisconnect("Got Disconnect")
case .Error:
socket.didError("Error: \(pack.data)")
}
}
static func parseBinaryData(data: NSData, socket: SocketIOClient) {
@ -156,9 +150,8 @@ class SocketParser {
return
}
let shouldExecute = socket.waitingData[socket.waitingData.count - 1].addData(data)
guard shouldExecute else {
// Should execute event?
guard socket.waitingData[socket.waitingData.count - 1].addData(data) else {
return
}

View File

@ -28,3 +28,7 @@ public typealias AckCallback = ([AnyObject]) -> Void
public typealias NormalCallback = ([AnyObject], SocketAckEmitter?) -> Void
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void
enum Either<E, V> {
case Left(E)
case Right(V)
}