update 1.2

This commit is contained in:
Erik 2015-03-13 10:08:41 -04:00
parent 560235353d
commit 4551cad9e1
5 changed files with 715 additions and 671 deletions

View File

@ -42,7 +42,7 @@ private enum PacketType: String {
case NOOP = "6" case NOOP = "6"
} }
class SocketEngine: NSObject, WebSocketDelegate { public class SocketEngine: NSObject, WebSocketDelegate {
unowned let client:SocketIOClient unowned let client:SocketIOClient
private let workQueue = NSOperationQueue() private let workQueue = NSOperationQueue()
private let emitQueue = dispatch_queue_create( private let emitQueue = dispatch_queue_create(
@ -176,12 +176,10 @@ class SocketEngine: NSObject, WebSocketDelegate {
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) {callback(str)} dispatch_async(self!.parseQueue) {callback(str)}
} }
@ -242,7 +240,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
@ -289,7 +286,6 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
let (urlPolling, urlWebSocket) = self.createURLs(params: opts) let (urlPolling, urlWebSocket) = self.createURLs(params: opts)
self.urlPolling = urlPolling self.urlPolling = urlPolling
self.urlWebSocket = urlWebSocket self.urlWebSocket = urlWebSocket
let reqPolling = NSURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!) let reqPolling = NSURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!)
@ -463,7 +459,7 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
func send(msg:String, datas:[NSData]? = nil) { public func send(msg:String, datas:[NSData]? = nil) {
let _send = {[weak self] (msg:String, datas:[NSData]?) -> () -> Void in let _send = {[weak self] (msg:String, datas:[NSData]?) -> () -> Void in
return { return {
if self == nil || !self!.connected { if self == nil || !self!.connected {
@ -475,7 +471,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, doPoll: true) self?.sendPollMessage(msg, withType: PacketType.MESSAGE, datas: datas)
} }
} }
} }
@ -497,12 +493,12 @@ 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, doPoll: false) self.sendPollMessage("", withType: PacketType.PING)
} }
} }
private func sendPollMessage(msg:String, withType type:PacketType, private func sendPollMessage(msg:String, withType type:PacketType,
datas:[NSData]? = nil, doPoll poll:Bool) { datas:[NSData]? = nil) {
// println("Sending poll: \(msg) as type: \(type.rawValue)") // println("Sending poll: \(msg) as type: \(type.rawValue)")
let strMsg = "\(type.rawValue)\(msg)" let strMsg = "\(type.rawValue)\(msg)"
@ -516,12 +512,8 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
if !self.waitingForPoll && self.waitingForPost && poll {
self.doPoll()
} 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)")
@ -555,17 +547,17 @@ class SocketEngine: NSObject, WebSocketDelegate {
// Do a fast upgrade // Do a fast upgrade
self.fastUpgrade = true self.fastUpgrade = true
self.probing = false self.probing = false
self.sendPollMessage("", withType: PacketType.NOOP, doPoll: false) self.sendPollMessage("", withType: PacketType.NOOP)
} }
} }
func websocketDidConnect(socket:WebSocket) { public func websocketDidConnect(socket:WebSocket) {
self.websocketConnected = true self.websocketConnected = true
self.probing = true self.probing = true
self.probeWebSocket() self.probeWebSocket()
} }
func websocketDidDisconnect(socket:WebSocket, error:NSError?) { public func websocketDidDisconnect(socket:WebSocket, error:NSError?) {
self.websocketConnected = false self.websocketConnected = false
self.probing = false self.probing = false
@ -580,11 +572,11 @@ class SocketEngine: NSObject, WebSocketDelegate {
} }
} }
func websocketDidReceiveMessage(socket:WebSocket, text:String) { public func websocketDidReceiveMessage(socket:WebSocket, text:String) {
self.parseEngineMessage(text) self.parseEngineMessage(text)
} }
func websocketDidReceiveData(socket:WebSocket, data:NSData) { public func websocketDidReceiveData(socket:WebSocket, data:NSData) {
self.parseEngineData(data) self.parseEngineData(data)
} }
} }

