Merge pull request #344 from socketio/development

Development
This commit is contained in:
Erik Little 2016-04-11 18:55:27 -04:00
commit c9f653ef2c
19 changed files with 164 additions and 149 deletions

View File

@ -116,6 +116,7 @@
7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; 7420CB791C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; 7420CB7A1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; }; 7420CB7B1C49629E00956AA4 /* SocketEnginePollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */; };
742D150C1CA5794B00BD987D /* SocketObjectiveCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 742D150B1CA5794B00BD987D /* SocketObjectiveCTest.m */; };
74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */; }; 74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */; };
74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */; }; 74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */; };
7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74ABF7761C3991C10078C657 /* SocketClientSpec.swift */; }; 7471CCEA1C39926300364B59 /* SocketClientSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74ABF7761C3991C10078C657 /* SocketClientSpec.swift */; };
@ -187,6 +188,7 @@
74171E621C10CD240062D398 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; }; 74171E621C10CD240062D398 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; };
741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; }; 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEnginePollable.swift; path = Source/SocketEnginePollable.swift; sourceTree = "<group>"; }; 7420CB781C49629E00956AA4 /* SocketEnginePollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketEnginePollable.swift; path = Source/SocketEnginePollable.swift; sourceTree = "<group>"; };
742D150B1CA5794B00BD987D /* SocketObjectiveCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketObjectiveCTest.m; sourceTree = "<group>"; };
74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketAckManagerTest.swift; sourceTree = "<group>"; }; 74321DC91C2D939A00CF6F43 /* SocketAckManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketAckManagerTest.swift; sourceTree = "<group>"; };
74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = "<group>"; }; 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketParserTest.swift; sourceTree = "<group>"; };
7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespacePacketTest.swift; sourceTree = "<group>"; }; 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketNamespacePacketTest.swift; sourceTree = "<group>"; };
@ -326,6 +328,7 @@
74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */, 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */,
741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */, 741F39ED1BD025D80026C9CC /* SocketEngineTest.swift */,
7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */, 7472C65B1BCAB53E003CA70D /* SocketNamespacePacketTest.swift */,
742D150B1CA5794B00BD987D /* SocketObjectiveCTest.m */,
74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */, 74321DCA1C2D939A00CF6F43 /* SocketParserTest.swift */,
7472C65E1BCAC46E003CA70D /* SocketSideEffectTest.swift */, 7472C65E1BCAC46E003CA70D /* SocketSideEffectTest.swift */,
572EF2471B51F18A00EEBB58 /* Supporting Files */, 572EF2471B51F18A00EEBB58 /* Supporting Files */,
@ -513,7 +516,7 @@
572EF20E1B51F12F00EEBB58 /* Project object */ = { 572EF20E1B51F12F00EEBB58 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0710; LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0720; LastUpgradeCheck = 0720;
TargetAttributes = { TargetAttributes = {
572EF2181B51F16C00EEBB58 = { 572EF2181B51F16C00EEBB58 = {
@ -687,6 +690,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
742D150C1CA5794B00BD987D /* SocketObjectiveCTest.m in Sources */,
74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */, 74321DCB1C2D939A00CF6F43 /* SocketAckManagerTest.swift in Sources */,
74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */, 74321DCC1C2D939A00CF6F43 /* SocketParserTest.swift in Sources */,
7472C6601BCAC46E003CA70D /* SocketSideEffectTest.swift in Sources */, 7472C6601BCAC46E003CA70D /* SocketSideEffectTest.swift in Sources */,
@ -1169,6 +1173,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
}; };
name = Debug; name = Debug;
}; };

View File

@ -0,0 +1,45 @@
//
// SocketObjectiveCTest.m
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/25/16.
//
// Merely tests whether the Objective-C api breaks
//
#import <XCTest/XCTest.h>
@import SocketIOClientSwift;
@interface SocketObjectiveCTest : XCTestCase
@property SocketIOClient* socket;
@end
@implementation SocketObjectiveCTest
- (void)setUp {
[super setUp];
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
self.socket = [[SocketIOClient alloc] initWithSocketURL:url options:nil];
}
- (void)testOnSyntax {
[self.socket on:@"someCallback" callback:^(NSArray* data, SocketAckEmitter* ack) {
[ack with:@[@1]];
}];
}
- (void)testEmitSyntax {
[self.socket emit:@"testEmit" withItems:@[@YES]];
}
- (void)testEmitWithAckSyntax {
[self.socket emitWithAck:@"testAckEmit" withItems:@[@YES]];
}
- (void)testOffSyntax {
[self.socket off:@"test"];
}
@end

View File

@ -25,6 +25,7 @@ class SocketParserTest: XCTestCase {
"0/swift": ("/swift", [], [], -1), "0/swift": ("/swift", [], [], -1),
"1/swift": ("/swift", [], [], -1), "1/swift": ("/swift", [], [], -1),
"4\"ERROR\"": ("/", ["ERROR"], [], -1), "4\"ERROR\"": ("/", ["ERROR"], [], -1),
"4{\"test\":2}": ("/", [["test": 2]], [], -1),
"41": ("/", [1], [], -1)] "41": ("/", [1], [], -1)]
func testDisconnect() { func testDisconnect() {
@ -87,6 +88,11 @@ class SocketParserTest: XCTestCase {
validateParseResult(message) validateParseResult(message)
} }
func testErrorTypeDictionary() {
let message = "4{\"test\":2}"
validateParseResult(message)
}
func testErrorTypeInt() { func testErrorTypeInt() {
let message = "41" let message = "41"
validateParseResult(message) validateParseResult(message)

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
public final class SocketAckEmitter: NSObject { public final class SocketAckEmitter : NSObject {
let socket: SocketIOClient let socket: SocketIOClient
let ackNum: Int let ackNum: Int

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
private struct SocketAck: Hashable, Equatable { private struct SocketAck : Hashable, Equatable {
let ack: Int let ack: Int
var callback: AckCallback! var callback: AckCallback!
var hashValue: Int { var hashValue: Int {

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
public final class SocketAnyEvent: NSObject { public final class SocketAnyEvent : NSObject {
public let event: String public let event: String
public let items: NSArray? public let items: NSArray?
override public var description: String { override public var description: String {

View File

@ -22,7 +22,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
protocol SocketClientSpec: class { protocol SocketClientSpec : class {
var nsp: String { get set } var nsp: String { get set }
var waitingPackets: [SocketPacket] { get set } var waitingPackets: [SocketPacket] { get set }

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWebsocket { public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWebsocket {
public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL) public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL) public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL) public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
@ -47,7 +47,6 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
public private(set) var forcePolling = false public private(set) var forcePolling = false
public private(set) var forceWebsockets = false public private(set) var forceWebsockets = false
public private(set) var invalidated = false public private(set) var invalidated = false
public private(set) var pingTimer: NSTimer?
public private(set) var polling = true public private(set) var polling = true
public private(set) var probing = false public private(set) var probing = false
public private(set) var session: NSURLSession? public private(set) var session: NSURLSession?
@ -123,18 +122,6 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? []) self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
} }
@available(*, deprecated=5.3, message="Please use the NSURL based init")
public convenience init(client: SocketEngineClient, urlString: String, options: Set<SocketIOClientOption>) {
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
self.init(client: client, url: url, options: options)
}
@available(*, deprecated=5.3, message="Please use the NSURL based init")
public convenience init(client: SocketEngineClient, urlString: String, options: NSDictionary?) {
guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") }
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
}
deinit { deinit {
DefaultSocketLogger.Logger.log("Engine is being released", type: logType) DefaultSocketLogger.Logger.log("Engine is being released", type: logType)
closed = true closed = true
@ -185,15 +172,11 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
} }
} }
public func close(reason: String) {
disconnect(reason)
}
/// Starts the connection to the server /// Starts the connection to the server
public func connect() { public func connect() {
if connected { if connected {
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType) DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType)
close("reconnect") disconnect("reconnect")
} }
DefaultSocketLogger.Logger.log("Starting engine", type: logType) DefaultSocketLogger.Logger.log("Starting engine", type: logType)
@ -285,7 +268,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
public func didError(error: String) { public func didError(error: String) {
DefaultSocketLogger.Logger.error(error, type: logType) DefaultSocketLogger.Logger.error(error, type: logType)
client?.engineDidError(error) client?.engineDidError(error)
close(error) disconnect(error)
} }
public func disconnect(reason: String) { public func disconnect(reason: String) {
@ -295,7 +278,6 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
invalidated = true invalidated = true
connected = false connected = false
pingTimer?.invalidate()
ws?.disconnect() ws?.disconnect()
stopPolling() stopPolling()
client?.engineDidClose(reason) client?.engineDidClose(reason)
@ -401,8 +383,7 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
createWebsocketAndConnect() createWebsocketAndConnect()
} }
sendPing()
startPingTimer()
if !forceWebsockets { if !forceWebsockets {
doPoll() doPoll()
@ -425,10 +406,6 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
} }
} }
public func open() {
connect()
}
public func parseEngineData(data: NSData) { public func parseEngineData(data: NSData) {
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data) DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1))) client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
@ -487,26 +464,24 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
websocket = false websocket = false
} }
@objc private func sendPing() { private func sendPing() {
if !connected {
return
}
//Server is not responding //Server is not responding
if pongsMissed > pongsMissedMax { if pongsMissed > pongsMissedMax {
pingTimer?.invalidate()
client?.engineDidClose("Ping timeout") client?.engineDidClose("Ping timeout")
return return
} }
pongsMissed += 1
write("", withType: .Ping, withData: [])
}
private func startPingTimer() {
if let pingInterval = pingInterval { if let pingInterval = pingInterval {
pingTimer?.invalidate() pongsMissed += 1
pingTimer = nil write("", withType: .Ping, withData: [])
dispatch_async(dispatch_get_main_queue()) { let time = dispatch_time(DISPATCH_TIME_NOW, Int64(pingInterval * Double(NSEC_PER_SEC)))
self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(pingInterval, target: self, dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
selector: #selector(SocketEngine.sendPing), userInfo: nil, repeats: true) self?.sendPing()
} }
} }
} }
@ -562,7 +537,6 @@ public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWeb
} }
if websocket { if websocket {
pingTimer?.invalidate()
connected = false connected = false
websocket = false websocket = false

View File

@ -25,6 +25,6 @@
import Foundation import Foundation
@objc public enum SocketEnginePacketType: Int { @objc public enum SocketEnginePacketType : Int {
case Open, Close, Ping, Pong, Message, Upgrade, Noop case Open, Close, Ping, Pong, Message, Upgrade, Noop
} }

View File

@ -25,7 +25,7 @@
import Foundation import Foundation
/// Protocol that is used to implement socket.io polling support /// Protocol that is used to implement socket.io polling support
public protocol SocketEnginePollable: SocketEngineSpec { public protocol SocketEnginePollable : SocketEngineSpec {
var invalidated: Bool { get } var invalidated: Bool { get }
/// Holds strings waiting to be sent over polling. /// Holds strings waiting to be sent over polling.
/// You shouldn't need to mess with this. /// You shouldn't need to mess with this.

View File

@ -37,7 +37,6 @@ import Foundation
var forcePolling: Bool { get } var forcePolling: Bool { get }
var forceWebsockets: Bool { get } var forceWebsockets: Bool { get }
var parseQueue: dispatch_queue_t! { get } var parseQueue: dispatch_queue_t! { get }
var pingTimer: NSTimer? { get }
var polling: Bool { get } var polling: Bool { get }
var probing: Bool { get } var probing: Bool { get }
var emitQueue: dispatch_queue_t! { get } var emitQueue: dispatch_queue_t! { get }
@ -50,13 +49,11 @@ import Foundation
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
@available(*, deprecated=5.5, message="Please use disconnect") func close(reason: String)
func connect() func connect()
func didError(error: String) func didError(error: String)
func disconnect(reason: String) func disconnect(reason: String)
func doFastUpgrade() func doFastUpgrade()
func flushWaitingForPostToWebSocket() func flushWaitingForPostToWebSocket()
@available(*, deprecated=5.5, message="Please use connect") func open()
func parseEngineData(data: NSData) func parseEngineData(data: NSData)
func parseEngineMessage(message: String, fromPolling: Bool) func parseEngineMessage(message: String, fromPolling: Bool)
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])

View File

@ -26,7 +26,7 @@
import Foundation import Foundation
/// Protocol that is used to implement socket.io WebSocket support /// Protocol that is used to implement socket.io WebSocket support
public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { public protocol SocketEngineWebsocket : SocketEngineSpec, WebSocketDelegate {
var ws: WebSocket? { get } var ws: WebSocket? { get }
func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData])

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable { public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable {
public let socketURL: NSURL public let socketURL: NSURL
public private(set) var engine: SocketEngineSpec? public private(set) var engine: SocketEngineSpec?
@ -46,7 +46,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
public var reconnects = true public var reconnects = true
public var reconnectWait = 10 public var reconnectWait = 10
public var sid: String? { public var sid: String? {
return engine?.sid return nsp + "#" + (engine?.sid ?? "")
} }
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL) private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
@ -108,18 +108,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? []) self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
} }
@available(*, deprecated=5.3, message="Please use the NSURL based init")
public convenience init(socketURLString: String, options: Set<SocketIOClientOption> = []) {
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
self.init(socketURL: url, options: options)
}
@available(*, deprecated=5.3, message="Please use the NSURL based init")
public convenience init(socketURLString: String, options: NSDictionary?) {
guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") }
self.init(socketURL: url, options: options?.toSocketOptionsSet() ?? [])
}
deinit { deinit {
DefaultSocketLogger.Logger.log("Client is being released", type: logType) DefaultSocketLogger.Logger.log("Client is being released", type: logType)
engine?.disconnect("Client Deinit") engine?.disconnect("Client Deinit")
@ -133,11 +121,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
return engine! return engine!
} }
@available(*, deprecated=5.3, message="Please use disconnect()")
public func close() {
disconnect()
}
/// Connect to the server. /// Connect to the server.
public func connect() { public func connect() {
connect(timeoutAfter: 0, withTimeoutHandler: nil) connect(timeoutAfter: 0, withTimeoutHandler: nil)
@ -181,10 +164,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
return {[weak self, ack = currentAck] timeout, callback in return {[weak self, ack = currentAck] timeout, callback in
if let this = self { if let this = self {
this.ackHandlers.addAck(ack, callback: callback) this.ackHandlers.addAck(ack, callback: callback)
this._emit(items, ack: ack)
dispatch_async(this.emitQueue) {
this._emit(items, ack: ack)
}
if timeout != 0 { if timeout != 0 {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC)) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
@ -240,38 +220,34 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
return return
} }
dispatch_async(emitQueue) {[emitData = [event] + items] in _emit([event] + items)
self._emit(emitData)
}
} }
/** /// Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add /// an ack.
an ack.
*/
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback { public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
return emitWithAck(event, withItems: items) return emitWithAck(event, withItems: items)
} }
/** /// Same as emitWithAck, but for Objective-C
Same as emitWithAck, but for Objective-C
*/
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback { public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
return createOnAck([event] + items) return createOnAck([event] + items)
} }
private func _emit(data: [AnyObject], ack: Int? = nil) { private func _emit(data: [AnyObject], ack: Int? = nil) {
guard status == .Connected else { dispatch_async(emitQueue) {
handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true) guard self.status == .Connected else {
return self.handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
return
}
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: self.nsp, ack: false)
let str = packet.packetString
DefaultSocketLogger.Logger.log("Emitting: %@", type: self.logType, args: str)
self.engine?.send(str, withData: packet.binary)
} }
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
let str = packet.packetString
DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str)
engine?.send(str, withData: packet.binary)
} }
// If the server wants to know that the client received data // If the server wants to know that the client received data
@ -312,7 +288,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
// Called when the socket gets an ack for something it sent // Called when the socket gets an ack for something it sent
func handleAck(ack: Int, data: [AnyObject]) { func handleAck(ack: Int, data: [AnyObject]) {
guard status == .Connected else {return} guard status == .Connected else { return }
DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "") DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
@ -402,11 +378,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
anyHandler = handler anyHandler = handler
} }
@available(*, deprecated=5.3, message="Please use one of the connect methods)")
public func open() {
connect()
}
public func parseEngineMessage(msg: String) { public func parseEngineMessage(msg: String) {
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg) DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
@ -443,15 +414,13 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
} }
} }
@objc private func _tryReconnect() { private func _tryReconnect() {
if !reconnecting { if !reconnecting {
return return
} }
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects { if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
didDisconnect("Reconnect Failed") return didDisconnect("Reconnect Failed")
return
} }
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType) DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)

