handle acks from the server

This commit is contained in:
Erik 2015-02-15 13:17:36 -05:00
parent 12b8f3ef1f
commit 3754bd572a
4 changed files with 145 additions and 27 deletions

View File

@ -18,9 +18,10 @@ Methods
-------
1. `socket.on(name:String, callback:((data:AnyObject?) -> Void)) -> SocketAckHandler` - Adds a handler for an event. Returns a SocketAckHandler which can be used to ack an event. See example.
2. `socket.onMultipleItems(name:String, callback:((data:NSArray?) -> Void)) -> SocketAckHandler` - Adds a handler for an event that can have multiple items. Items are stored in an array. Returns a SocketAckHandler which can be used to ack an event. See example.
3. `socket.emit(event:String, args:AnyObject...) -> SocketAckHandler` - Sends a message. Can send multiple args. Returns a SocketAckHandler that can be used to request an ack. See example.
4. `socket.connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
5. `socket.close()` - Closes the socket. Once a socket is closed it should not be reopened.
3. `socket.emit(event:String, args:AnyObject...)` - Sends a message. Can send multiple args.
4. `socket.emitWithAck(event:String, args:AnyObject...) -> SocketAckHandler` - Sends a message that requests an acknoweldgement from the server. Returns a SocketAckHandler which you can use to add an onAck handler. See example.
5. `socket.connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
6. `socket.close()` - Closes the socket. Once a socket is closed it should not be reopened.
Events
------

View File