View File

@ -226,7 +226,7 @@ class SocketEvent {
// We have multiple items // We have multiple items
// Do it live // Do it live
let argsAsArray = "[\(self.args)]" let argsAsArray = "[\(self.args)]"
if let parsedArr = SocketIOClient.parseData(argsAsArray) as? NSArray { if let parsedArr = SocketParser.parseData(argsAsArray) as? NSArray {
var returnArr = [AnyObject](count: parsedArr.count, repeatedValue: 0) var returnArr = [AnyObject](count: parsedArr.count, repeatedValue: 0)
for i in 0..<parsedArr.count { for i in 0..<parsedArr.count {

View File

@ -36,26 +36,43 @@ public class SocketIOClient: NSObject {
private lazy var params = [String: AnyObject]() private lazy var params = [String: AnyObject]()
private var ackHandlers = [SocketAckHandler]() private var ackHandlers = [SocketAckHandler]()
private var anyHandler:((AnyHandler) -> Void)? private var anyHandler:((AnyHandler) -> Void)?
private var currentAck = -1 private var _closed = false
private var _connected = false
private var _connecting = false
private var currentReconnectAttempt = 0 private var currentReconnectAttempt = 0
private var forcePolling = false private var forcePolling = false
private var handlers = [SocketEventHandler]() private var handlers = [SocketEventHandler]()
private var waitingData = [SocketEvent]()
private var paramConnect = false private var paramConnect = false
private var _secure = false private var _secure = false
private var _sid:String?
private var _reconnecting = false
private var reconnectTimer:NSTimer? private var reconnectTimer:NSTimer?
var closed = false
var connected = false internal var currentAck = -1
var connecting = false internal var waitingData = [SocketEvent]()
var engine:SocketEngine?
var nsp:String? public var closed:Bool {
var reconnects = true return self._closed
var reconnecting = false }
var reconnectWait = 10 public var connected:Bool {
var secure:Bool { return self._connected
}
public var connecting:Bool {
return self._connecting
}
public var engine:SocketEngine?
public var nsp:String?
public var reconnects = true
public var reconnecting:Bool {
return self._reconnecting
}
public var reconnectWait = 10
public var secure:Bool {
return self._secure return self._secure
} }
var sid:String? public var sid:String? {
return self._sid
}
public init(socketURL:String, opts:[String: AnyObject]? = nil) { public init(socketURL:String, opts:[String: AnyObject]? = nil) {
var mutURL = RegexMutable(socketURL) var mutURL = RegexMutable(socketURL)
@ -103,10 +120,10 @@ public class SocketIOClient: NSObject {
// Closes the socket // Closes the socket
public func close() { public func close() {
self.closed = true self._closed = true
self.connecting = false self._connecting = false
self.connected = false self._connected = false
self.reconnecting = false self._reconnecting = false
self.engine?.close() self.engine?.close()
} }
@ -114,7 +131,7 @@ public class SocketIOClient: NSObject {
public func connect() { public func connect() {
if self.closed { if self.closed {
println("Warning! This socket was previously closed. This might be dangerous!") println("Warning! This socket was previously closed. This might be dangerous!")
self.closed = false self._closed = false
} }
self.engine?.open() self.engine?.open()
@ -124,7 +141,7 @@ public class SocketIOClient: NSObject {
public func connectWithParams(params:[String: AnyObject]) { public func connectWithParams(params:[String: AnyObject]) {
if self.closed { if self.closed {
println("Warning! This socket was previously closed. This might be dangerous!") println("Warning! This socket was previously closed. This might be dangerous!")
self.closed = false self._closed = false
} }
self.params = params self.params = params
@ -134,25 +151,27 @@ public class SocketIOClient: NSObject {
} }
func didConnect() { func didConnect() {
self.closed = false self._closed = false
self.connected = true self._connected = true
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
self.currentReconnectAttempt = 0 self.currentReconnectAttempt = 0
self.reconnectTimer?.invalidate() self.reconnectTimer?.invalidate()
self.reconnectTimer = nil self.reconnectTimer = nil
self.sid = self.engine?.sid self._sid = self.engine?.sid
// Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
self.handleEvent("connect", data: nil, isInternalMessage: false) self.handleEvent("connect", data: nil, isInternalMessage: false)
} }
// Server wants us to die // Server wants us to die
func didForceClose() { func didForceClose() {
self.closed = true self._closed = true
self.connected = false self._connected = false
self.reconnects = false self.reconnects = false
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
self.handleEvent("disconnect", data: "closed", isInternalMessage: true) self.handleEvent("disconnect", data: "closed", isInternalMessage: true)
} }
@ -200,7 +219,7 @@ public class SocketIOClient: NSObject {
var frame:SocketEvent var frame:SocketEvent
var str:String var str:String
let (items, hasBinary, emitDatas) = SocketIOClient.parseEmitArgs(args) let (items, hasBinary, emitDatas) = SocketParser.parseEmitArgs(args)
if !self.connected { if !self.connected {
return return
@ -230,13 +249,13 @@ public class SocketIOClient: NSObject {
} }
// If the server wants to know that the client received data // If the server wants to know that the client received data
internal func emitAck(ack:Int, withData data:[AnyObject]?, withAckType ackType:Int) { func emitAck(ack:Int, withData data:[AnyObject]?, withAckType ackType:Int) {
dispatch_async(self.ackQueue) {[weak self] in dispatch_async(self.ackQueue) {[weak self] in
if self == nil || !self!.connected || data == nil { if self == nil || !self!.connected || data == nil {
return return
} }
let (items, hasBinary, emitDatas) = SocketIOClient.parseEmitArgs(data!) let (items, hasBinary, emitDatas) = SocketParser.parseEmitArgs(data!)
var str:String var str:String
if !hasBinary { if !hasBinary {
@ -264,7 +283,7 @@ public class SocketIOClient: NSObject {
} }
// Called when the socket gets an ack for something it sent // Called when the socket gets an ack for something it sent
private func handleAck(ack:Int, data:AnyObject?) { func handleAck(ack:Int, data:AnyObject?) {
self.ackHandlers = self.ackHandlers.filter {handler in self.ackHandlers = self.ackHandlers.filter {handler in
if handler.ackNum != ack { if handler.ackNum != ack {
return true return true
@ -347,454 +366,36 @@ public class SocketIOClient: NSObject {
self.connect() self.connect()
} }
// Parse an NSArray looking for binary data func parseSocketMessage(msg:String) {
private class func parseArray(arr:NSArray, var currentPlaceholder:Int) -> (NSArray, Bool, [NSData]) { SocketParser.parseSocketMessage(msg, socket: self)
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
var hasBinary = false
var arrayDatas = [NSData]()
for g in 0..<arr.count {
if arr[g] is NSData {
hasBinary = true
currentPlaceholder++
let sendData = arr[g] as! NSData
arrayDatas.append(sendData)
replacementArr[g] = ["_placeholder": true,
"num": currentPlaceholder]
} else if let dict = arr[g] as? NSDictionary {
let (nestDict, hadBinary, dictArrs) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += dictArrs.count
replacementArr[g] = nestDict
arrayDatas.extend(dictArrs)
} else {
replacementArr[g] = dict
}
} else if let nestArr = arr[g] as? NSArray {
// Recursive
let (nested, hadBinary, nestDatas) = self.parseArray(nestArr,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += nestDatas.count
replacementArr[g] = nested
arrayDatas.extend(nestDatas)
} else {
replacementArr[g] = arr[g]
}
} else {
replacementArr[g] = arr[g]
}
} }
return (replacementArr, hasBinary, arrayDatas) func parseBinaryData(data:NSData) {
} SocketParser.parseBinaryData(data, socket: self)
// Parses data for events
class func parseData(data:String?) -> AnyObject? {
if data == nil {
return nil
}
var err:NSError?
let stringData = data!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.AllowFragments, error: &err)
if err != nil {
// println(err)
return nil
}
return parsed
}
private class func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) {
var items = [AnyObject](count: args.count, repeatedValue: 1)
var currentPlaceholder = -1
var hasBinary = false
var emitDatas = [NSData]()
for i in 0..<args.count {
if let dict = args[i] as? NSDictionary {
// Check for binary data
let (newDict, hadBinary, binaryDatas) = SocketIOClient.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
currentPlaceholder += binaryDatas.count
emitDatas.extend(binaryDatas)
hasBinary = true
items[i] = newDict
} else {
items[i] = dict
}
} else if let arr = args[i] as? NSArray {
// arg is array, check for binary
let (replace, hadData, newDatas) = SocketIOClient.parseArray(arr,
currentPlaceholder: currentPlaceholder)
if hadData {
hasBinary = true
currentPlaceholder += newDatas.count
for data in newDatas {
emitDatas.append(data)
}
items[i] = replace
} else {
items[i] = arr
}
} else if let binaryData = args[i] as? NSData {
// args is just binary
hasBinary = true
currentPlaceholder++
items[i] = ["_placeholder": true, "num": currentPlaceholder]
emitDatas.append(binaryData)
} else {
items[i] = args[i]
}
}
return (items, hasBinary, emitDatas)
}
// Parses a NSDictionary, looking for NSData objects
private class func parseNSDictionary(dict:NSDictionary, var currentPlaceholder:Int) -> (NSDictionary, Bool, [NSData]) {
var returnDict = NSMutableDictionary()
var hasBinary = false
var returnDatas = [NSData]()
for (key, value) in dict {
if let binaryData = value as? NSData {
currentPlaceholder++
hasBinary = true
returnDatas.append(binaryData)
returnDict[key as! String] = ["_placeholder": true, "num": currentPlaceholder++]
} else if let arr = value as? NSArray {
let (replace, hadBinary, arrDatas) = self.parseArray(arr, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = replace
currentPlaceholder += arrDatas.count
returnDatas.extend(arrDatas)
} else {
returnDict[key as! String] = arr
}
} else if let dict = value as? NSDictionary {
// Recursive
let (nestDict, hadBinary, nestDatas) = self.parseNSDictionary(dict, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = nestDict
currentPlaceholder += nestDatas.count
returnDatas.extend(nestDatas)
} else {
returnDict[key as! String] = dict
}
} else {
returnDict[key as! String] = value
}
}
return (returnDict, hasBinary, returnDatas)
}
// Parses messages recieved
internal func parseSocketMessage(stringMessage:String) {
// println(message!)
// Check for successful namepsace connect
if self.nsp != nil {
if stringMessage == "0/\(self.nsp!)" {
self.didConnect()
return
}
}
if stringMessage == "0" {
if self.nsp != nil {
// Join namespace
self.joinNamespace()
return
} else {
// Don't handle as internal because something crazy could happen where
// we disconnect before it's handled
self.didConnect()
return
}
}
var mutMessage = RegexMutable(stringMessage)
/**
Begin check for message
**/
let messageGroups = mutMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?(\\[.*\\])?"].groups()
if messageGroups[1].hasPrefix("2") {
var mesNum = messageGroups[1]
var ackNum:String
var namespace:String?
var messagePart:String!
if messageGroups[3] != "" {
ackNum = messageGroups[3]
} else {
let range = Range<String.Index>(start: mesNum.startIndex, end: advance(mesNum.startIndex, 1))
mesNum.replaceRange(range, with: "")
ackNum = mesNum
}
namespace = messageGroups[2]
messagePart = messageGroups[4]
if namespace == "" && self.nsp != nil {
return
}
let messageInternals = RegexMutable(messagePart)["\\[\"(.*?)\",(.*?)?\\]$"].groups()
if messageInternals != nil && messageInternals.count > 2 {
let event = messageInternals[1]
var data:String?
if messageInternals[2] == "" {
data = nil
} else {
data = messageInternals[2]
}
// It would be nice if socket.io only allowed one thing
// per message, but alas, it doesn't.
if let parsed:AnyObject = SocketIOClient.parseData(data) {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
} else if let strData = data {
// There are multiple items in the message
// Turn it into a String and run it through
// parseData to try and get an array.
let asArray = "[\(strData)]"
if let parsed:AnyObject = SocketIOClient.parseData(asArray) {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
}
}
// Check for no item event
let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups()
if noItemMessage != nil && noItemMessage.count == 2 {
let event = noItemMessage[1]
if ackNum == "" {
self.handleEvent(event, data: nil)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: nil, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
} else if messageGroups[1].hasPrefix("3") {
let arr = Array(messageGroups[1])
var ackNum:String
let nsp = messageGroups[2]
if nsp == "" && self.nsp != nil {
return
}
if nsp == "" {
ackNum = String(arr[1...arr.count-1])
} else {
ackNum = messageGroups[3]
}
let ackData:AnyObject? = SocketIOClient.parseData(messageGroups[4])
self.handleAck(ackNum.toInt()!, data: ackData)
return
}
/**
End Check for message
**/
// Check for message with binary placeholders
self.parseBinaryMessage(message: stringMessage)
}
// Tries to parse a message that contains binary
private func parseBinaryMessage(#message:String) {
// println(message)
var mutMessage = RegexMutable(message)
/**
Begin check for binary placeholders
**/
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups()
if binaryGroup == nil {
return
}
if binaryGroup[1].hasPrefix("5") {
// println(binaryGroup)
var ackNum:String
var event:String
var mutMessageObject:NSMutableString
var namespace:String?
var numberOfPlaceholders:String
let messageType = RegexMutable(binaryGroup[1])
namespace = binaryGroup[2]
if binaryGroup[3] != "" {
ackNum = binaryGroup[3] as String
} else if self.nsp == nil && binaryGroup[2] != "" {
ackNum = binaryGroup[2]
} else {
ackNum = ""
}
numberOfPlaceholders = (messageType["5"] ~= "") as String
event = (RegexMutable(binaryGroup[4])["\""] ~= "") as String
mutMessageObject = RegexMutable(binaryGroup[5])
if namespace == "" && self.nsp != nil {
return
}
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
var mes:SocketEvent
if ackNum == "" {
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!)
} else {
self.currentAck = ackNum.toInt()!
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt())
}
self.waitingData.append(mes)
} else if binaryGroup[1].hasPrefix("6") {
let messageType = RegexMutable(binaryGroup[1])
let numberOfPlaceholders = (messageType["6"] ~= "") as String
var ackNum:String
var nsp:String
if binaryGroup[3] == "" {
ackNum = binaryGroup[2]
nsp = ""
} else {
ackNum = binaryGroup[3]
nsp = binaryGroup[2]
}
if nsp == "" && self.nsp != nil {
return
}
var mutMessageObject = RegexMutable(binaryGroup[5])
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
let event = SocketEvent(event: "", args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt(), justAck: true)
self.waitingData.append(event)
}
/**
End check for binary placeholders
**/
}
// Handles binary data
internal func parseBinaryData(data:NSData) {
let shouldExecute = self.waitingData[0].addData(data)
if shouldExecute {
let socketEvent = self.waitingData.removeAtIndex(0)
var event = socketEvent.event
var parsedArgs:AnyObject? = SocketIOClient.parseData(socketEvent.args as? String)
if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders(args)
if socketEvent.justAck! {
// Should handle ack
self.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should do event
if socketEvent.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
self.handleEvent(event, data: filledInArgs)
}
} else {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders()
// Should handle ack
if socketEvent.justAck! {
self.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should handle ack
if socketEvent.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
self.handleEvent(event, data: filledInArgs)
}
}
}
} }
// Something happened while polling // Something happened while polling
internal func pollingDidFail(err:NSError?) { func pollingDidFail(err:NSError?) {
if !self.reconnecting { if !self.reconnecting {
self.connected = false self._connected = false
self.handleEvent("reconnect", data: err?.localizedDescription, isInternalMessage: true) self.handleEvent("reconnect", data: err?.localizedDescription, isInternalMessage: true)
self.tryReconnect() self.tryReconnect()
} }
} }
// We lost connection and should attempt to reestablish // We lost connection and should attempt to reestablish
internal func tryReconnect() { func tryReconnect() {
if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts { if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts {
self.didForceClose() self.didForceClose()
return return
} else if self.connected { } else if self.connected {
self.connecting = false self._connecting = false
self.reconnecting = false self._reconnecting = false
return return
} }
if self.reconnectTimer == nil { if self.reconnectTimer == nil {
self.reconnecting = true self._reconnecting = true
dispatch_async(dispatch_get_main_queue()) {[weak self] in dispatch_async(dispatch_get_main_queue()) {[weak self] in
if self == nil { if self == nil {
return return
@ -819,8 +420,8 @@ public class SocketIOClient: NSObject {
// Called when the socket is closed // Called when the socket is closed
func webSocketDidCloseWithCode(code:Int, reason:String!, wasClean:Bool) { func webSocketDidCloseWithCode(code:Int, reason:String!, wasClean:Bool) {
self.connected = false self._connected = false
self.connecting = false self._connecting = false
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.didForceClose() self.didForceClose()
} else { } else {
@ -831,8 +432,8 @@ public class SocketIOClient: NSObject {
// Called when an error occurs. // Called when an error occurs.
func webSocketDidFailWithError(error:NSError!) { func webSocketDidFailWithError(error:NSError!) {
self.connected = false self._connected = false
self.connecting = false self._connecting = false
self.handleEvent("error", data: error.localizedDescription, isInternalMessage: true) self.handleEvent("error", data: error.localizedDescription, isInternalMessage: true)
if self.closed || !self.reconnects { if self.closed || !self.reconnects {
self.didForceClose() self.didForceClose()

451
SwiftIO/SocketParser.swift Normal file
View File

@ -0,0 +1,451 @@
//
// SocketParser.swift
// Socket.IO-Swift
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
class SocketParser {
// Parse an NSArray looking for binary data
class func parseArray(arr:NSArray, var currentPlaceholder:Int) -> (NSArray, Bool, [NSData]) {
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
var hasBinary = false
var arrayDatas = [NSData]()
for g in 0..<arr.count {
if arr[g] is NSData {
hasBinary = true
currentPlaceholder++
let sendData = arr[g] as! NSData
arrayDatas.append(sendData)
replacementArr[g] = ["_placeholder": true,
"num": currentPlaceholder]
} else if let dict = arr[g] as? NSDictionary {
let (nestDict, hadBinary, dictArrs) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += dictArrs.count
replacementArr[g] = nestDict
arrayDatas.extend(dictArrs)
} else {
replacementArr[g] = dict
}
} else if let nestArr = arr[g] as? NSArray {
// Recursive
let (nested, hadBinary, nestDatas) = self.parseArray(nestArr,
currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
currentPlaceholder += nestDatas.count
replacementArr[g] = nested
arrayDatas.extend(nestDatas)
} else {
replacementArr[g] = arr[g]
}
} else {
replacementArr[g] = arr[g]
}
}
return (replacementArr, hasBinary, arrayDatas)
}
// Parses data for events
class func parseData(data:String?) -> AnyObject? {
if data == nil {
return nil
}
var err:NSError?
let stringData = data!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let parsed:AnyObject? = NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.AllowFragments, error: &err)
if err != nil {
// println(err)
return nil
}
return parsed
}
class func parseEmitArgs(args:[AnyObject]) -> ([AnyObject], Bool, [NSData]) {
var items = [AnyObject](count: args.count, repeatedValue: 1)
var currentPlaceholder = -1
var hasBinary = false
var emitDatas = [NSData]()
for i in 0..<args.count {
if let dict = args[i] as? NSDictionary {
// Check for binary data
let (newDict, hadBinary, binaryDatas) = self.parseNSDictionary(dict,
currentPlaceholder: currentPlaceholder)
if hadBinary {
currentPlaceholder += binaryDatas.count
emitDatas.extend(binaryDatas)
hasBinary = true
items[i] = newDict
} else {
items[i] = dict
}
} else if let arr = args[i] as? NSArray {
// arg is array, check for binary
let (replace, hadData, newDatas) = self.parseArray(arr,
currentPlaceholder: currentPlaceholder)
if hadData {
hasBinary = true
currentPlaceholder += newDatas.count
for data in newDatas {
emitDatas.append(data)
}
items[i] = replace
} else {
items[i] = arr
}
} else if let binaryData = args[i] as? NSData {
// args is just binary
hasBinary = true
currentPlaceholder++
items[i] = ["_placeholder": true, "num": currentPlaceholder]
emitDatas.append(binaryData)
} else {
items[i] = args[i]
}
}
return (items, hasBinary, emitDatas)
}
// Parses a NSDictionary, looking for NSData objects
class func parseNSDictionary(dict:NSDictionary, var currentPlaceholder:Int) -> (NSDictionary, Bool, [NSData]) {
var returnDict = NSMutableDictionary()
var hasBinary = false
var returnDatas = [NSData]()
for (key, value) in dict {
if let binaryData = value as? NSData {
currentPlaceholder++
hasBinary = true
returnDatas.append(binaryData)
returnDict[key as! String] = ["_placeholder": true, "num": currentPlaceholder]
} else if let arr = value as? NSArray {
let (replace, hadBinary, arrDatas) = self.parseArray(arr, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = replace
currentPlaceholder += arrDatas.count
returnDatas.extend(arrDatas)
} else {
returnDict[key as! String] = arr
}
} else if let dict = value as? NSDictionary {
// Recursive
let (nestDict, hadBinary, nestDatas) = self.parseNSDictionary(dict, currentPlaceholder: currentPlaceholder)
if hadBinary {
hasBinary = true
returnDict[key as! String] = nestDict
currentPlaceholder += nestDatas.count
returnDatas.extend(nestDatas)
} else {
returnDict[key as! String] = dict
}
} else {
returnDict[key as! String] = value
}
}
return (returnDict, hasBinary, returnDatas)
}
// Parses messages recieved
class func parseSocketMessage(stringMessage:String, socket:SocketIOClient) {
// println(message!)
// Check for successful namepsace connect
if socket.nsp != nil {
if stringMessage == "0/\(socket.nsp!)" {
socket.didConnect()
return
}
}
if stringMessage == "0" {
if socket.nsp != nil {
// Join namespace
socket.joinNamespace()
return
} else {
socket.didConnect()
return
}
}
var mutMessage = RegexMutable(stringMessage)
/**
Begin check for message
**/
let messageGroups = mutMessage["(\\d*)\\/?(\\w*)?,?(\\d*)?(\\[.*\\])?"].groups()
if messageGroups[1].hasPrefix("2") {
var mesNum = messageGroups[1]
var ackNum:String
var namespace:String?
var messagePart:String!
if messageGroups[3] != "" {
ackNum = messageGroups[3]
} else {
let range = Range<String.Index>(start: mesNum.startIndex,
end: advance(mesNum.startIndex, 1))
mesNum.replaceRange(range, with: "")
ackNum = mesNum
}
namespace = messageGroups[2]
messagePart = messageGroups[4]
if namespace == "" && socket.nsp != nil {
return
}
let messageInternals = RegexMutable(messagePart)["\\[\"(.*?)\",(.*?)?\\]$"].groups()
if messageInternals != nil && messageInternals.count > 2 {
let event = messageInternals[1]
var data:String?
if messageInternals[2] == "" {
data = nil
} else {
data = messageInternals[2]
}
// It would be nice if socket.io only allowed one thing
// per message, but alas, it doesn't.
if let parsed:AnyObject = self.parseData(data) {
if ackNum == "" {
socket.handleEvent(event, data: parsed)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
} else if let strData = data {
// There are multiple items in the message
// Turn it into a String and run it through
// parseData to try and get an array.
let asArray = "[\(strData)]"
if let parsed:AnyObject = self.parseData(asArray) {
if ackNum == "" {
socket.handleEvent(event, data: parsed)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
}
}
// Check for no item event
let noItemMessage = RegexMutable(messagePart)["\\[\"(.*?)\"]$"].groups()
if noItemMessage != nil && noItemMessage.count == 2 {
let event = noItemMessage[1]
if ackNum == "" {
socket.handleEvent(event, data: nil)
} else {
socket.currentAck = ackNum.toInt()!
socket.handleEvent(event, data: nil, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
return
}
} else if messageGroups[1].hasPrefix("3") {
let arr = Array(messageGroups[1])
var ackNum:String
let nsp = messageGroups[2]
if nsp == "" && socket.nsp != nil {
return
}
if nsp == "" {
ackNum = String(arr[1...arr.count-1])
} else {
ackNum = messageGroups[3]
}
let ackData:AnyObject? = self.parseData(messageGroups[4])
socket.handleAck(ackNum.toInt()!, data: ackData)
return
}
/**
End Check for message
**/
// Check for message with binary placeholders
self.parseBinaryMessage(stringMessage, socket: socket)
}
// Handles binary data
class func parseBinaryData(data:NSData, socket:SocketIOClient) {
let shouldExecute = socket.waitingData[0].addData(data)
if shouldExecute {
let socketEvent = socket.waitingData.removeAtIndex(0)
var event = socketEvent.event
var parsedArgs:AnyObject? = self.parseData(socketEvent.args as? String)
if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders(args)
if socketEvent.justAck! {
// Should handle ack
socket.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should do event
if socketEvent.ack != nil {
socket.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
socket.handleEvent(event, data: filledInArgs)
}
} else {
let filledInArgs:AnyObject = socketEvent.fillInPlaceholders()
// Should handle ack
if socketEvent.justAck! {
socket.handleAck(socketEvent.ack!, data: filledInArgs)
return
}
// Should handle ack
if socketEvent.ack != nil {
socket.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: socketEvent.ack!, withAckType: 6)
} else {
socket.handleEvent(event, data: filledInArgs)
}
}
}
}
// Tries to parse a message that contains binary
class func parseBinaryMessage(message:String, socket:SocketIOClient) {
// println(message)
var mutMessage = RegexMutable(message)
/**
Begin check for binary placeholders
**/
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups()
if binaryGroup == nil {
return
}
if binaryGroup[1].hasPrefix("5") {
// println(binaryGroup)
var ackNum:String
var event:String
var mutMessageObject:NSMutableString
var namespace:String?
var numberOfPlaceholders:String
let messageType = RegexMutable(binaryGroup[1])
namespace = binaryGroup[2]
if binaryGroup[3] != "" {
ackNum = binaryGroup[3] as String
} else if socket.nsp == nil && binaryGroup[2] != "" {
ackNum = binaryGroup[2]
} else {
ackNum = ""
}
numberOfPlaceholders = (messageType["5"] ~= "") as String
event = (RegexMutable(binaryGroup[4])["\""] ~= "") as String
mutMessageObject = RegexMutable(binaryGroup[5])
if namespace == "" && socket.nsp != nil {
return
}
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
var mes:SocketEvent
if ackNum == "" {
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!)
} else {
socket.currentAck = ackNum.toInt()!
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt())
}
socket.waitingData.append(mes)
} else if binaryGroup[1].hasPrefix("6") {
let messageType = RegexMutable(binaryGroup[1])
let numberOfPlaceholders = (messageType["6"] ~= "") as String
var ackNum:String
var nsp:String
if binaryGroup[3] == "" {
ackNum = binaryGroup[2]
nsp = ""
} else {
ackNum = binaryGroup[3]
nsp = binaryGroup[2]
}
if nsp == "" && socket.nsp != nil {
return
}
var mutMessageObject = RegexMutable(binaryGroup[5])
let placeholdersRemoved = mutMessageObject["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"]
~= "\"~~$2\""
let event = SocketEvent(event: "", args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt(), justAck: true)
socket.waitingData.append(event)
}
/**
End check for binary placeholders
**/
}
}