View File

@ -24,11 +24,11 @@
import Foundation import Foundation
protocol ClientOption: CustomStringConvertible, Hashable { protocol ClientOption : CustomStringConvertible, Hashable {
func getSocketIOOptionValue() -> AnyObject func getSocketIOOptionValue() -> AnyObject
} }
public enum SocketIOClientOption: ClientOption { public enum SocketIOClientOption : ClientOption {
case ConnectParams([String: AnyObject]) case ConnectParams([String: AnyObject])
case Cookies([NSHTTPCookie]) case Cookies([NSHTTPCookie])
case DoubleEncodeUTF8(Bool) case DoubleEncodeUTF8(Bool)
@ -152,7 +152,7 @@ public func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
return lhs.description == rhs.description return lhs.description == rhs.description
} }
extension Set where Element: ClientOption { extension Set where Element : ClientOption {
mutating func insertIgnore(element: Element) { mutating func insertIgnore(element: Element) {
if !contains(element) { if !contains(element) {
insert(element) insert(element)

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
@objc public enum SocketIOClientStatus: Int, CustomStringConvertible { @objc public enum SocketIOClientStatus : Int, CustomStringConvertible {
case NotConnected, Closed, Connecting, Connected case NotConnected, Closed, Connecting, Connected
public var description: String { public var description: String {

View File

@ -24,7 +24,7 @@
import Foundation import Foundation
public protocol SocketLogger: class { public protocol SocketLogger : class {
/// Whether to log or not /// Whether to log or not
var log: Bool {get set} var log: Bool {get set}
@ -54,7 +54,7 @@ public extension SocketLogger {
} }
} }
class DefaultSocketLogger: SocketLogger { class DefaultSocketLogger : SocketLogger {
static var Logger: SocketLogger = DefaultSocketLogger() static var Logger: SocketLogger = DefaultSocketLogger()
var log = false var log = false

View File

@ -22,7 +22,7 @@
import Foundation import Foundation
protocol SocketParsable: SocketClientSpec { protocol SocketParsable : SocketClientSpec {
func parseBinaryData(data: NSData) func parseBinaryData(data: NSData)
func parseSocketMessage(message: String) func parseSocketMessage(message: String)
} }
@ -76,7 +76,7 @@ extension SocketParsable {
return .Right(SocketPacket(type: type, nsp: "/")) return .Right(SocketPacket(type: type, nsp: "/"))
} }
var namespace: String? var namespace = "/"
var placeholders = -1 var placeholders = -1
if type == .BinaryEvent || type == .BinaryAck { if type == .BinaryEvent || type == .BinaryAck {
@ -116,26 +116,27 @@ extension SocketParsable {
switch parseData(noPlaceholders) { switch parseData(noPlaceholders) {
case let .Left(err): case let .Left(err):
// If first you don't succeed, try again // Errors aren't always enclosed in an array
if case let .Right(data) = parseData("\([noPlaceholders as AnyObject])") { if case let .Right(data) = parseData("\([noPlaceholders as AnyObject])") {
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1, return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders)) nsp: namespace, placeholders: placeholders))
} else { } else {
return .Left(err) return .Left(err)
} }
case let .Right(data): case let .Right(data):
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1, return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders)) nsp: namespace, placeholders: placeholders))
} }
} }
// Parses data for events // Parses data for events
private func parseData(data: String) -> Either<String, [AnyObject]> { private func parseData(data: String) -> Either<String, [AnyObject]> {
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
do { do {
if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!, if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!,
options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] { options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] {
return .Right(arr) return .Right(arr)
} else { } else {
return .Left("Expected data array") return .Left("Expected data array")
} }

View File

@ -18,7 +18,7 @@ infix operator <~ { associativity none precedence 130 }
private let lock = dispatch_semaphore_create(1) private let lock = dispatch_semaphore_create(1)
private var swiftRegexCache = [String: NSRegularExpression]() private var swiftRegexCache = [String: NSRegularExpression]()
internal final class SwiftRegex: NSObject, BooleanType { internal final class SwiftRegex : NSObject, BooleanType {
var target: String var target: String
var regex: NSRegularExpression var regex: NSRegularExpression

View File

@ -180,30 +180,42 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
} }
///write a string to the websocket. This sends it as a text frame. /**
public func writeString(str: String) { Write a string to the websocket. This sends it as a text frame.
If you supply a non-nil completion block, I will perform it when the write completes.
- parameter str: The string to write.
- parameter completion: The (optional) completion handler.
*/
public func writeString(str: String, completion: (() -> ())? = nil) {
guard isConnected else { return } guard isConnected else { return }
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame) dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame, writeCompletion: completion)
} }
///write binary data to the websocket. This sends it as a binary frame. /**
public func writeData(data: NSData) { Write binary data to the websocket. This sends it as a binary frame.
If you supply a non-nil completion block, I will perform it when the write completes.
- parameter data: The data to write.
- parameter completion: The (optional) completion handler.
*/
public func writeData(data: NSData, completion: (() -> ())? = nil) {
guard isConnected else { return } guard isConnected else { return }
dequeueWrite(data, code: .BinaryFrame) dequeueWrite(data, code: .BinaryFrame, writeCompletion: completion)
} }
//write a ping to the websocket. This sends it as a control frame. //write a ping to the websocket. This sends it as a control frame.
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s //yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
public func writePing(data: NSData) { public func writePing(data: NSData, completion: (() -> ())? = nil) {
guard isConnected else { return } guard isConnected else { return }
dequeueWrite(data, code: .Ping) dequeueWrite(data, code: .Ping, writeCompletion: completion)
} }
//private method that starts the connection //private method that starts the connection
private func createHTTPRequest() { private func createHTTPRequest() {
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET", let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
url, kCFHTTPVersion1_1).takeRetainedValue() url, kCFHTTPVersion1_1).takeRetainedValue()
var port = url.port var port = url.port
if port == nil { if port == nil {
@ -283,18 +295,18 @@ public class WebSocket : NSObject, NSStreamDelegate {
if let cipherSuites = self.enabledSSLCipherSuites { if let cipherSuites = self.enabledSSLCipherSuites {
if let sslContextIn = CFReadStreamCopyProperty(inputStream, kCFStreamPropertySSLContext) as! SSLContextRef?, if let sslContextIn = CFReadStreamCopyProperty(inputStream, kCFStreamPropertySSLContext) as! SSLContextRef?,
sslContextOut = CFWriteStreamCopyProperty(outputStream, kCFStreamPropertySSLContext) as! SSLContextRef? { sslContextOut = CFWriteStreamCopyProperty(outputStream, kCFStreamPropertySSLContext) as! SSLContextRef? {
let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count) let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count)
let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count) let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count)
if resIn != errSecSuccess { if resIn != errSecSuccess {
let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn)) let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn))
disconnectStream(error) disconnectStream(error)
return return
} }
if resOut != errSecSuccess { if resOut != errSecSuccess {
let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut)) let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut))
disconnectStream(error) disconnectStream(error)
return return
} }
} }
} }
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue) CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
@ -428,7 +440,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
} }
case -1: case -1:
fragBuffer = NSData(bytes: buffer, length: bufferLen) fragBuffer = NSData(bytes: buffer, length: bufferLen)
break //do nothing, we are going to collect more data break //do nothing, we are going to collect more data
default: default:
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code))) doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
} }
@ -547,10 +559,10 @@ public class WebSocket : NSObject, NSStreamDelegate {
let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping) let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping)
if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame && if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame &&
receivedOpcode != .TextFrame && receivedOpcode != .Pong) { receivedOpcode != .TextFrame && receivedOpcode != .Pong) {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)) doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode))
writeError(errCode) writeError(errCode)
return return
} }
if isControlFrame && isFin == 0 { if isControlFrame && isFin == 0 {
let errCode = CloseCode.ProtocolError.rawValue let errCode = CloseCode.ProtocolError.rawValue
@ -603,7 +615,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
if dataLength > UInt64(bufferLen) { if dataLength > UInt64(bufferLen) {
len = UInt64(bufferLen-offset) len = UInt64(bufferLen-offset)
} }
var data: NSData! let data: NSData
if len < 0 { if len < 0 {
len = 0 len = 0
data = NSData() data = NSData()
@ -739,7 +751,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose) dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
} }
///used to write things to the stream ///used to write things to the stream
private func dequeueWrite(data: NSData, code: OpCode) { private func dequeueWrite(data: NSData, code: OpCode, writeCompletion: (() -> ())? = nil) {
writeQueue.addOperationWithBlock { [weak self] in writeQueue.addOperationWithBlock { [weak self] in
//stream isn't ready, let's wait //stream isn't ready, let's wait
guard let s = self else { return } guard let s = self else { return }
@ -788,6 +800,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
total += len total += len
} }
if total >= offset { if total >= offset {
if let queue = self?.queue, callback = writeCompletion {
dispatch_async(queue) {
callback()
}
}
break break
} }
} }