From 14487a1bebbfe1ffde908a6129b6cb5e1c37032d Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 8 Apr 2015 21:14:52 -0400 Subject: [PATCH] use int for enum --- SwiftIO/SocketEngine.swift | 374 ++++++++++++++++++------------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/SwiftIO/SocketEngine.swift b/SwiftIO/SocketEngine.swift index 6046650..eaca423 100644 --- a/SwiftIO/SocketEngine.swift +++ b/SwiftIO/SocketEngine.swift @@ -59,7 +59,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { var connected:Bool { return self._connected } - + weak var client:SocketEngineClient? var cookies:[NSHTTPCookie]? var pingInterval:Int? @@ -74,16 +74,24 @@ public class SocketEngine: NSObject, WebSocketDelegate { } var ws:WebSocket? - public enum PacketType:String { - case OPEN = "0" - case CLOSE = "1" - case PING = "2" - case PONG = "3" - case MESSAGE = "4" - case UPGRADE = "5" - case NOOP = "6" + public enum PacketType:Int { + case OPEN = 0 + case CLOSE = 1 + case PING = 2 + case PONG = 3 + case MESSAGE = 4 + case UPGRADE = 5 + case NOOP = 6 + + init(str:String) { + if let value = str.toInt() { + self = PacketType(rawValue: value)! + } else { + self = PacketType.NOOP + } + } } - + public init(client:SocketEngineClient, forcePolling:Bool, forceWebsockets:Bool, withCookies cookies:[NSHTTPCookie]?) { self.client = client @@ -93,19 +101,19 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(), delegate: nil, delegateQueue: self.workQueue) } - + public func close(#fast:Bool) { self.pingTimer?.invalidate() self.closed = true - + self.write("", withType: PacketType.CLOSE, withData: nil) self.ws?.disconnect() - + if fast || self.polling { self.client?.didForceClose("Disconnect") } } - + private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) { if self.websocket { var byteArray = [UInt8](count: 1, repeatedValue: 0x0) @@ -117,20 +125,20 @@ public class SocketEngine: NSObject, WebSocketDelegate { var str = "b4" str += data.base64EncodedStringWithOptions( NSDataBase64EncodingOptions.Encoding64CharacterLineLength) - + return (nil, str) } } - + private func createURLs(params:[String: AnyObject]?) -> (String, String) { if self.client == nil { return ("", "") } - + var url = "\(self.client!.socketURL)/socket.io/?transport=" var urlPolling:String var urlWebSocket:String - + if self.client!.secure { urlPolling = "https://" + url + "polling" urlWebSocket = "wss://" + url + "websocket" @@ -138,14 +146,14 @@ public class SocketEngine: NSObject, WebSocketDelegate { urlPolling = "http://" + url + "polling" urlWebSocket = "ws://" + url + "websocket" } - + if params != nil { for (key, value) in params! { let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters( NSCharacterSet.URLHostAllowedCharacterSet())! urlPolling += "&\(keyEsc)=" urlWebSocket += "&\(keyEsc)=" - + if value is String { let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters( NSCharacterSet.URLHostAllowedCharacterSet())! @@ -157,26 +165,26 @@ public class SocketEngine: NSObject, WebSocketDelegate { } } } - + return (urlPolling, urlWebSocket) } - + private func createWebsocket(andConnect connect:Bool) { self.ws = WebSocket(url: NSURL(string: self.urlWebSocket! + "&sid=\(self.sid)")!) self.ws?.queue = self.handleQueue self.ws?.delegate = self - + if connect { self.ws?.connect() } } - + private func doFastUpgrade() { if self.waitingForPoll { NSLog("Outstanding poll when switched to websockets," + "we'll probably disconnect soon. You should report this.") } - + self.sendWebSocketMessage("", withType: PacketType.UPGRADE, datas: nil) self._websocket = true self._polling = false @@ -184,25 +192,25 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.probing = false self.flushProbeWait() } - + private func doPoll() { if self.websocket || self.waitingForPoll || !self.connected { return } - + self.waitingForPoll = true let req = NSMutableURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)&b64=1")!) - + self.doRequest(req) } - + private func doRequest(req:NSMutableURLRequest) { if !self.polling { return } - + req.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData - + // NSLog("Doing request: \(req)") self.session.dataTaskWithRequest(req) {[weak self] data, res, err in if self == nil { @@ -213,21 +221,21 @@ public class SocketEngine: NSObject, WebSocketDelegate { } else { NSLog(err.localizedDescription) } - + return } - + // NSLog("Got response: \(res)") - + if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { dispatch_async(self!.parseQueue) { self?.parsePollingMessage(str) return } } - + self?.waitingForPoll = false - + if self!.fastUpgrade { self?.doFastUpgrade() return @@ -236,26 +244,26 @@ public class SocketEngine: NSObject, WebSocketDelegate { } }.resume() } - + private func flushProbeWait() { // NSLog("flushing probe wait") dispatch_async(self.emitQueue) {[weak self] in if self == nil { return } - + for waiter in self!.probeWait { self?.write(waiter.msg, withType: waiter.type, withData: waiter.data) } - + self?.probeWait.removeAll(keepCapacity: false) - + if self?.postWait.count != 0 { self?.flushWaitingForPostToWebSocket() } } } - + private func flushWaitingForPost() { if self.postWait.count == 0 || !self.connected { return @@ -263,33 +271,33 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.flushWaitingForPostToWebSocket() return } - + var postStr = "" - + for packet in self.postWait { let len = count(packet) - + postStr += "\(len):\(packet)" } - + self.postWait.removeAll(keepCapacity: false) - + let req = NSMutableURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!) - + req.HTTPMethod = "POST" req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") - + let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - + req.HTTPBody = postData req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") - + self.waitingForPost = true - + // NSLog("posting: \(postStr)") // NSLog("Posting with WS status of: \(self.websocket)") - + self.session.dataTaskWithRequest(req) {[weak self] data, res, err in if self == nil { return @@ -300,7 +308,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { NSLog(err.localizedDescription) return } - + self?.waitingForPost = false dispatch_async(self!.emitQueue) { if !self!.fastUpgrade { @@ -309,90 +317,90 @@ public class SocketEngine: NSObject, WebSocketDelegate { } }}.resume() } - + // We had packets waiting for send when we upgraded // Send them raw private func flushWaitingForPostToWebSocket() { for msg in self.postWait { self.ws?.writeString(msg) } - + self.postWait.removeAll(keepCapacity: true) } - + // A poll failed, tell the client about it - + private func handlePollingFailed(reason:String) { self._connected = false self.ws?.disconnect() self.pingTimer?.invalidate() self.waitingForPoll = false self.waitingForPost = false - + if self.client == nil { return } - + if !self.closed && !self.client!.reconnecting { self.client?.pollingDidFail(reason) } else if !self.client!.reconnecting { self.client?.didForceClose(reason) } } - + public func open(opts:[String: AnyObject]? = nil) { if self.connected { fatalError("Engine tried to open while connected") } - + self.closed = false let (urlPolling, urlWebSocket) = self.createURLs(opts) self.urlPolling = urlPolling self.urlWebSocket = urlWebSocket - + if self.forceWebsockets { self._polling = false self._websocket = true self.createWebsocket(andConnect: true) return } - + let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!) - + if self.cookies != nil { let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(self.cookies!) reqPolling.allHTTPHeaderFields = headers } - + self.doRequest(reqPolling) } - + // Translatation of engine.io-parser#decodePayload private func parsePollingMessage(str:String) { if str.length == 1 { return } - + // println(str) - + let strArray = Array(str) var length = "" var n = 0 var msg = "" - + func testLength(length:String, inout n:Int) -> Bool { if let num = length.toInt() { n = num } else { return true } - + return false } - + for var i = 0, l = str.length; i < l; i = i &+ 1 { let chr = String(strArray[i]) - + if chr != ":" { length += chr } else { @@ -401,16 +409,16 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.handlePollingFailed("Error parsing XHR message") return } - + msg = String(strArray[i&+1...i&+n]) - + if let lengthInt = length.toInt() { if lengthInt != msg.length { NSLog("parsing error: \(str)") return } } - + if msg.length != 0 { // Be sure to capture the value of the msg dispatch_async(self.handleQueue) {[weak self, msg] in @@ -418,134 +426,126 @@ public class SocketEngine: NSObject, WebSocketDelegate { return } } - + i += n length = "" } } } - + private func parseEngineData(data:NSData) { if self.client == nil { return } - + dispatch_async(self.client!.handleQueue) {[weak self] in self?.client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1))) return } } - + private func parseEngineMessage(var message:String, fromPolling:Bool) { // NSLog("Engine got message: \(message)") if fromPolling { fixDoubleUTF8(&message) } - - let type = message["^(\\d)"].groups()?[1] - - if type != PacketType.MESSAGE.rawValue { - // TODO Handle other packets + + let type = PacketType(str: (message["^(\\d)"].groups()?[1])!) + + if type == PacketType.MESSAGE { + // Remove message type + message.removeAtIndex(message.startIndex) + + if self.client == nil { + return + } + + dispatch_async(self.client!.handleQueue) {[weak self] in + self?.client?.parseSocketMessage(message) + return + } + } else if type == PacketType.NOOP { + self.doPoll() + return + } else if type == PacketType.PONG { + // We should upgrade + if message == "3probe" { + self.upgradeTransport() + return + } + + return + } else if type == PacketType.OPEN { + var err:NSError? + + message.removeAtIndex(message.startIndex) + let mesData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + + if let json = NSJSONSerialization.JSONObjectWithData(mesData, + options: NSJSONReadingOptions.AllowFragments, error: &err) as? NSDictionary { + if let sid = json["sid"] as? String { + // println(json) + self.sid = sid + self._connected = true + if !self.forcePolling && !self.forceWebsockets { + self.createWebsocket(andConnect: true) + } + } else { + NSLog("Error handshaking") + return + } + + if let pingInterval = json["pingInterval"] as? Int { + self.pingInterval = pingInterval / 1000 + } + } else { + fatalError("Error parsing engine connect") + } + + self.startPingTimer() + + if !self.forceWebsockets { + self.doPoll() + } + + return + } else if type == PacketType.CLOSE { + if self.client == nil { + return + } + + if self.polling { + self.client!.didForceClose("Disconnect") + } + + return + } else { if message.hasPrefix("b4") { // binary in base64 string - + message.removeRange(Range(start: message.startIndex, end: advance(message.startIndex, 2))) - + if let data = NSData(base64EncodedString: message, - options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) { + options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) + where self.client != nil { // println("sending \(data)") - - if self.client == nil { - return - } - + dispatch_async(self.client!.handleQueue) {[weak self] in self?.client?.parseBinaryData(data) return } } - - return - } else if type == PacketType.NOOP.rawValue { - self.doPoll() - return - } else if type == PacketType.PONG.rawValue { - // We should upgrade - if message == "3probe" { - self.upgradeTransport() - return - } - - return - } else if type == PacketType.OPEN.rawValue { - var err:NSError? - - message.removeAtIndex(message.startIndex) - let mesData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - - if let json = NSJSONSerialization.JSONObjectWithData(mesData, - options: NSJSONReadingOptions.AllowFragments, error: &err) as? NSDictionary { - if let sid = json["sid"] as? String { - // println(json) - self.sid = sid - self._connected = true - if !self.forcePolling && !self.forceWebsockets { - self.createWebsocket(andConnect: true) - } - } else { - NSLog("Error handshaking") - return - } - - if let pingInterval = json["pingInterval"] as? Int { - self.pingInterval = pingInterval / 1000 - } - } else { - fatalError("Error parsing engine connect") - } - - self.startPingTimer() - - if !self.forceWebsockets { - self.doPoll() - } - - return - } else if type == PacketType.CLOSE.rawValue { - if self.client == nil { - return - } - - if self.polling { - self.client!.didForceClose("Disconnect") - } - - return } - // println("Got something idk what to do with") - // println(messageString) - } - - // Remove message type - message.removeAtIndex(message.startIndex) - - if self.client == nil { - return - } - - dispatch_async(self.client!.handleQueue) {[weak self] in - self?.client?.parseSocketMessage(message) - return } } - + private func probeWebSocket() { if self.websocketConnected { self.sendWebSocketMessage("probe", withType: PacketType.PING) } } - + /// Send an engine message (4) public func send(msg:String, withData datas:ContiguousArray?) { if self.probing { @@ -554,11 +554,11 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.write(msg, withType: PacketType.MESSAGE, withData: datas) } } - + func sendPing() { self.write("", withType: PacketType.PING, withData: nil) } - + /// Send polling message. /// Only call on emitQueue private func sendPollMessage(var msg:String, withType type:PacketType, @@ -566,29 +566,29 @@ public class SocketEngine: NSObject, WebSocketDelegate { // println("Sending poll: \(msg) as type: \(type.rawValue)") doubleEncodeUTF8(&msg) let strMsg = "\(type.rawValue)\(msg)" - + self.postWait.append(strMsg) - + if datas != nil { for data in datas! { let (nilData, b64Data) = self.createBinaryDataForSend(data) - + self.postWait.append(b64Data!) } } - + if !self.waitingForPost { self.flushWaitingForPost() } } - + /// Send message on WebSockets /// Only call on emitQueue private func sendWebSocketMessage(str:String, withType type:PacketType, datas:ContiguousArray? = nil) { // println("Sending ws: \(str) as type: \(type.rawValue)") self.ws?.writeString("\(type.rawValue)\(str)") - + if datas != nil { for data in datas! { let (data, nilString) = self.createBinaryDataForSend(data) @@ -598,13 +598,13 @@ public class SocketEngine: NSObject, WebSocketDelegate { } } } - + // Starts the ping timer private func startPingTimer() { if self.pingInterval == nil { return } - + self.pingTimer?.invalidate() dispatch_async(dispatch_get_main_queue()) { self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(self.pingInterval!), @@ -612,7 +612,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { selector: Selector("sendPing"), userInfo: nil, repeats: true) } } - + private func upgradeTransport() { if self.websocketConnected { // NSLog("Doing fast upgrade") @@ -622,13 +622,13 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.sendPollMessage("", withType: PacketType.NOOP) } } - + public func write(msg:String, withType type:PacketType, withData data:ContiguousArray?) { dispatch_async(self.emitQueue) {[weak self] in if self == nil || !self!.connected { return } - + if self!.websocket { // NSLog("writing ws: \(msg):\(data)") self?.sendWebSocketMessage(msg, withType: type, datas: data) @@ -638,12 +638,12 @@ public class SocketEngine: NSObject, WebSocketDelegate { } } } - + // Delagate methods - + public func websocketDidConnect(socket:WebSocket) { self.websocketConnected = true - + if !self.forceWebsockets { self.probing = true self.probeWebSocket() @@ -653,21 +653,21 @@ public class SocketEngine: NSObject, WebSocketDelegate { self._polling = false } } - + public func websocketDidDisconnect(socket:WebSocket, error:NSError?) { self.websocketConnected = false self.probing = false - + if self.closed { self.client?.didForceClose("Disconnect") return } - + if self.websocket { self.pingTimer?.invalidate() self._connected = false self._websocket = false - + let reason = error?.localizedDescription self.client?.webSocketDidCloseWithCode(1, reason: reason == nil ? "Socket Disconnected" : reason!) @@ -675,11 +675,11 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.flushProbeWait() } } - + public func websocketDidReceiveMessage(socket:WebSocket, text:String) { self.parseEngineMessage(text, fromPolling: false) } - + public func websocketDidReceiveData(socket:WebSocket, data:NSData) { self.parseEngineData(data) }