@ -24,14 +24,16 @@
import Foundation
typealias AckCallback = ([AnyObject]?) -> Void
typealias AckCallback = (AnyObject?) -> Void
class SocketAckHandler {
let ackNum:Int!
let event:String!
var ackData:[AnyObject]?
var callback:AckCallback?
init(event:String) {
init(event:String, ackNum:Int = 0) {
self.ackNum = ackNum
self.event = event
}

View File

@ -25,6 +25,7 @@
import Foundation
class SocketEvent {
let justAck:Bool!
var ack:Int?
var args:AnyObject!
lazy var currentPlace = 0
@ -32,11 +33,12 @@ class SocketEvent {
var event:String!
var placeholders:Int!
init(event:String, args:AnyObject?, placeholders:Int = 0, ack:Int? = nil) {
init(event:String, args:AnyObject?, placeholders:Int = 0, ackNum:Int? = nil, justAck:Bool = false) {
self.event = event
self.args = args
self.placeholders = placeholders
self.ack = ack
self.ack = ackNum
self.justAck = justAck
}
func addData(data:NSData) -> Bool {
@ -64,22 +66,38 @@ class SocketEvent {
}
static func createMessageForEvent(event:String, withArgs args:[AnyObject],
hasBinary:Bool, withDatas datas:Int = 0, toNamespace nsp:String?) -> String {
hasBinary:Bool, withDatas datas:Int = 0, toNamespace nsp:String?, wantsAck ack:Int? = nil) -> String {
var message:String
var jsonSendError:NSError?
if !hasBinary {
if nsp == nil {
message = "42[\"\(event)\","
if ack == nil {
message = "42[\"\(event)\","
} else {
message = "42\(ack!)[\"\(event)\","
}
} else {
message = "42/\(nsp!),[\"\(event)\","
if ack == nil {
message = "42/\(nsp!),[\"\(event)\","
} else {
message = "42/\(nsp!),\(ack!)[\"\(event)\","
}
}
} else {
if nsp == nil {
message = "45\(datas)-[\"\(event)\","
if ack == nil {
message = "45\(datas)-[\"\(event)\","
} else {
message = "45\(datas)-\(ack!)[\"\(event)\","
}
} else {
message = "45\(datas)-/\(nsp!),[\"\(event)\","
if ack == nil {
message = "45\(datas)-/\(nsp!),[\"\(event)\","
} else {
message = "45\(datas)-/\(nsp!),\(ack!)[\"\(event)\","
}
}
}

View File

@ -36,10 +36,11 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
let emitQueue = dispatch_queue_create("emitQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL)
private var ackHandlers = [SocketAckHandler]()
private var secure = false
private var currentAck = -1
private var handlers = [SocketEventHandler]()
private var lastSocketMessage:SocketEvent?
private var pingTimer:NSTimer!
private var secure = false
var closed = false
var connected = false
var connecting = false
@ -126,14 +127,11 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
// Sends a message with multiple args
// If a message contains binary we have to send those
// seperately.
func emit(event:String, _ args:AnyObject...) -> SocketAckHandler {
func emit(event:String, _ args:AnyObject...) {
if !self.connected {
return SocketAckHandler(event: "fail")
return
}
let ackHandler = SocketAckHandler(event: event)
self.ackHandlers.append(ackHandler)
dispatch_async(self.emitQueue) {[weak self] in
if self == nil {
return
@ -141,11 +139,29 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self?._emit(event, args)
}
}
func emitWithAck(event:String, _ args:AnyObject...) -> SocketAckHandler {
if !self.connected {
return SocketAckHandler(event: "fail")
}
self.currentAck++
let ackHandler = SocketAckHandler(event: event, ackNum: self.currentAck)
self.ackHandlers.append(ackHandler)
dispatch_async(self.emitQueue) {[weak self] in
if self == nil {
return
}
self?._emit(event, args, ack: true)
}
return ackHandler
}
private func _emit(event:String, _ args:[AnyObject]) {
private func _emit(event:String, _ args:[AnyObject], ack:Bool = false) {
var frame:SocketEvent
var str:String
@ -156,16 +172,27 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
}
if hasBinary {
str = SocketEvent.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp)
if !ack {
str = SocketEvent.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp)
} else {
str = SocketEvent.createMessageForEvent(event, withArgs: items,
hasBinary: true, withDatas: emitDatas.count, toNamespace: self.nsp, wantsAck: self.currentAck)
}
self.io?.send(str)
for data in emitDatas {
self.io?.send(data)
}
} else {
str = SocketEvent.createMessageForEvent(event, withArgs: items, hasBinary: false,
withDatas: 0, toNamespace: self.nsp)
if !ack {
str = SocketEvent.createMessageForEvent(event, withArgs: items, hasBinary: false,
withDatas: 0, toNamespace: self.nsp)
} else {
str = SocketEvent.createMessageForEvent(event, withArgs: items, hasBinary: false,
withDatas: 0, toNamespace: self.nsp, wantsAck: self.currentAck)
}
self.io?.send(str)
}
}
@ -207,6 +234,16 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
}
}
// Called when the socket gets an ack for something it sent
private func handleAck(ack:Int, data:AnyObject?) {
for handler in self.ackHandlers {
if handler.ackNum == ack {
handler.callback?(data)
break
}
}
}
// Handles events
func handleEvent(event:String, data:AnyObject?, isInternalMessage:Bool = false,
wantsAck ack:Int? = nil, withAckType ackType:Int = 3) {
@ -264,7 +301,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
}
// Parse an NSArray looking for binary data
private class func parseArray(arr:NSArray, var placeholders:Int) -> (NSArray, Bool, [NSData]) {
private static func parseArray(arr:NSArray, var placeholders:Int) -> (NSArray, Bool, [NSData]) {
var replacementArr = [AnyObject](count: arr.count, repeatedValue: 1)
var hasBinary = false
var arrayDatas = [NSData]()
@ -512,6 +549,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
@ -525,6 +563,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
if ackNum == "" {
self.handleEvent(event, data: parsed)
} else {
self.currentAck = ackNum.toInt()!
self.handleEvent(event, data: parsed, isInternalMessage: false,
wantsAck: ackNum.toInt(), withAckType: 3)
}
@ -540,11 +579,31 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
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("43") {
let arr = Array(messageGroups[1])
let ackNum:String
let nsp = messageGroups[2]
if nsp == "" && self.nsp != nil {
return
}
if nsp == "" {
ackNum = String(arr[2...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
@ -574,9 +633,13 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
/**
Begin check for binary placeholders
**/
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\"),(.*)\\]$"].groups()
let binaryGroup = mutMessage["^(\\d*)-\\/?(\\w*)?,?(\\d*)?\\[(\".*?\")?,?(.*)?\\]$"].groups()
if binaryGroup != nil {
if binaryGroup == nil {
return
}
if binaryGroup[1].hasPrefix("45") {
// println(binaryGroup)
var ackNum:String
var event:String
@ -611,11 +674,35 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!)
} else {
self.currentAck = ackNum.toInt()!
mes = SocketEvent(event: event, args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ack: ackNum.toInt())
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt())
}
self.lastSocketMessage = mes
} else if binaryGroup[1].hasPrefix("46") {
let messageType = RegexMutable(binaryGroup[1])
let numberOfPlaceholders = (messageType["46"] ~= "") as String
let ackNum:String
let 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\""
self.lastSocketMessage = SocketEvent(event: "", args: placeholdersRemoved,
placeholders: numberOfPlaceholders.toInt()!, ackNum: ackNum.toInt(), justAck: true)
}
/**
End check for binary placeholders
@ -634,6 +721,11 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
if let args:AnyObject = parsedArgs {
let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders(args)
if self.lastSocketMessage!.justAck! {
self.handleAck(self.lastSocketMessage!.ack!, data: filledInArgs)
return
}
if self.lastSocketMessage!.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: self.lastSocketMessage!.ack!, withAckType: 6)
@ -643,6 +735,11 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} else {
let filledInArgs:AnyObject = self.lastSocketMessage!.fillInPlaceholders()
if self.lastSocketMessage!.justAck! {
self.handleAck(self.lastSocketMessage!.ack!, data: filledInArgs)
return
}
if self.lastSocketMessage!.ack != nil {
self.handleEvent(event, data: filledInArgs, isInternalMessage: false,
wantsAck: self.lastSocketMessage!.ack!, withAckType: 6)