Merge pull request #141 from lightsprint09/API-improvements

Api improvements
This commit is contained in:
Erik Little 2015-08-10 10:57:13 -04:00
commit b52684cb8f
5 changed files with 92 additions and 127 deletions

View File

@ -20,11 +20,12 @@ class AbstractSocketTest: XCTestCase {
func openConnection() { func openConnection() {
let expection = self.expectationWithDescription("connect") let expection = self.expectationWithDescription("connect")
XCTAssertTrue(socket.status == SocketIOClientStatus.NotConnected)
socket.on("connect") {data, ack in socket.on("connect") {data, ack in
expection.fulfill() expection.fulfill()
} }
socket.connect() socket.connect()
XCTAssertTrue(socket.connecting) XCTAssertEqual(socket.status, SocketIOClientStatus.Connecting)
waitForExpectationsWithTimeout(AbstractSocketTest.TEST_TIMEOUT, handler: nil) waitForExpectationsWithTimeout(AbstractSocketTest.TEST_TIMEOUT, handler: nil)
} }
@ -33,10 +34,7 @@ class AbstractSocketTest: XCTestCase {
} }
func checkConnectionStatus() { func checkConnectionStatus() {
XCTAssertTrue(socket.connected) XCTAssertEqual(socket.status, SocketIOClientStatus.Connected)
XCTAssertFalse(socket.connecting)
XCTAssertFalse(socket.reconnecting)
XCTAssertFalse(socket.closed)
XCTAssertFalse(socket.secure) XCTAssertFalse(socket.secure)
} }

View File

