refactor engine, don't re-add engine on reconnect, other improvements
This commit is contained in:
parent
87e12fd284
commit
57b252fa7d
@ -33,6 +33,8 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
public private(set) var ws: WebSocket?
|
public private(set) var ws: WebSocket?
|
||||||
|
|
||||||
public weak var client: SocketEngineClient?
|
public weak var client: SocketEngineClient?
|
||||||
|
|
||||||
|
private weak var sessionDelegate: NSURLSessionDelegate?
|
||||||
|
|
||||||
private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
|
private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
|
||||||
private typealias ProbeWaitQueue = [Probe]
|
private typealias ProbeWaitQueue = [Probe]
|
||||||
@ -45,6 +47,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
private let url: String
|
private let url: String
|
||||||
private let workQueue = NSOperationQueue()
|
private let workQueue = NSOperationQueue()
|
||||||
|
|
||||||
|
private var connectParams: [String: AnyObject]?
|
||||||
private var closed = false
|
private var closed = false
|
||||||
private var extraHeaders: [String: String]?
|
private var extraHeaders: [String: String]?
|
||||||
private var fastUpgrade = false
|
private var fastUpgrade = false
|
||||||
@ -64,12 +67,11 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
private var probing = false
|
private var probing = false
|
||||||
private var probeWait = ProbeWaitQueue()
|
private var probeWait = ProbeWaitQueue()
|
||||||
private var secure = false
|
private var secure = false
|
||||||
private var session: NSURLSession!
|
private var session: NSURLSession?
|
||||||
private var voipEnabled = false
|
private var voipEnabled = false
|
||||||
private var waitingForPoll = false
|
private var waitingForPoll = false
|
||||||
private var waitingForPost = false
|
private var waitingForPost = false
|
||||||
private var websocketConnected = false
|
private var websocketConnected = false
|
||||||
|
|
||||||
private(set) var connected = false
|
private(set) var connected = false
|
||||||
private(set) var polling = true
|
private(set) var polling = true
|
||||||
private(set) var websocket = false
|
private(set) var websocket = false
|
||||||
@ -81,9 +83,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
for option in options {
|
for option in options {
|
||||||
switch option {
|
switch option {
|
||||||
case .SessionDelegate(let delegate):
|
case .SessionDelegate(let delegate):
|
||||||
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
sessionDelegate = delegate
|
||||||
delegate: delegate,
|
|
||||||
delegateQueue: workQueue)
|
|
||||||
case .ForcePolling(let force):
|
case .ForcePolling(let force):
|
||||||
forcePolling = force
|
forcePolling = force
|
||||||
case .ForceWebsockets(let force):
|
case .ForceWebsockets(let force):
|
||||||
@ -102,12 +102,6 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if session == nil {
|
|
||||||
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
|
||||||
delegate: nil,
|
|
||||||
delegateQueue: workQueue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(client: SocketEngineClient, url: String, options: NSDictionary?) {
|
public convenience init(client: SocketEngineClient, url: String, options: NSDictionary?) {
|
||||||
@ -120,6 +114,35 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
closed = true
|
closed = true
|
||||||
stopPolling()
|
stopPolling()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func checkAndHandleEngineError(msg: String) {
|
||||||
|
guard let stringData = msg.dataUsingEncoding(NSUTF8StringEncoding,
|
||||||
|
allowLossyConversion: false) else { return }
|
||||||
|
|
||||||
|
do {
|
||||||
|
if let dict = try NSJSONSerialization.JSONObjectWithData(stringData,
|
||||||
|
options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
|
||||||
|
guard let code = dict["code"] as? Int else { return }
|
||||||
|
guard let error = dict["message"] as? String else { return }
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case 0: // Unknown transport
|
||||||
|
logAndError(error)
|
||||||
|
case 1: // Unknown sid. clear and retry connect
|
||||||
|
sid = ""
|
||||||
|
open(connectParams)
|
||||||
|
case 2: // Bad handshake request
|
||||||
|
logAndError(error)
|
||||||
|
case 3: // Bad request
|
||||||
|
logAndError(error)
|
||||||
|
default:
|
||||||
|
logAndError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
DefaultSocketLogger.Logger.error("Got message: %@", type: logType, args: msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func checkIfMessageIsBase64Binary(var message: String) -> Bool {
|
private func checkIfMessageIsBase64Binary(var message: String) -> Bool {
|
||||||
if message.hasPrefix("b4") {
|
if message.hasPrefix("b4") {
|
||||||
@ -143,6 +166,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
|
|
||||||
pingTimer?.invalidate()
|
pingTimer?.invalidate()
|
||||||
closed = true
|
closed = true
|
||||||
|
connected = false
|
||||||
|
|
||||||
if websocket {
|
if websocket {
|
||||||
sendWebSocketMessage("", withType: .Close)
|
sendWebSocketMessage("", withType: .Close)
|
||||||
@ -341,11 +365,18 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
client?.engineDidClose(reason)
|
client?.engineDidClose(reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func logAndError(error: String) {
|
||||||
|
DefaultSocketLogger.Logger.error(error, type: logType)
|
||||||
|
client?.didError(error)
|
||||||
|
}
|
||||||
|
|
||||||
public func open(opts: [String: AnyObject]? = nil) {
|
public func open(opts: [String: AnyObject]? = nil) {
|
||||||
|
connectParams = opts
|
||||||
|
|
||||||
if connected {
|
if connected {
|
||||||
DefaultSocketLogger.Logger.error("Tried to open while connected", type: logType)
|
DefaultSocketLogger.Logger.error("Tried to open while connected", type: logType)
|
||||||
client?.didError("Tried to open while connected")
|
client?.didError("Tried to open engine while connected")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -353,7 +384,7 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
||||||
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
||||||
|
|
||||||
closed = false
|
resetEngine()
|
||||||
|
|
||||||
(urlPolling, urlWebSocket) = createURLs(opts)
|
(urlPolling, urlWebSocket) = createURLs(opts)
|
||||||
|
|
||||||
@ -388,19 +419,15 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
private func parseEngineMessage(var message: String, fromPolling: Bool) {
|
private func parseEngineMessage(var message: String, fromPolling: Bool) {
|
||||||
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
|
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
|
||||||
|
|
||||||
func handleOther(msg: String) -> SocketEnginePacketType {
|
|
||||||
if checkIfMessageIsBase64Binary(msg) {
|
|
||||||
return .Noop
|
|
||||||
} else {
|
|
||||||
DefaultSocketLogger.Logger.error("Got message: %@", type: logType, args: msg)
|
|
||||||
return .Close
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let reader = SocketStringReader(message: message)
|
let reader = SocketStringReader(message: message)
|
||||||
|
|
||||||
let type = SocketEnginePacketType(rawValue: Int(reader.currentCharacter) ?? -1)
|
guard let type = SocketEnginePacketType(rawValue: Int(reader.currentCharacter) ?? -1) else {
|
||||||
?? handleOther(message)
|
if !checkIfMessageIsBase64Binary(message) {
|
||||||
|
checkAndHandleEngineError(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if fromPolling && type != .Noop {
|
if fromPolling && type != .Noop {
|
||||||
fixDoubleUTF8(&message)
|
fixDoubleUTF8(&message)
|
||||||
@ -429,7 +456,25 @@ public final class SocketEngine: NSObject, SocketEngineSpec, WebSocketDelegate {
|
|||||||
sendWebSocketMessage("probe", withType: .Ping)
|
sendWebSocketMessage("probe", withType: .Ping)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private func resetEngine() {
|
||||||
|
closed = false
|
||||||
|
connected = false
|
||||||
|
fastUpgrade = false
|
||||||
|
polling = true
|
||||||
|
probing = false
|
||||||
|
invalidated = false
|
||||||
|
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
||||||
|
delegate: sessionDelegate,
|
||||||
|
delegateQueue: workQueue)
|
||||||
|
sid = ""
|
||||||
|
waitingForPoll = false
|
||||||
|
waitingForPost = false
|
||||||
|
websocket = false
|
||||||
|
websocketConnected = false
|
||||||
|
}
|
||||||
|
|
||||||
/// Send an engine message (4)
|
/// Send an engine message (4)
|
||||||
public func send(msg: String, withData datas: [NSData]) {
|
public func send(msg: String, withData datas: [NSData]) {
|
||||||
if probing {
|
if probing {
|
||||||
@ -525,13 +570,14 @@ extension SocketEngine {
|
|||||||
private func doRequest(req: NSMutableURLRequest,
|
private func doRequest(req: NSMutableURLRequest,
|
||||||
withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
||||||
if !polling || closed || invalidated {
|
if !polling || closed || invalidated {
|
||||||
|
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: logType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSocketLogger.Logger.log("Doing polling request", type: logType)
|
DefaultSocketLogger.Logger.log("Doing polling request", type: logType)
|
||||||
|
|
||||||
req.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
|
req.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
|
||||||
session.dataTaskWithRequest(req, completionHandler: callback).resume()
|
session?.dataTaskWithRequest(req, completionHandler: callback).resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func doLongPoll(req: NSMutableURLRequest) {
|
private func doLongPoll(req: NSMutableURLRequest) {
|
||||||
@ -684,7 +730,7 @@ extension SocketEngine {
|
|||||||
|
|
||||||
private func stopPolling() {
|
private func stopPolling() {
|
||||||
invalidated = true
|
invalidated = true
|
||||||
session.finishTasksAndInvalidate()
|
session?.finishTasksAndInvalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
|
|||||||
public private(set) var engine: SocketEngineSpec?
|
public private(set) var engine: SocketEngineSpec?
|
||||||
public private(set) var status = SocketIOClientStatus.NotConnected
|
public private(set) var status = SocketIOClientStatus.NotConnected
|
||||||
|
|
||||||
|
public var forceNew = false
|
||||||
public var nsp = "/"
|
public var nsp = "/"
|
||||||
public var options: Set<SocketIOClientOption>
|
public var options: Set<SocketIOClientOption>
|
||||||
public var reconnects = true
|
public var reconnects = true
|
||||||
@ -88,6 +89,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
|
|||||||
DefaultSocketLogger.Logger = logger
|
DefaultSocketLogger.Logger = logger
|
||||||
case .HandleQueue(let queue):
|
case .HandleQueue(let queue):
|
||||||
handleQueue = queue
|
handleQueue = queue
|
||||||
|
case .ForceNew(let force):
|
||||||
|
forceNew = force
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -109,7 +112,6 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
DefaultSocketLogger.Logger.log("Client is being deinit", type: logType)
|
DefaultSocketLogger.Logger.log("Client is being deinit", type: logType)
|
||||||
DefaultSocketLogger.Logger.log = false
|
|
||||||
engine?.close()
|
engine?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,21 +156,21 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
|
|||||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||||
|
|
||||||
guard status != .Connected else {
|
guard status != .Connected else {
|
||||||
return
|
DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket",
|
||||||
}
|
|
||||||
|
|
||||||
if status == .Closed {
|
|
||||||
DefaultSocketLogger.Logger.log("Warning! This socket was previously closed. This might be dangerous!",
|
|
||||||
type: logType)
|
type: logType)
|
||||||
}
|
|
||||||
|
|
||||||
status = SocketIOClientStatus.Connecting
|
|
||||||
addEngine().open(connectParams)
|
|
||||||
|
|
||||||
guard timeoutAfter != 0 else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = .Connecting
|
||||||
|
|
||||||
|
if engine == nil || forceNew {
|
||||||
|
addEngine().open(connectParams)
|
||||||
|
} else {
|
||||||
|
engine?.open(connectParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard timeoutAfter != 0 else { 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, handleQueue) {[weak self] in
|
dispatch_after(time, handleQueue) {[weak self] in
|
||||||
|
|||||||
@ -32,6 +32,7 @@ public enum SocketIOClientOption: ClientOption {
|
|||||||
case ConnectParams([String: AnyObject])
|
case ConnectParams([String: AnyObject])
|
||||||
case Cookies([NSHTTPCookie])
|
case Cookies([NSHTTPCookie])
|
||||||
case ExtraHeaders([String: String])
|
case ExtraHeaders([String: String])
|
||||||
|
case ForceNew(Bool)
|
||||||
case ForcePolling(Bool)
|
case ForcePolling(Bool)
|
||||||
case ForceWebsockets(Bool)
|
case ForceWebsockets(Bool)
|
||||||
case HandleQueue(dispatch_queue_t)
|
case HandleQueue(dispatch_queue_t)
|
||||||
@ -68,6 +69,8 @@ public enum SocketIOClientOption: ClientOption {
|
|||||||
return .ReconnectAttempts(value as! Int)
|
return .ReconnectAttempts(value as! Int)
|
||||||
case "reconnectWait" where value is Int:
|
case "reconnectWait" where value is Int:
|
||||||
return .ReconnectWait(value as! Int)
|
return .ReconnectWait(value as! Int)
|
||||||
|
case "forceNew" where value is Bool:
|
||||||
|
return .ForceNew(value as! Bool)
|
||||||
case "forcePolling" where value is Bool:
|
case "forcePolling" where value is Bool:
|
||||||
return .ForcePolling(value as! Bool)
|
return .ForcePolling(value as! Bool)
|
||||||
case "forceWebsockets" where value is Bool:
|
case "forceWebsockets" where value is Bool:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user