merge master

This commit is contained in:
Erik 2015-04-03 16:37:02 -04:00
commit a17f2b6e7a
6 changed files with 127 additions and 122 deletions

View File

@ -11,7 +11,7 @@ socket.on("connect") {data, ack in
socket.on("currentAmount") {data, ack in
if let cur = data?[0] as? Double {
socket.emitWithAck("canUpdate", cur).onAck(0) {data in
socket.emitWithAck("canUpdate", cur)(timeout: 0) {data in
socket.emit("update", ["amount": cur + 2.50])
}
@ -30,9 +30,9 @@ SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8
[socket on: @"connect" callback: ^(NSArray* data, void (^ack)(NSArray*)) {
NSLog(@"connected");
[socket emitObjc:@"echo" withItems:@[@"echo test"]];
[[socket emitWithAckObjc:@"ackack" withItems:@[@"test"]] onAck:0 withCallback:^(NSArray* data) {
NSLog(@"Got data");
}];
[socket emitWithAckObjc:@"ackack" withItems:@[@1]](10, ^(NSArray* data) {
NSLog(@"Got ack");
});
}];
```

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.version = "1.4.4"
s.version = "1.5.0"
s.summary = "Socket.IO-client for Swift"
s.description = <<-DESC
Socket.IO-client for Swift.
@ -12,7 +12,7 @@ Pod::Spec.new do |s|
s.author = { "Erik" => "nuclear.ace@gmail.com" }
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.4.4' }
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v1.5.0' }
s.source_files = "SwiftIO/**/*.swift"
s.requires_arc = true
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files

View File

@ -1,9 +1,9 @@
//
// SocketAckHandler.swift
// Socket.IO-Swift
// SocketAckMap.swift
// SocketIO-Swift
//
// Created by Erik Little on 4/3/15.
//
// Created by Erik Little on 2/14/15.
// 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
@ -25,45 +25,35 @@
import Foundation
public typealias AckCallback = (NSArray?) -> Void
public typealias OnAckCallback = (timeout:UInt64, callback:AckCallback) -> Void
@objc public class SocketAckHandler {
let ackNum:Int!
let event:String!
var acked = false
var callback:AckCallback?
weak var socket:SocketIOClient?
struct SocketAckMap {
private var acks = [Int: AckCallback]()
private var waiting = [Int: Bool]()
init(event:String, ackNum:Int = 0, socket:SocketIOClient) {
self.ackNum = ackNum
self.event = event
self.socket = socket
mutating func addAck(ack:Int, callback:AckCallback) {
waiting[ack] = true
acks[ack] = callback
}
public func onAck(timeout:UInt64, withCallback callback:AckCallback) {
self.callback = callback
mutating func executeAck(ack:Int, items:[AnyObject]?) {
let callback = acks[ack]
waiting[ack] = false
if timeout != 0 {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
if self == nil {
dispatch_async(dispatch_get_main_queue()) {
callback?(items)
return
}
if !self!.acked {
self?.executeAck(["No ACK"])
self?.socket?.removeAck(self!)
}
}
}
acks.removeValueForKey(ack)
}
func executeAck(data:NSArray?) {
dispatch_async(dispatch_get_main_queue()) {[weak self, cb = self.callback] in
self?.acked = true
cb?(data)
return
mutating func timeoutAck(ack:Int) {
if waiting[ack] != nil && waiting[ack]! {
acks[ack]?(["NO ACK"])
}
acks.removeValueForKey(ack)
waiting.removeValueForKey(ack)
}
}

View File

@ -175,6 +175,7 @@ public class SocketEngine: NSObject, WebSocketDelegate {
self._websocket = true
self._polling = false
self.fastUpgrade = false
self.probing = false
self.flushProbeWait()
}
@ -229,7 +230,7 @@ public class SocketEngine: NSObject, WebSocketDelegate {
}
private func flushProbeWait() {
// println("flushing probe wait")
// NSLog("flushing probe wait")
dispatch_async(self.emitQueue) {[weak self] in
if self == nil {
return
@ -240,6 +241,10 @@ public class SocketEngine: NSObject, WebSocketDelegate {
}
self?.probeWait.removeAll(keepCapacity: false)
if self?.postWait.count != 0 {
self?.flushWaitingForPostToWebSocket()
}
}
}
@ -269,11 +274,14 @@ public class SocketEngine: NSObject, WebSocketDelegate {
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)!
// NSLog("posting: \(postStr)")
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
@ -284,9 +292,13 @@ public class SocketEngine: NSObject, WebSocketDelegate {
self?.waitingForPost = false
dispatch_async(self!.emitQueue) {
if self!.fastUpgrade {
self?.doFastUpgrade()
return
} else {
self?.flushWaitingForPost()
self?.doPoll()
return
}
}}.resume()
}
@ -518,6 +530,8 @@ public class SocketEngine: NSObject, WebSocketDelegate {
self.write("", withType: PacketType.PING, withData: nil)
}
/// Send polling message.
/// Only call on emitQueue
private func sendPollMessage(var msg:String, withType type:PacketType,
datas:ContiguousArray<NSData>? = nil) {
// println("Sending poll: \(msg) as type: \(type.rawValue)")
@ -539,6 +553,8 @@ public class SocketEngine: NSObject, WebSocketDelegate {
}
}
/// Send message on WebSockets
/// Only call on emitQueue
private func sendWebSocketMessage(str:String, withType type:PacketType,
datas:ContiguousArray<NSData>? = nil) {
// println("Sending ws: \(str) as type: \(type.rawValue)")
@ -570,9 +586,9 @@ public class SocketEngine: NSObject, WebSocketDelegate {
private func upgradeTransport() {
if self.websocketConnected {
// NSLog("Doing fast upgrade")
// Do a fast upgrade
self.fastUpgrade = true
self.probing = false
self.sendPollMessage("", withType: PacketType.NOOP)
}
}

View File

@ -25,9 +25,7 @@
import Foundation
public class SocketIOClient: NSObject, SocketEngineClient {
let reconnectAttempts:Int!
private lazy var params = [String: AnyObject]()
private var ackHandlers = ContiguousArray<SocketAckHandler>()
private var anyHandler:((SocketAnyEvent) -> Void)?
private var _closed = false
private var _connected = false
@ -42,14 +40,15 @@ public class SocketIOClient: NSObject, SocketEngineClient {
private var _reconnecting = false
private var reconnectTimer:NSTimer?
let reconnectAttempts:Int!
var ackHandlers = SocketAckMap()
var currentAck = -1
var waitingData = ContiguousArray<SocketPacket>()
public let socketURL:String
public let handleQueue = dispatch_queue_create("handleQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL)
public let emitQueue = dispatch_queue_create("emitQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL)
public let handleAckQueue = dispatch_queue_create("handleAckQueue", DISPATCH_QUEUE_SERIAL)
public let handleQueue = dispatch_queue_create("handleQueue", DISPATCH_QUEUE_SERIAL)
public let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL)
public var closed:Bool {
return self._closed
}
@ -89,6 +88,26 @@ public class SocketIOClient: NSObject, SocketEngineClient {
// Set options
if opts != nil {
if let cookies = opts!["cookies"] as? [NSHTTPCookie] {
self.cookies = cookies
}
if let polling = opts!["forcePolling"] as? Bool {
self.forcePolling = polling
}
if let ws = opts!["forceWebsockets"] as? Bool {
self.forceWebsockets = ws
}
if var nsp = opts!["nsp"] as? String {
if nsp != "/" && nsp.hasPrefix("/") {
nsp.removeAtIndex(nsp.startIndex)
}
self.nsp = nsp
}
if let reconnects = opts!["reconnects"] as? Bool {
self.reconnects = reconnects
}
@ -102,26 +121,6 @@ public class SocketIOClient: NSObject, SocketEngineClient {
if let reconnectWait = opts!["reconnectWait"] as? Int {
self.reconnectWait = abs(reconnectWait)
}
if var nsp = opts!["nsp"] as? String {
if nsp != "/" && nsp.hasPrefix("/") {
nsp.removeAtIndex(nsp.startIndex)
}
self.nsp = nsp
}
if let polling = opts!["forcePolling"] as? Bool {
self.forcePolling = polling
}
if let ws = opts!["forceWebsockets"] as? Bool {
self.forceWebsockets = ws
}
if let cookies = opts!["cookies"] as? [NSHTTPCookie] {
self.cookies = cookies
}
} else {
self.reconnectAttempts = -1
}
@ -190,6 +189,29 @@ public class SocketIOClient: NSObject, SocketEngineClient {
self.engine?.open(opts: params)
}
private func createOnAck(event:String, items:[AnyObject]) -> OnAckCallback {
return {[weak self, ack = ++self.currentAck] timeout, callback in
if self == nil {
return
}
self?.ackHandlers.addAck(ack, callback)
dispatch_async(self!.emitQueue) {
self?._emit(event, items, ack: ack)
return
}
if timeout != 0 {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
self?.ackHandlers.timeoutAck(ack)
return
}
}
}
}
func didConnect() {
self._closed = false
self._connected = true
@ -219,6 +241,13 @@ public class SocketIOClient: NSObject, SocketEngineClient {
self.handleEvent("disconnect", data: [reason], isInternalMessage: true)
}
/**
Same as close
*/
public func disconnect(#fast:Bool) {
self.close(fast: fast)
}
/**
Send a message to the server
*/
@ -251,43 +280,23 @@ public class SocketIOClient: NSObject, SocketEngineClient {
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
an ack.
*/
public func emitWithAck(event:String, _ items:AnyObject...) -> SocketAckHandler {
public func emitWithAck(event:String, _ items:AnyObject...) -> OnAckCallback {
if !self.connected {
return SocketAckHandler(event: "fail", socket: self)
return createOnAck(event, items: items)
}
self.currentAck++
let ackHandler = SocketAckHandler(event: event,
ackNum: self.currentAck, socket: self)
self.ackHandlers.append(ackHandler)
dispatch_async(self.emitQueue) {[weak self, ack = self.currentAck] in
self?._emit(event, items, ack: ack)
return
}
return ackHandler
return self.createOnAck(event, items: items)
}
/**
Same as emitWithAck, but for Objective-C
*/
public func emitWithAckObjc(event:String, withItems items:[AnyObject]) -> SocketAckHandler {
public func emitWithAckObjc(event:String, withItems items:[AnyObject]) -> OnAckCallback {
if !self.connected {
return SocketAckHandler(event: "fail", socket: self)
return self.createOnAck(event, items: items)
}
self.currentAck++
let ackHandler = SocketAckHandler(event: event,
ackNum: self.currentAck, socket: self)
self.ackHandlers.append(ackHandler)
dispatch_async(self.emitQueue) {[weak self, ack = self.currentAck] in
self?._emit(event, items, ack: ack)
return
}
return ackHandler
return self.createOnAck(event, items: items)
}
private func _emit(event:String, _ args:[AnyObject], ack:Int? = nil) {
@ -331,21 +340,15 @@ public class SocketIOClient: NSObject, SocketEngineClient {
// Called when the socket gets an ack for something it sent
func handleAck(ack:Int, data:AnyObject?) {
self.ackHandlers = self.ackHandlers.filter {handler in
if handler.ackNum != ack {
return true
} else {
var ackData:[AnyObject]?
if data is NSArray {
handler.executeAck(data as? NSArray)
ackData = data as? NSArray
} else if data != nil {
handler.executeAck([data!])
} else {
handler.executeAck(nil)
ackData = [data!]
}
return false
}
}
self.ackHandlers.executeAck(ack, items: ackData)
}
/**
@ -428,10 +431,6 @@ public class SocketIOClient: NSObject, SocketEngineClient {
}
}
func removeAck(ack:SocketAckHandler) {
self.ackHandlers = self.ackHandlers.filter {$0 === ack ? false : true}
}
// We lost connection and should attempt to reestablish
func tryReconnect() {
if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts {

View File

@ -24,7 +24,7 @@
import Foundation
enum SocketPacketType: Int {
enum SocketPacketType:Int {
case CONNECT = 0
case DISCONNECT = 1
case EVENT = 2