diff --git a/README.md b/README.md index cb35287..efe2f19 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Methods 6. `socket.emitWithAckObjc(event:String, withItems items:[AnyObject]) -> SocketAckHandler` - `emitWithAck` for Objective-C. 7. `socket.connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. 8. `socket.connectWithParams(params:[String: AnyObject])` - Establishes a connection to the server passing the specified params. A "connect" event is fired upon successful connection. -9. `socket.close()` - Closes the socket. Once a socket is closed it should not be reopened. +9. `socket.close(fast:Bool = false)` - Closes the socket. Once a socket is closed it should not be reopened. Pass true to fast if you're closing from a background task. Events ------ diff --git a/SwiftIO/SocketEngine.swift b/SwiftIO/SocketEngine.swift index c8be3ab..b815785 100644 --- a/SwiftIO/SocketEngine.swift +++ b/SwiftIO/SocketEngine.swift @@ -53,6 +53,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { private let handleQueue = dispatch_queue_create( "engineHandleQueue".cStringUsingEncoding(NSUTF8StringEncoding), DISPATCH_QUEUE_SERIAL) private let session:NSURLSession! + private var closed = false private var _connected = false private var fastUpgrade = false private var forcePolling = false @@ -81,7 +82,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { } var ws:WebSocket? - init(client:SocketEngineClient, forcePolling:Bool, withCookies cookies:[NSHTTPCookie]?) { + public init(client:SocketEngineClient, forcePolling:Bool, withCookies cookies:[NSHTTPCookie]?) { self.client = client self.forcePolling = forcePolling self.cookies = cookies @@ -89,9 +90,20 @@ public class SocketEngine: NSObject, WebSocketDelegate { delegate: nil, delegateQueue: self.workQueue) } - func close() { + public func close(#fast:Bool) { self.pingTimer?.invalidate() - self.send(PacketType.CLOSE.rawValue, withData: nil) + self.closed = true + + if self.polling { + self.write("", withType: PacketType.CLOSE, withData: nil) + self.client.didForceClose("Disconnect") + } else { + self.ws?.disconnect() + + if fast { + self.client.didForceClose("Fast Disconnect") + } + } } private func createBinaryDataForSend(data:NSData) -> (NSData?, String?) { @@ -174,7 +186,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { return } else if err != nil { if self!.polling { - self?.handlePollingFailed(err) + self?.handlePollingFailed(err.localizedDescription) } return @@ -191,7 +203,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { if self!.fastUpgrade { self?.doFastUpgrade() return - } else { + } else if !self!.closed { self?.doPoll() } }.resume() @@ -247,7 +259,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { if self == nil { return } else if err != nil && self!.polling { - self?.handlePollingFailed(err) + self?.handlePollingFailed(err.localizedDescription) return } @@ -270,24 +282,26 @@ public class SocketEngine: NSObject, WebSocketDelegate { } // A poll failed, tell the client about it - private func handlePollingFailed(reason:NSError) { - assert(self.polling, "Polling failed when we're not polling") + private func handlePollingFailed(reason:String) { + self._connected = false + self.ws?.disconnect() + self.pingTimer?.invalidate() + self.waitingForPoll = false + self.waitingForPost = false - if !self.client.reconnecting { - self._connected = false - self.ws?.disconnect() - self.pingTimer?.invalidate() - self.waitingForPoll = false - self.waitingForPost = false + if !self.closed && !self.client.reconnecting { self.client.pollingDidFail(reason) + } else if !self.client.reconnecting { + self.client.didForceClose(reason) } } - func open(opts:[String: AnyObject]? = nil) { + public func open(opts:[String: AnyObject]? = nil) { if self.connected { - assert(false, "We're in a bad state, this shouldn't happen.") + fatalError("Engine tried to open while connected") } + self.closed = false let (urlPolling, urlWebSocket) = self.createURLs(opts) self.urlPolling = urlPolling self.urlWebSocket = urlWebSocket @@ -304,7 +318,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { if self == nil { return } else if err != nil || data == nil { - self?.handlePollingFailed(err) + self?.handlePollingFailed(err.localizedDescription) return } @@ -382,7 +396,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { length += chr } else { if length == "" || testLength(length, &n) { - println("failure in parsePollingMessage") + self.handlePollingFailed("Error parsing XHR message") return } @@ -451,10 +465,11 @@ public class SocketEngine: NSObject, WebSocketDelegate { self.upgradeTransport() return } - } - - if message == PacketType.CLOSE.rawValue { - // do nothing + } else if type == PacketType.CLOSE.rawValue { + if self.polling { + self.client.didForceClose("Disconnect") + } + return } // println("Got something idk what to do with") @@ -554,11 +569,7 @@ public class SocketEngine: NSObject, WebSocketDelegate { public func write(msg:String, withType type:PacketType, withData data:ContiguousArray?) { dispatch_async(self.emitQueue) {[weak self] in - if self == nil { - return - } - - if !self!.connected { + if self == nil || !self!.connected { return } diff --git a/SwiftIO/SocketEngineClient.swift b/SwiftIO/SocketEngineClient.swift index 81ac7ee..57c5c1e 100644 --- a/SwiftIO/SocketEngineClient.swift +++ b/SwiftIO/SocketEngineClient.swift @@ -32,9 +32,10 @@ import Foundation var socketURL:String {get} var secure:Bool {get} + func didForceClose(reason:String) func parseSocketMessage(msg:String) func parseBinaryData(data:NSData) - func pollingDidFail(err:NSError) + func pollingDidFail(err:String) func webSocketDidCloseWithCode(code:Int, reason:String, wasClean:Bool) func webSocketDidFailWithError(error:NSError) } \ No newline at end of file diff --git a/SwiftIO/SocketIOClient.swift b/SwiftIO/SocketIOClient.swift index f30a770..70edf9c 100644 --- a/SwiftIO/SocketIOClient.swift +++ b/SwiftIO/SocketIOClient.swift @@ -130,13 +130,15 @@ public class SocketIOClient: NSObject, SocketEngineClient { /** Closes the socket. Only reopen the same socket if you know what you're doing. + Will turn off automatic reconnects. + Pass true to fast if you're closing from a background task */ - public func close() { - self._closed = true + public func close(fast:Bool = false) { + self.reconnects = false self._connecting = false self._connected = false self._reconnecting = false - self.engine?.close() + self.engine?.close(fast: fast) } /** @@ -182,13 +184,17 @@ public class SocketIOClient: NSObject, SocketEngineClient { } /// Server wants us to die - func didForceClose(#message:String) { + public func didForceClose(reason:String) { + if self.closed { + return + } + self._closed = true self._connected = false self.reconnects = false self._connecting = false self._reconnecting = false - self.handleEvent("disconnect", data: [message], isInternalMessage: true) + self.handleEvent("disconnect", data: [reason], isInternalMessage: true) } /** @@ -328,7 +334,6 @@ public class SocketIOClient: NSObject, SocketEngineClient { } } - // Should be removed and moved to SocketEngine func joinNamespace() { if self.nsp != "/" { self.engine?.send("0/\(self.nsp)", withData: nil) @@ -373,10 +378,10 @@ public class SocketIOClient: NSObject, SocketEngineClient { } // Something happened while polling - public func pollingDidFail(err:NSError) { + public func pollingDidFail(err:String) { if !self.reconnecting { self._connected = false - self.handleEvent("reconnect", data: [err.localizedDescription], isInternalMessage: true) + self.handleEvent("reconnect", data: [err], isInternalMessage: true) self.tryReconnect() } } @@ -388,7 +393,7 @@ public class SocketIOClient: NSObject, SocketEngineClient { // We lost connection and should attempt to reestablish func tryReconnect() { if self.reconnectAttempts != -1 && self.currentReconnectAttempt + 1 > self.reconnectAttempts { - self.didForceClose(message: "Reconnect Failed") + self.didForceClose("Reconnect Failed") return } else if self.connected { self._connecting = false @@ -426,7 +431,7 @@ public class SocketIOClient: NSObject, SocketEngineClient { self._connected = false self._connecting = false if self.closed || !self.reconnects { - self.didForceClose(message: "WebSocket closed") + self.didForceClose("WebSocket closed") } else { self.handleEvent("reconnect", data: [reason], isInternalMessage: true) self.tryReconnect() @@ -439,7 +444,7 @@ public class SocketIOClient: NSObject, SocketEngineClient { self._connecting = false self.handleEvent("error", data: [error.localizedDescription], isInternalMessage: true) if self.closed || !self.reconnects { - self.didForceClose(message: "WebSocket closed with an error \(error)") + self.didForceClose("WebSocket closed with an error \(error)") } else if !self.reconnecting { self.handleEvent("reconnect", data: [error.localizedDescription], isInternalMessage: true) self.tryReconnect()