Use dispatch queues for buffering emitting and recieving

This commit is contained in:
Erik 2015-02-13 17:07:04 -05:00
parent 6d6ac0fc74
commit b53d22f3a2

View File

@ -29,6 +29,10 @@ typealias MultipleCallback = (NSArray?) -> Void
class SocketIOClient: NSObject, SRWebSocketDelegate { class SocketIOClient: NSObject, SRWebSocketDelegate {
let socketURL:NSMutableString! let socketURL:NSMutableString!
let handleQueue = dispatch_queue_create("handleQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL)
let emitQueue = dispatch_queue_create("emitQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL)
private var secure = false private var secure = false
private var handlers = [SocketEventHandler]() private var handlers = [SocketEventHandler]()
private var lastSocketMessage:SocketEvent? private var lastSocketMessage:SocketEvent?
@ -124,6 +128,10 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
return return
} }
dispatch_async(self.emitQueue) {self._emit(event, args)}
}
private func _emit(event:String, _ args:[AnyObject]) {
var frame:SocketEvent var frame:SocketEvent
var str:String var str:String
var items = [AnyObject](count: args.count, repeatedValue: 1) var items = [AnyObject](count: args.count, repeatedValue: 1)
@ -175,6 +183,10 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} }
} }
if !self.connected {
return
}
if hasBinary { if hasBinary {
str = SocketEvent.createMessageForEvent(event, withArgs: items, str = SocketEvent.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp) hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp)
@ -191,19 +203,27 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} }
// Handles events // Handles events
func handleEvent(#event:String, data:AnyObject?, multipleItems:Bool = false) { func handleEvent(event:String, data:AnyObject?, multipleItems:Bool = false, internalMessage:Bool = false) {
// println("Should do event: \(event) with data: \(data)") // println("Should do event: \(event) with data: \(data)")
if !self.connected && !internalMessage {
return
}
for handler in self.handlers { for handler in self.handlers {
if handler.event == event { if handler.event == event {
if data is NSArray { if data is NSArray {
dispatch_async(dispatch_get_main_queue()) {
handler.executeCallback(nil, items: (data as! NSArray)) handler.executeCallback(nil, items: (data as! NSArray))
}
} else { } else {
dispatch_async(dispatch_get_main_queue()) {
handler.executeCallback(data) handler.executeCallback(data)
} }
} }
} }
} }
}
private func joinNamespace() { private func joinNamespace() {
if self.nsp != nil { if self.nsp != nil {
@ -354,7 +374,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// Check for successful namepsace connect // Check for successful namepsace connect
if self.nsp != nil { if self.nsp != nil {
if stringMessage == "40/\(self.nsp!)" { if stringMessage == "40/\(self.nsp!)" {
self.handleEvent(event: "connect", data: nil) self.handleEvent("connect", data: nil)
return return
} }
} }
@ -413,7 +433,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// It would be nice if socket.io only allowed one thing // It would be nice if socket.io only allowed one thing
// per message, but alas, it doesn't. // per message, but alas, it doesn't.
if let parsed:AnyObject = SocketIOClient.parseData(data) { if let parsed:AnyObject = SocketIOClient.parseData(data) {
self.handleEvent(event: event, data: parsed) self.handleEvent(event, data: parsed)
return return
} else if let strData = data { } else if let strData = data {
// There are multiple items in the message // There are multiple items in the message
@ -421,7 +441,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// parseData to try and get an array. // parseData to try and get an array.
let asArray = "[\(strData)]" let asArray = "[\(strData)]"
if let parsed:AnyObject = SocketIOClient.parseData(asArray) { if let parsed:AnyObject = SocketIOClient.parseData(asArray) {
self.handleEvent(event: event, data: parsed, multipleItems: true) self.handleEvent(event, data: parsed, multipleItems: true)
return return
} }
} }
@ -431,7 +451,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups() let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups()
if noItemMessage != nil && noItemMessage.count == 2 { if noItemMessage != nil && noItemMessage.count == 2 {
let event = noItemMessage[1] let event = noItemMessage[1]
self.handleEvent(event: event, data: nil, multipleItems: false) self.handleEvent(event, data: nil, multipleItems: false)
return return
} }
} }
@ -467,7 +487,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
if binaryGroup != nil { if binaryGroup != nil {
// println(binaryGroup) // println(binaryGroup)
var event:NSString! var event:String!
var mutMessageObject:NSMutableString! var mutMessageObject:NSMutableString!
var namespace:String? var namespace:String?
let messageType = RegexMutable(binaryGroup[1]) let messageType = RegexMutable(binaryGroup[1])
@ -476,7 +496,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// Check if message came from a namespace // Check if message came from a namespace
if binaryGroup.count == 5 { if binaryGroup.count == 5 {
namespace = binaryGroup[2] namespace = binaryGroup[2]
event = RegexMutable(binaryGroup[3])["\""] ~= "" event = (RegexMutable(binaryGroup[3])["\""] ~= "") as String
mutMessageObject = RegexMutable(binaryGroup[4]) mutMessageObject = RegexMutable(binaryGroup[4])
} }
@ -488,7 +508,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\"" ~= "\"~~$2\""
let mes = SocketEvent(event: event as! String, args: placeholdersRemoved, let mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.integerValue) placeholders: numberOfPlaceholders.integerValue)
self.lastSocketMessage = mes self.lastSocketMessage = mes
} }
@ -508,10 +528,10 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
if let args:AnyObject = parsedArgs { if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders(args) let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders(args)
self.handleEvent(event: event, data: filledInArgs) self.handleEvent(event, data: filledInArgs)
} else { } else {
let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders() let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders()
self.handleEvent(event: event, data: filledInArgs, multipleItems: true) self.handleEvent(event, data: filledInArgs, multipleItems: true)
return return
} }
} }
@ -535,7 +555,8 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self.connecting = false self.connecting = false
self.reconnects = false self.reconnects = false
self.reconnecting = false self.reconnecting = false
self.handleEvent(event: "disconnect", data: "Failed to reconnect") self.handleEvent("disconnect", data: "Failed to reconnect",
multipleItems: false, internalMessage: true)
return return
} else if self.connected { } else if self.connected {
self.connecting = false self.connecting = false
@ -544,7 +565,8 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} }
// println("Trying to reconnect #\(reconnectAttempts - triesLeft)") // println("Trying to reconnect #\(reconnectAttempts - triesLeft)")
self.handleEvent(event: "reconnectAttempt", data: triesLeft) self.handleEvent("reconnectAttempt", data: triesLeft,
multipleItems: false, internalMessage: true)
let waitTime = UInt64(self.reconnectWait) * NSEC_PER_SEC let waitTime = UInt64(self.reconnectWait) * NSEC_PER_SEC
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(waitTime)) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(waitTime))
@ -567,7 +589,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// Called when a message is recieved // Called when a message is recieved
func webSocket(webSocket:SRWebSocket!, didReceiveMessage message:AnyObject?) { func webSocket(webSocket:SRWebSocket!, didReceiveMessage message:AnyObject?) {
self.parseSocketMessage(message) dispatch_async(self.handleQueue) {self.parseSocketMessage(message)}
} }
// Called when the socket is opened // Called when the socket is opened
@ -583,7 +605,9 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
return return
} }
self.handleEvent(event: "connect", data: nil) // Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
self.handleEvent("connect", data: nil)
} }
// Called when the socket is closed // Called when the socket is closed
@ -592,9 +616,11 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self.connected = false self.connected = false
self.connecting = false self.connecting = false
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.handleEvent(event: "disconnect", data: reason) self.handleEvent("disconnect", data: reason,
multipleItems: false, internalMessage: true)
} else { } else {
self.handleEvent(event: "reconnect", data: reason) self.handleEvent("reconnect", data: reason,
multipleItems: false, internalMessage: true)
self.tryReconnect(triesLeft: self.reconnectAttempts) self.tryReconnect(triesLeft: self.reconnectAttempts)
} }
@ -605,11 +631,14 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self.pingTimer?.invalidate() self.pingTimer?.invalidate()
self.connected = false self.connected = false
self.connecting = false self.connecting = false
self.handleEvent(event: "error", data: error.localizedDescription) self.handleEvent("error", data: error.localizedDescription,
multipleItems: false, internalMessage: true)
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.handleEvent(event: "disconnect", data: error.localizedDescription) self.handleEvent("disconnect", data: error.localizedDescription,
multipleItems: false, internalMessage: true)
} else if !self.reconnecting { } else if !self.reconnecting {
self.handleEvent(event: "reconnect", data: error.localizedDescription) self.handleEvent("reconnect", data: error.localizedDescription,
multipleItems: false, internalMessage: true)
self.tryReconnect(triesLeft: self.reconnectAttempts) self.tryReconnect(triesLeft: self.reconnectAttempts)
} }
} }