@ -52,8 +52,8 @@ class SocketTestCases: NSObject {
func didGetResult(result:NSArray?, ack:AckEmitter?) { func didGetResult(result:NSArray?, ack:AckEmitter?) {
if let array = result?.firstObject as? NSArray { if let array = result?.firstObject as? NSArray {
XCTAssertEqual(array.count, 2) XCTAssertEqual(array.count, 2)
XCTAssertEqual(array.firstObject! as! String, "test3") XCTAssertEqual((array.firstObject! as! String), "test3")
XCTAssertEqual(array.lastObject! as! String, "test4") XCTAssertEqual((array.lastObject! as! String), "test4")
}else { }else {
XCTFail("Should have NSArray as result") XCTFail("Should have NSArray as result")
} }
@ -113,10 +113,10 @@ class SocketTestCases: NSObject {
let testName = "testJSONWithBuffer" let testName = "testJSONWithBuffer"
func didGetResult(result:NSArray?, ack:AckEmitter?) { func didGetResult(result:NSArray?, ack:AckEmitter?) {
if let json = result?.firstObject as? NSDictionary { if let json = result?.firstObject as? NSDictionary {
XCTAssertEqual(json.valueForKey("testString")! as! String, "test") XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
XCTAssertEqual(json.valueForKey("testNumber")! as! Int, 15) XCTAssertEqual((json.valueForKey("testNumber")! as! Int), 15)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2) XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).last! as! Int, 1) XCTAssertEqual(((json.valueForKey("testArray")! as! Array<AnyObject>).last! as! Int), 1)
let string = NSString(data: (json.valueForKey("testArray")! as! Array<AnyObject>).first! as! NSData, encoding: NSUTF8StringEncoding)! let string = NSString(data: (json.valueForKey("testArray")! as! Array<AnyObject>).first! as! NSData, encoding: NSUTF8StringEncoding)!
XCTAssertEqual(string, "gakgakgak2") XCTAssertEqual(string, "gakgakgak2")
}else { }else {
@ -132,11 +132,11 @@ class SocketTestCases: NSObject {
let testName = "testJSON" let testName = "testJSON"
func didGetResult(result:NSArray?, ack:AckEmitter?) { func didGetResult(result:NSArray?, ack:AckEmitter?) {
if let json = result?.firstObject as? NSDictionary { if let json = result?.firstObject as? NSDictionary {
XCTAssertEqual(json.valueForKey("testString")! as! String, "test") XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
XCTAssertEqual(json.valueForKey("testNumber")! as! Int, 15) XCTAssertEqual(json.valueForKey("testNumber")! as? Int, 15)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2) XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).first! as! Int, 1) XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).first! as? Int, 1)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).last! as! Int, 1) XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).last! as? Int, 1)
}else { }else {
XCTFail("Should have NSDictionary as result") XCTFail("Should have NSDictionary as result")
@ -168,13 +168,13 @@ class SocketTestCases: NSObject {
return return
} }
if let array = result?.firstObject as? Array<AnyObject> { if let array = result?.firstObject as? Array<AnyObject> {
XCTAssertEqual(array.last! as! Int, 2) XCTAssertEqual((array.last! as! Int), 2)
XCTAssertEqual(array.first! as! Int, 1) XCTAssertEqual((array.first! as! Int), 1)
}else { }else {
XCTFail("Should have Array as result") XCTFail("Should have Array as result")
} }
if let dict = result?[1] as? NSDictionary { if let dict = result?[1] as? NSDictionary {
XCTAssertEqual(dict.valueForKey("test") as! String, "bob") XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
}else { }else {
XCTFail("Should have NSDictionary as result") XCTFail("Should have NSDictionary as result")
@ -212,13 +212,13 @@ class SocketTestCases: NSObject {
return return
} }
if let array = result?.firstObject as? Array<AnyObject> { if let array = result?.firstObject as? Array<AnyObject> {
XCTAssertEqual(array.last! as! Int, 2) XCTAssertEqual((array.last! as! Int), 2)
XCTAssertEqual(array.first! as! Int, 1) XCTAssertEqual((array.first! as! Int), 1)
}else { }else {
XCTFail("Should have Array as result") XCTFail("Should have Array as result")
} }
if let dict = result?[1] as? NSDictionary { if let dict = result?[1] as? NSDictionary {
XCTAssertEqual(dict.valueForKey("test") as! String, "bob") XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
}else { }else {
XCTFail("Should have NSDictionary as result") XCTFail("Should have NSDictionary as result")

View File

@ -325,8 +325,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!) let req = NSMutableURLRequest(URL: NSURL(string: urlPolling! + "&sid=\(sid)")!)
if cookies != nil { if let cookies = cookies {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
req.allHTTPHeaderFields = headers req.allHTTPHeaderFields = headers
} }
@ -375,8 +375,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
private func handleClose() { private func handleClose() {
if polling { if let client = client where polling == true {
client?.engineDidClose("Disconnect") client.engineDidClose("Disconnect")
} }
} }
@ -494,8 +494,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
reqPolling.allHTTPHeaderFields = headers reqPolling.allHTTPHeaderFields = headers
} }
if extraHeaders != nil { if let extraHeaders = extraHeaders {
for (headerName, value) in extraHeaders! { for (headerName, value) in extraHeaders {
reqPolling.setValue(value, forHTTPHeaderField: headerName) reqPolling.setValue(value, forHTTPHeaderField: headerName)
} }
} }
@ -504,11 +504,10 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
} }
// Translatation of engine.io-parser#decodePayload // Translatation of engine.io-parser#decodePayload
private func parsePollingMessage(str: String) { private func parsePollingMessage(str:String) {
if str.characters.count == 1 { guard str.characters.count != 1 else {
return return
} }
// println(str) // println(str)
let strArray = Array(str.characters) let strArray = Array(str.characters)
@ -633,8 +632,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
postWait.append(strMsg) postWait.append(strMsg)
if datas != nil { if let datas = datas {
for data in datas! { for data in datas {
let (_, b64Data) = createBinaryDataForSend(data) let (_, b64Data) = createBinaryDataForSend(data)
postWait.append(b64Data!) postWait.append(b64Data!)
@ -654,8 +653,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
ws?.writeString("\(type.rawValue)\(str)") ws?.writeString("\(type.rawValue)\(str)")
if datas != nil { if let datas = datas {
for data in datas! { for data in datas {
let (data, _) = createBinaryDataForSend(data) let (data, _) = createBinaryDataForSend(data)
if data != nil { if data != nil {
ws?.writeData(data!) ws?.writeData(data!)
@ -666,7 +665,7 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
// Starts the ping timer // Starts the ping timer
private func startPingTimer() { private func startPingTimer() {
if pingInterval == nil { guard pingInterval != nil else {
return return
} }
@ -719,8 +718,8 @@ public final class SocketEngine: NSObject, WebSocketDelegate, SocketLogClient {
if let pType = PacketType(rawValue: type) { if let pType = PacketType(rawValue: type) {
var arr = [NSData]() var arr = [NSData]()
if data != nil { if let data = data {
for d in data! { for d in data {
arr.append(d as! NSData) arr.append(d as! NSData)
} }
} }

View File

@ -26,14 +26,11 @@ import Foundation
public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient { public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient {
private var anyHandler:((SocketAnyEvent) -> Void)? private var anyHandler:((SocketAnyEvent) -> Void)?
private var _closed = false public private(set) var status = SocketIOClientStatus.NotConnected
private var _connected = false
private var _connecting = false
private var currentReconnectAttempt = 0 private var currentReconnectAttempt = 0
private var handlers = ContiguousArray<SocketEventHandler>() private var handlers = ContiguousArray<SocketEventHandler>()
public private(set) var secure = false
private var connectParams: [String: AnyObject]? private var connectParams: [String: AnyObject]?
private var _secure = false
private var _reconnecting = false
private var reconnectTimer: NSTimer? private var reconnectTimer: NSTimer?
let reconnectAttempts: Int! let reconnectAttempts: Int!
@ -47,27 +44,13 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
public let handleAckQueue = dispatch_queue_create("handleAckQueue", DISPATCH_QUEUE_SERIAL) public let handleAckQueue = dispatch_queue_create("handleAckQueue", DISPATCH_QUEUE_SERIAL)
public let handleQueue: dispatch_queue_t! public let handleQueue: dispatch_queue_t!
public let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL) public let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL)
public var closed: Bool {
return _closed
}
public var connected: Bool {
return _connected
}
public var connecting: Bool {
return _connecting
}
public var engine:SocketEngine? public var engine:SocketEngine?
public var nsp = "/" public var nsp = "/"
public var opts: [String: AnyObject]? public var opts: [String: AnyObject]?
public var reconnects = true public var reconnects = true
public var reconnecting: Bool {
return _reconnecting
}
public var reconnectWait = 10 public var reconnectWait = 10
public var secure: Bool { public var sid:String? {
return _secure
}
public var sid: String? {
return engine?.sid return engine?.sid
} }
@ -76,7 +59,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
*/ */
public init(var socketURL: String, opts: [String: AnyObject]? = nil) { public init(var socketURL: String, opts: [String: AnyObject]? = nil) {
if socketURL["https://"].matches().count != 0 { if socketURL["https://"].matches().count != 0 {
self._secure = true self.secure = true
} }
socketURL = socketURL["http://"] ~= "" socketURL = socketURL["http://"] ~= ""
@ -145,9 +128,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
SocketLogger.log("Closing socket", client: self) SocketLogger.log("Closing socket", client: self)
reconnects = false reconnects = false
_connecting = false status = SocketIOClientStatus.Closed
_connected = false
_reconnecting = false
engine?.close(fast: fast) engine?.close(fast: fast)
engine = nil engine = nil
} }
@ -162,28 +143,28 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
/** /**
Connect to the server. If we aren't connected after timeoutAfter, call handler Connect to the server. If we aren't connected after timeoutAfter, call handler
*/ */
public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) { public func connect(timeoutAfter timeoutAfter:Int,
if closed { withTimeoutHandler handler:(() -> Void)?) {
SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self) guard status != SocketIOClientStatus.Connected else {
_closed = false
} else if connected {
return return
} }
if status == SocketIOClientStatus.Closed {
SocketLogger.log("Warning! This socket was previously closed. This might be dangerous!", client: self)
}
_connecting = true status = SocketIOClientStatus.Connecting
addEngine() addEngine()
engine?.open(connectParams) engine?.open(connectParams)
if timeoutAfter == 0 { guard timeoutAfter != 0 else {
return return
} }
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC)) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
if let this = self where !this.connected { if let this = self where this.status != SocketIOClientStatus.Connected {
this._closed = true this.status = SocketIOClientStatus.Closed
this._connecting = false
this.engine?.close(fast: true) this.engine?.close(fast: true)
handler?() handler?()
@ -213,11 +194,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
func didConnect() { func didConnect() {
SocketLogger.log("Socket connected", client: self) SocketLogger.log("Socket connected", client: self)
status = SocketIOClientStatus.Connected
_closed = false
_connected = true
_connecting = false
_reconnecting = false
currentReconnectAttempt = 0 currentReconnectAttempt = 0
clearReconnectTimer() clearReconnectTimer()
@ -226,18 +203,16 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
handleEvent("connect", data: nil, isInternalMessage: false) handleEvent("connect", data: nil, isInternalMessage: false)
} }
func didDisconnect(reason: String) { func didDisconnect(reason:String) {
if closed { guard status != SocketIOClientStatus.Closed else {
return return
} }
SocketLogger.log("Disconnected: %@", client: self, args: reason) SocketLogger.log("Disconnected: %@", client: self, args: reason)
_closed = true status = SocketIOClientStatus.Closed
_connected = false
reconnects = false reconnects = false
_connecting = false
_reconnecting = false
// Make sure the engine is actually dead. // Make sure the engine is actually dead.
engine?.close(fast: true) engine?.close(fast: true)
@ -262,21 +237,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
/** /**
Send a message to the server Send a message to the server
*/ */
public func emit(event:String, _ items: AnyObject...) { public func emit(event:String, _ items:AnyObject...) {
if !connected { emit(event, withItems: items)
return
}
dispatch_async(emitQueue) {[weak self] in
self?._emit(event, items)
}
} }
/** /**
Same as emit, but meant for Objective-C Same as emit, but meant for Objective-C
*/ */
public func emit(event: String, withItems items: [AnyObject]) { public func emit(event:String, withItems items:[AnyObject]) {
if !connected { guard status == SocketIOClientStatus.Connected else {
return return
} }
@ -289,27 +258,19 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
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 {
if !connected {
return createOnAck(event, items: items)
}
return createOnAck(event, items: items) return createOnAck(event, items: 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 {
if !connected {
return createOnAck(event, items: items)
}
return createOnAck(event, items: items) return createOnAck(event, items: items)
} }
private func _emit(event: String, _ args: [AnyObject], ack: Int? = nil) { private func _emit(event:String, _ args:[AnyObject], ack:Int? = nil) {
if !connected { guard status == SocketIOClientStatus.Connected else {
return return
} }
@ -328,7 +289,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
// If the server wants to know that the client received data // If the server wants to know that the client received data
func emitAck(ack: Int, withData args: [AnyObject]) { func emitAck(ack: Int, withData args: [AnyObject]) {
dispatch_async(emitQueue) {[weak self] in dispatch_async(emitQueue) {[weak self] in
if let this = self where this.connected { if let this = self where this.status == SocketIOClientStatus.Connected {
let packet = SocketPacket.packetFromEmitAckWithData(args, id: ack ?? -1, nsp: this.nsp) let packet = SocketPacket.packetFromEmitAckWithData(args, id: ack ?? -1, nsp: this.nsp)
let str = packet.createAck() let str = packet.createAck()
@ -344,13 +305,10 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
} }
} }
public func engineDidClose(reason: String) { public func engineDidClose(reason:String) {
_connected = false if status == SocketIOClientStatus.Closed || !reconnects {
_connecting = false
if closed || !reconnects {
didDisconnect(reason) didDisconnect(reason)
} else if !reconnecting { } else if status != SocketIOClientStatus.Reconnecting {
handleEvent("reconnect", data: [reason], isInternalMessage: true) handleEvent("reconnect", data: [reason], isInternalMessage: true)
tryReconnect() tryReconnect()
} }
@ -368,12 +326,12 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
/** /**
Causes an event to be handled. Only use if you know what you're doing. Causes an event to be handled. Only use if you know what you're doing.
*/ */
public func handleEvent(event: String, data: [AnyObject]?, isInternalMessage: Bool = false, public func handleEvent(event:String, data:[AnyObject]?, isInternalMessage:Bool = false,
wantsAck ack: Int? = nil) { wantsAck ack:Int? = nil) {
// println("Should do event: \(event) with data: \(data)") guard status == SocketIOClientStatus.Connected && !isInternalMessage else {
if !connected && !isInternalMessage {
return return
} }
// println("Should do event: \(event) with data: \(data)")
SocketLogger.log("Handling event: %@ with data: %@", client: self, SocketLogger.log("Handling event: %@ with data: %@", client: self,
args: event, data ?? "") args: event, data ?? "")
@ -385,9 +343,9 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
} }
for handler in handlers where handler.event == event { for handler in handlers where handler.event == event {
if ack != nil { if let ack = ack {
dispatch_async(handleQueue) {[weak self] in dispatch_async(handleQueue) {[weak self] in
handler.executeCallback(data, withAck: ack!, withSocket: self) handler.executeCallback(data, withAck: ack, withSocket: self)
} }
} else { } else {
dispatch_async(handleQueue) { dispatch_async(handleQueue) {
@ -418,6 +376,14 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
} }
} }
/**
Joins namespace /
*/
public func joinNamespace(namespace:String) {
self.nsp = namespace
joinNamespace()
}
/** /**
Removes handler(s) Removes handler(s)
*/ */
@ -481,30 +447,26 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketLogClient
Trieds to reconnect to the server. Trieds to reconnect to the server.
*/ */
public func reconnect() { public func reconnect() {
_connected = false status = SocketIOClientStatus.Reconnecting
_connecting = false
_reconnecting = false
engine?.stopPolling() engine?.stopPolling()
tryReconnect() tryReconnect()
} }
@objc private func tryReconnect() { @objc private func tryReconnect() {
guard status != SocketIOClientStatus.Connected else {
return
}
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects { if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
clearReconnectTimer() clearReconnectTimer()
didDisconnect("Reconnect Failed") didDisconnect("Reconnect Failed")
return
} else if connected {
_connecting = false
_reconnecting = false
return return
} }
if reconnectTimer == nil { if reconnectTimer == nil {
SocketLogger.log("Starting reconnect", client: self) SocketLogger.log("Starting reconnect", client: self)
_reconnecting = true status = SocketIOClientStatus.Reconnecting
dispatch_async(dispatch_get_main_queue()) {[weak self] in dispatch_async(dispatch_get_main_queue()) {[weak self] in
if let this = self { if let this = self {

View File

@ -29,4 +29,10 @@ public typealias AckEmitter = (AnyObject...) -> Void
public typealias AckEmitterObjectiveC = (NSArray) -> Void public typealias AckEmitterObjectiveC = (NSArray) -> Void
public typealias NormalCallback = (NSArray?, AckEmitter?) -> Void public typealias NormalCallback = (NSArray?, AckEmitter?) -> Void
public typealias NormalCallbackObjectiveC = (NSArray?, AckEmitterObjectiveC?) -> Void public typealias NormalCallbackObjectiveC = (NSArray?, AckEmitterObjectiveC?) -> Void
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void public typealias OnAckCallback = (timeoutAfter:UInt64, callback:AckCallback) -> Void
@objc public enum SocketIOClientStatus: Int {
case NotConnected, Closed, Connecting, Connected, Reconnecting
}