refactor client dispatch queues

This commit is contained in:
Erik 2015-10-29 19:10:38 -04:00
parent 9633bea018
commit 0b6cece96b

View File

@ -26,7 +26,7 @@ import Foundation
public final class SocketIOClient: NSObject, SocketEngineClient { public final class SocketIOClient: NSObject, SocketEngineClient {
public let socketURL: String public let socketURL: String
public private(set) var engine: SocketEngineSpec? public private(set) var engine: SocketEngineSpec?
public private(set) var secure = false public private(set) var secure = false
public private(set) var status = SocketIOClientStatus.NotConnected public private(set) var status = SocketIOClientStatus.NotConnected
@ -41,6 +41,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL) private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
private let logType = "SocketIOClient" private let logType = "SocketIOClient"
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)
private var anyHandler: ((SocketAnyEvent) -> Void)? private var anyHandler: ((SocketAnyEvent) -> Void)?
private var currentReconnectAttempt = 0 private var currentReconnectAttempt = 0
@ -52,14 +53,15 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
private(set) var currentAck = -1 private(set) var currentAck = -1
private(set) var handleQueue = dispatch_get_main_queue() private(set) var handleQueue = dispatch_get_main_queue()
private(set) var reconnectAttempts = -1 private(set) var reconnectAttempts = -1
var waitingData = [SocketPacket]() var waitingData = [SocketPacket]()
/** /**
Type safe way to create a new SocketIOClient. opts can be omitted Type safe way to create a new SocketIOClient. opts can be omitted
*/ */
public init(var socketURL: String, options: Set<SocketIOClientOption>? = nil) { public init(var socketURL: String, options: Set<SocketIOClientOption>? = nil) {
self.options = options self.options = options
if socketURL["https://"].matches().count != 0 { if socketURL["https://"].matches().count != 0 {
self.options?.insertIgnore(.Secure(true)) self.options?.insertIgnore(.Secure(true))
} }
@ -98,9 +100,9 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity. Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
If using Swift it's recommended to use `init(var socketURL: String, opts: SocketOptionsDictionary? = nil)` If using Swift it's recommended to use `init(var socketURL: String, opts: SocketOptionsDictionary? = nil)`
*/ */
public convenience init(socketURL: String, options: NSDictionary?) { public convenience init(socketURL: String, options: NSDictionary?) {
self.init(socketURL: socketURL, self.init(socketURL: socketURL,
options: SocketIOClientOption.NSDictionaryToSocketOptionsSet(options ?? [:])) options: SocketIOClientOption.NSDictionaryToSocketOptionsSet(options ?? [:]))
@ -113,9 +115,9 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
private func addEngine() -> SocketEngine { private func addEngine() -> SocketEngine {
Logger.log("Adding engine", type: logType) Logger.log("Adding engine", type: logType)
let newEngine = SocketEngine(client: self, url: socketURL, options: options ?? []) let newEngine = SocketEngine(client: self, url: socketURL, options: options ?? [])
engine = newEngine engine = newEngine
return newEngine return newEngine
} }
@ -126,10 +128,10 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Closes the socket. Only reopen the same socket if you know what you're doing. Closes the socket. Only reopen the same socket if you know what you're doing.
Will turn off automatic reconnects. Will turn off automatic reconnects.
Pass true to fast if you're closing from a background task Pass true to fast if you're closing from a background task
*/ */
public func close() { public func close() {
Logger.log("Closing socket", type: logType) Logger.log("Closing socket", type: logType)
@ -138,23 +140,23 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Connect to the server. Connect to the server.
*/ */
public func connect() { public func connect() {
connect(timeoutAfter: 0, withTimeoutHandler: nil) connect(timeoutAfter: 0, withTimeoutHandler: nil)
} }
/** /**
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, public func connect(timeoutAfter timeoutAfter: Int,
withTimeoutHandler handler: (() -> Void)?) { withTimeoutHandler handler: (() -> Void)?) {
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)") assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
guard status != .Connected else { guard status != .Connected else {
return return
} }
if status == .Closed { if status == .Closed {
Logger.log("Warning! This socket was previously closed. This might be dangerous!", Logger.log("Warning! This socket was previously closed. This might be dangerous!",
type: logType) type: logType)
@ -168,7 +170,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
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
if let this = self where this.status != .Connected { if let this = self where this.status != .Connected {
this.status = .Closed this.status = .Closed
@ -234,43 +236,43 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Same as close Same as close
*/ */
public func disconnect() { public func disconnect() {
close() close()
} }
/** /**
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...) {
emit(event, withItems: items) emit(event, withItems: 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]) {
guard status == .Connected else { guard status == .Connected else {
return return
} }
dispatch_async(emitQueue) { dispatch_async(emitQueue) {
self._emit([event] + items) self._emit([event] + items)
} }
} }
/** /**
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)
} }
@ -334,8 +336,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
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, public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool,
wantsAck ack: Int? = nil) { wantsAck ack: Int? = nil) {
guard status == .Connected || isInternalMessage else { guard status == .Connected || isInternalMessage else {
@ -344,28 +346,25 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "") Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
if anyHandler != nil { dispatch_async(handleQueue) {
dispatch_async(handleQueue) { if self.anyHandler != nil {
self.anyHandler?(SocketAnyEvent(event: event, items: data)) self.anyHandler?(SocketAnyEvent(event: event, items: data))
} }
for handler in self.handlers where handler.event == event {
if let ack = ack {
handler.executeCallback(data, withAck: ack, withSocket: self)
} else {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
}
} }
for handler in handlers where handler.event == event {
if let ack = ack {
dispatch_async(handleQueue) {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
} else {
dispatch_async(handleQueue) {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
}
}
} }
/** /**
Leaves nsp and goes back to / Leaves nsp and goes back to /
*/ */
public func leaveNamespace() { public func leaveNamespace() {
if nsp != "/" { if nsp != "/" {
engine?.send("1\(nsp)", withData: nil) engine?.send("1\(nsp)", withData: nil)
@ -374,8 +373,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Joins nsp if it is not / Joins nsp if it is not /
*/ */
public func joinNamespace() { public func joinNamespace() {
Logger.log("Joining namespace", type: logType) Logger.log("Joining namespace", type: logType)
@ -385,16 +384,16 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Joins namespace / Joins namespace /
*/ */
public func joinNamespace(namespace: String) { public func joinNamespace(namespace: String) {
self.nsp = namespace self.nsp = namespace
joinNamespace() joinNamespace()
} }
/** /**
Removes handler(s) Removes handler(s)
*/ */
public func off(event: String) { public func off(event: String) {
Logger.log("Removing handler for event: %@", type: logType, args: event) Logger.log("Removing handler for event: %@", type: logType, args: event)
@ -402,8 +401,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Adds a handler for an event. Adds a handler for an event.
*/ */
public func on(event: String, callback: NormalCallback) { public func on(event: String, callback: NormalCallback) {
Logger.log("Adding handler for event: %@", type: logType, args: event) Logger.log("Adding handler for event: %@", type: logType, args: event)
@ -412,8 +411,8 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
/** /**
Adds a single-use handler for an event. Adds a single-use handler for an event.
*/ */
public func once(event: String, callback: NormalCallback) { public func once(event: String, callback: NormalCallback) {
Logger.log("Adding once handler for event: %@", type: logType, args: event) Logger.log("Adding once handler for event: %@", type: logType, args: event)
@ -424,47 +423,47 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
this.handlers = ContiguousArray(this.handlers.filter {$0.id != id}) this.handlers = ContiguousArray(this.handlers.filter {$0.id != id})
callback(data, ack) callback(data, ack)
} }
handlers.append(handler) handlers.append(handler)
} }
/** /**
Removes all handlers. Removes all handlers.
Can be used after disconnecting to break any potential remaining retain cycles. Can be used after disconnecting to break any potential remaining retain cycles.
*/ */
public func removeAllHandlers() { public func removeAllHandlers() {
handlers.removeAll(keepCapacity: false) handlers.removeAll(keepCapacity: false)
} }
/** /**
Adds a handler that will be called on every event. Adds a handler that will be called on every event.
*/ */
public func onAny(handler: (SocketAnyEvent) -> Void) { public func onAny(handler: (SocketAnyEvent) -> Void) {
anyHandler = handler anyHandler = handler
} }
/** /**
Same as connect Same as connect
*/ */
public func open() { public func open() {
connect() connect()
} }
public func parseSocketMessage(msg: String) { public func parseSocketMessage(msg: String) {
dispatch_async(handleQueue) { dispatch_async(parseQueue) {
SocketParser.parseSocketMessage(msg, socket: self) SocketParser.parseSocketMessage(msg, socket: self)
} }
} }
public func parseBinaryData(data: NSData) { public func parseBinaryData(data: NSData) {
dispatch_async(handleQueue) { dispatch_async(parseQueue) {
SocketParser.parseBinaryData(data, socket: self) SocketParser.parseBinaryData(data, socket: self)
} }
} }
/** /**
Tries to reconnect to the server. Tries to reconnect to the server.
*/ */
public func reconnect() { public func reconnect() {
tryReconnect() tryReconnect()
} }
@ -481,7 +480,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient {
} }
} }
} }
@objc private func _tryReconnect() { @objc private func _tryReconnect() {
if status == .Connected { if status == .Connected {
clearReconnectTimer() clearReconnectTimer()