This commit is contained in:
Erik 2015-03-12 13:38:06 -04:00
parent ab5cccce85
commit 74939f1cea
2 changed files with 145 additions and 135 deletions

View File

@ -24,10 +24,6 @@
import Foundation import Foundation
// This is used because in Swift 1.1, turning on -O causes a
// memory access violation in SocketEngine#parseEngineMessage
private var fixSwift:AnyObject?
extension String { extension String {
private var length:Int { private var length:Int {
return countElements(self) return countElements(self)
@ -55,18 +51,22 @@ class SocketEngine: NSObject, WebSocketDelegate {
"parseQueue".cStringUsingEncoding(NSUTF8StringEncoding), DISPATCH_QUEUE_SERIAL) "parseQueue".cStringUsingEncoding(NSUTF8StringEncoding), DISPATCH_QUEUE_SERIAL)
private let handleQueue = dispatch_queue_create( private let handleQueue = dispatch_queue_create(
"handleQueue".cStringUsingEncoding(NSUTF8StringEncoding), DISPATCH_QUEUE_SERIAL) "handleQueue".cStringUsingEncoding(NSUTF8StringEncoding), DISPATCH_QUEUE_SERIAL)
private let session:NSURLSession!
private var _connected = false
private var fastUpgrade = false
private var forcePolling = false private var forcePolling = false
private var pingTimer:NSTimer? private var pingTimer:NSTimer?
private var postWait = [String]() private var postWait = [String]()
private var _polling = true private var _polling = true
private var probing = false private var probing = false
private var probeWait = PollWaitQueue() private var probeWait = PollWaitQueue()
private let session:NSURLSession!
private var waitingForPoll = false private var waitingForPoll = false
private var waitingForPost = false private var waitingForPost = false
private var _websocket = false private var _websocket = false
private var websocketConnected = false private var websocketConnected = false
var connected = false var connected:Bool {
return self._connected
}
var pingInterval:Int? var pingInterval:Int?
var polling:Bool { var polling:Bool {
return self._polling return self._polling
@ -142,14 +142,29 @@ class SocketEngine: NSObject, WebSocketDelegate {
return (urlPolling, urlWebSocket) return (urlPolling, urlWebSocket)
} }
private func doFastUpgrade() {
self.sendWebSocketMessage("", withType: PacketType.UPGRADE)
self._websocket = true
self._polling = false
self.fastUpgrade = false
self.flushProbeWait()
}
private func doPoll() { private func doPoll() {
if self.urlPolling == nil || self.websocket || self.waitingForPoll || !self.connected { if self.websocket || self.waitingForPoll || !self.connected {
return return
} }
let req = NSMutableURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!)
req.timeoutInterval = 0.0
self.waitingForPoll = true self.waitingForPoll = true
self.doRequest(self.parsePollingMessage)
}
private func doRequest(callback:(String) -> Void) {
if !self.polling {
return
}
let req = NSURLRequest(URL: NSURL(string: self.urlPolling! + "&sid=\(self.sid)")!)
self.session.dataTaskWithRequest(req) {[weak self] data, res, err in self.session.dataTaskWithRequest(req) {[weak self] data, res, err in
if self == nil { if self == nil {
@ -158,29 +173,31 @@ class SocketEngine: NSObject, WebSocketDelegate {
if self!.polling { if self!.polling {
self?.handlePollingFailed(err) self?.handlePollingFailed(err)
} }
return return
} }
// println(data) // println(data)
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String { if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
// println(str) // println(str)
dispatch_async(self!.parseQueue) {[weak self] in
if self == nil {
return
}
self?.parsePollingMessage(str) dispatch_async(self!.parseQueue) {callback(str)}
return
}
} }
self?.waitingForPoll = false self?.waitingForPoll = false
if self!.fastUpgrade {
self?.doFastUpgrade()
return
} else {
self?.doPoll() self?.doPoll()
}
}.resume() }.resume()
} }
private func flushProbeWait() { private func flushProbeWait() {
// println("flushing probe wait") // println("flushing probe wait")
dispatch_async(self.emitQueue) {[weak self] in dispatch_async(self.emitQueue) {[weak self] in
@ -227,7 +244,6 @@ class SocketEngine: NSObject, WebSocketDelegate {
req.HTTPBody = postData req.HTTPBody = postData
self.waitingForPost = true self.waitingForPost = true
self.session.dataTaskWithRequest(req) {[weak self] data, res, err in self.session.dataTaskWithRequest(req) {[weak self] data, res, err in
if self == nil { if self == nil {
return return
@ -255,10 +271,11 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
// A poll failed, tell the client about it // A poll failed, tell the client about it
// We check to see if we were closed by the server first
private func handlePollingFailed(reason:NSError?) { private func handlePollingFailed(reason:NSError?) {
assert(self.polling, "Polling failed when we're not polling")
if !self.client.reconnecting { if !self.client.reconnecting {
self.connected = false self._connected = false
self.ws?.disconnect() self.ws?.disconnect()
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
self.waitingForPoll = false self.waitingForPoll = false
@ -268,7 +285,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
func open(opts:[String: AnyObject]? = nil) { func open(opts:[String: AnyObject]? = nil) {
if self.waitingForPost || self.waitingForPoll || self.websocket || self.connected { if self.connected {
assert(false, "We're in a bad state, this shouldn't happen.") assert(false, "We're in a bad state, this shouldn't happen.")
} }
@ -304,13 +321,12 @@ class SocketEngine: NSObject, WebSocketDelegate {
return return
} }
self?.connected = true
if let json = NSJSONSerialization.JSONObjectWithData(jsonData!, if let json = NSJSONSerialization.JSONObjectWithData(jsonData!,
options: NSJSONReadingOptions.AllowFragments, error: &err2) as? NSDictionary { options: NSJSONReadingOptions.AllowFragments, error: &err2) as? NSDictionary {
if let sid = json["sid"] as? String { if let sid = json["sid"] as? String {
// println(json) // println(json)
self?.sid = sid self?.sid = sid
self?._connected = true
if !self!.forcePolling { if !self!.forcePolling {
self?.ws = WebSocket(url: NSURL(string: urlWebSocket + "&sid=\(self!.sid)")!) self?.ws = WebSocket(url: NSURL(string: urlWebSocket + "&sid=\(self!.sid)")!)
@ -363,7 +379,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
length += chr length += chr
} else { } else {
if length == "" || testLength(length, &n) { if length == "" || testLength(length, &n) {
self.handlePollingFailed(nil) println("failure in parsePollingMessage")
return return
} }
@ -379,10 +395,8 @@ class SocketEngine: NSObject, WebSocketDelegate {
if msg.length != 0 { if msg.length != 0 {
// Be sure to capture the value of the msg // Be sure to capture the value of the msg
dispatch_async(self.handleQueue) {[weak self, msg] in dispatch_async(self.handleQueue) {[weak self, msg] in
fixSwift = msg self?.parseEngineMessage(msg)
if fixSwift is String { return
self?.parseEngineMessage(fixSwift as String)
}
} }
} }
@ -462,7 +476,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
self?.sendWebSocketMessage(msg, withType: PacketType.MESSAGE, datas: datas) self?.sendWebSocketMessage(msg, withType: PacketType.MESSAGE, datas: datas)
} else { } else {
// println("sending poll: \(msg):\(datas)") // println("sending poll: \(msg):\(datas)")
self?.sendPollMessage(msg, withType: PacketType.MESSAGE, datas: datas) self?.sendPollMessage(msg, withType: PacketType.MESSAGE, datas: datas, doPoll: true)
} }
} }
} }
@ -484,12 +498,13 @@ class SocketEngine: NSObject, WebSocketDelegate {
if self.websocket { if self.websocket {
self.sendWebSocketMessage("", withType: PacketType.PING) self.sendWebSocketMessage("", withType: PacketType.PING)
} else { } else {
self.sendPollMessage("", withType: PacketType.PING) self.sendPollMessage("", withType: PacketType.PING, doPoll: false)
} }
} }
private func sendPollMessage(msg:String, withType type:PacketType, datas:[NSData]? = nil) { private func sendPollMessage(msg:String, withType type:PacketType,
// println("Sending: poll: \(msg) as type: \(type.rawValue)") datas:[NSData]? = nil, doPoll poll:Bool) {
// println("Sending poll: \(msg) as type: \(type.rawValue)")
let strMsg = "\(type.rawValue)\(msg)" let strMsg = "\(type.rawValue)\(msg)"
self.postWait.append(strMsg) self.postWait.append(strMsg)
@ -502,16 +517,15 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
if waitingForPost { if !self.waitingForPoll && self.waitingForPost && poll {
self.doPoll() self.doPoll()
return
} else { } else {
self.flushWaitingForPost() self.flushWaitingForPost()
} }
} }
private func sendWebSocketMessage(str:String, withType type:PacketType, datas:[NSData]? = nil) { private func sendWebSocketMessage(str:String, withType type:PacketType, datas:[NSData]? = nil) {
// println("Sending: ws: \(str) as type: \(type.rawValue)") // println("Sending ws: \(str) as type: \(type.rawValue)")
self.ws?.writeString("\(type.rawValue)\(str)") self.ws?.writeString("\(type.rawValue)\(str)")
if datas != nil { if datas != nil {
@ -539,12 +553,10 @@ class SocketEngine: NSObject, WebSocketDelegate {
private func upgradeTransport() { private func upgradeTransport() {
if self.websocketConnected { if self.websocketConnected {
// Do a fast upgrade
self.fastUpgrade = true
self.probing = false self.probing = false
self._websocket = true self.sendPollMessage("", withType: PacketType.NOOP, doPoll: false)
self.waitingForPoll = false
self._polling = false
self.sendWebSocketMessage("", withType: PacketType.UPGRADE)
self.flushProbeWait()
} }
} }
@ -560,7 +572,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
if self.websocket { if self.websocket {
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
self.connected = false self._connected = false
self._websocket = false self._websocket = false
self._polling = true self._polling = true
self.client.webSocketDidCloseWithCode(1, reason: "Socket Disconnect", wasClean: true) self.client.webSocketDidCloseWithCode(1, reason: "Socket Disconnect", wasClean: true)

View File

@ -643,10 +643,9 @@ public class SocketIOClient: NSObject {
} }
// Tries to parse a message that contains binary // Tries to parse a message that contains binary
private func parseBinaryMessage(#message:AnyObject) { private func parseBinaryMessage(#message:String) {
// println(message) // println(message)
if let stringMessage = message as? String { var mutMessage = RegexMutable(message)
var mutMessage = RegexMutable(stringMessage)
/** /**
Begin check for binary placeholders Begin check for binary placeholders
@ -727,7 +726,6 @@ public class SocketIOClient: NSObject {
End check for binary placeholders End check for binary placeholders
**/ **/
} }
}
// Handles binary data // Handles binary data
internal func parseBinaryData(data:NSData) { internal func parseBinaryData(data:NSData) {