Merge branch 'development'
* development: update changelog Remove MARK: for websockets methods Use callbacks instead of delegate methods for Starscream Fix exclusive access issue Execute acks sync. Implement #950 Fixes build warnings caused by documentation issues. update starscream carthage
This commit is contained in:
commit
31aed9e793
@ -1 +1 @@
|
||||
4.0.2
|
||||
system
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
# 13.1.1
|
||||
# v13.1.2
|
||||
|
||||
- Fix [#950](https://github.com/socketio/socket.io-client-swift/issues/950)
|
||||
- Conforming to `SocketEngineWebsocket` no longer requires conforming to `WebsocketDelegate`
|
||||
|
||||
|
||||
# v13.1.1
|
||||
|
||||
- Fix [#923](https://github.com/socketio/socket.io-client-swift/issues/923)
|
||||
- Fix [#894](https://github.com/socketio/socket.io-client-swift/issues/894)
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
github "daltoniam/Starscream" "3.0.3"
|
||||
github "daltoniam/common-crypto-spm" "1.1.0"
|
||||
github "daltoniam/zlib-spm" "1.1.0"
|
||||
github "daltoniam/Starscream" "3.0.2"
|
||||
|
||||
@ -108,7 +108,7 @@ public final class OnAckCallback : NSObject {
|
||||
|
||||
/// Completes an emitWithAck. If this isn't called, the emit never happens.
|
||||
///
|
||||
/// - parameter after: The number of seconds before this emit times out if an ack hasn't been received.
|
||||
/// - parameter seconds: The number of seconds before this emit times out if an ack hasn't been received.
|
||||
/// - parameter callback: The callback called when an ack is received, or when a timeout happens.
|
||||
/// To check for timeout, use `SocketAckStatus`'s `noAck` case.
|
||||
@objc
|
||||
@ -121,9 +121,9 @@ public final class OnAckCallback : NSObject {
|
||||
guard seconds != 0 else { return }
|
||||
|
||||
socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in
|
||||
guard let socket = socket, let manager = socket.manager else { return }
|
||||
guard let socket = socket else { return }
|
||||
|
||||
socket.ackHandlers.timeoutAck(self.ackNumber, onQueue: manager.handleQueue)
|
||||
socket.ackHandlers.timeoutAck(self.ackNumber)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -58,31 +58,20 @@ private struct SocketAck : Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
struct SocketAckManager {
|
||||
class SocketAckManager {
|
||||
private var acks = Set<SocketAck>(minimumCapacity: 1)
|
||||
private let ackSemaphore = DispatchSemaphore(value: 1)
|
||||
|
||||
mutating func addAck(_ ack: Int, callback: @escaping AckCallback) {
|
||||
func addAck(_ ack: Int, callback: @escaping AckCallback) {
|
||||
acks.insert(SocketAck(ack: ack, callback: callback))
|
||||
}
|
||||
|
||||
/// Should be called on handle queue
|
||||
mutating func executeAck(_ ack: Int, with items: [Any], onQueue: DispatchQueue) {
|
||||
ackSemaphore.wait()
|
||||
defer { ackSemaphore.signal() }
|
||||
let ack = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
onQueue.async() { ack?.callback(items) }
|
||||
func executeAck(_ ack: Int, with items: [Any]) {
|
||||
acks.remove(SocketAck(ack: ack))?.callback(items)
|
||||
}
|
||||
|
||||
/// Should be called on handle queue
|
||||
mutating func timeoutAck(_ ack: Int, onQueue: DispatchQueue) {
|
||||
ackSemaphore.wait()
|
||||
defer { ackSemaphore.signal() }
|
||||
let ack = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
onQueue.async() {
|
||||
ack?.callback?([SocketAckStatus.noAck.rawValue])
|
||||
}
|
||||
func timeoutAck(_ ack: Int) {
|
||||
acks.remove(SocketAck(ack: ack))?.callback?([SocketAckStatus.noAck.rawValue])
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
}
|
||||
}
|
||||
|
||||
var ackHandlers = SocketAckManager()
|
||||
let ackHandlers = SocketAckManager()
|
||||
|
||||
private(set) var currentAck = -1
|
||||
|
||||
@ -86,7 +86,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// Type safe way to create a new SocketIOClient. `opts` can be omitted.
|
||||
///
|
||||
/// - parameter manager: The manager for this socket.
|
||||
/// - parameter socketURL: The url of the socket.io server.
|
||||
/// - parameter nsp: The namespace of the socket.
|
||||
@objc
|
||||
public init(manager: SocketManagerSpec, nsp: String) {
|
||||
self.manager = manager
|
||||
@ -115,7 +115,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
///
|
||||
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||
/// has failed. Pass 0 to never timeout.
|
||||
/// - parameter withHandler: The handler to call when the client fails to connect.
|
||||
/// - parameter handler: The handler to call when the client fails to connect.
|
||||
@objc
|
||||
open func connect(timeoutAfter: Double, withHandler handler: (() -> ())?) {
|
||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||
@ -213,7 +213,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// Same as emit, but meant for Objective-C
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter with: The items to send with this event. Send an empty array to send no data.
|
||||
/// - parameter items: The items to send with this event. Send an empty array to send no data.
|
||||
@objc
|
||||
open func emit(_ event: String, with items: [Any]) {
|
||||
guard status == .connected else {
|
||||
@ -270,7 +270,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter with: The items to send with this event. Use `[]` to send nothing.
|
||||
/// - parameter items: The items to send with this event. Use `[]` to send nothing.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
@objc
|
||||
open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback {
|
||||
@ -314,11 +314,11 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter data: The data sent back with this ack.
|
||||
@objc
|
||||
open func handleAck(_ ack: Int, data: [Any]) {
|
||||
guard status == .connected, let manager = self.manager else { return }
|
||||
guard status == .connected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Handling ack: \(ack) with data: \(data)", type: logType)
|
||||
|
||||
ackHandlers.executeAck(ack, with: data, onQueue: manager.handleQueue)
|
||||
ackHandlers.executeAck(ack, with: data)
|
||||
}
|
||||
|
||||
/// Called on socket.io specific events.
|
||||
@ -334,7 +334,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
/// - parameter event: The name of the event.
|
||||
/// - parameter data: The data that was sent with this event.
|
||||
/// - parameter isInternalMessage: Whether this event was sent internally. If `true` it is always sent to handlers.
|
||||
/// - parameter withAck: If > 0 then this event expects to get an ack back from the client.
|
||||
/// - parameter ack: If > 0 then this event expects to get an ack back from the client.
|
||||
@objc
|
||||
open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
|
||||
guard status == .connected || isInternalMessage else { return }
|
||||
|
||||
@ -59,7 +59,7 @@ public protocol SocketIOClientSpec : class {
|
||||
///
|
||||
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||
/// has failed. Pass 0 to never timeout.
|
||||
/// - parameter withHandler: The handler to call when the client fails to connect.
|
||||
/// - parameter handler: The handler to call when the client fails to connect.
|
||||
func connect(timeoutAfter: Double, withHandler handler: (() -> ())?)
|
||||
|
||||
/// Called when the client connects to a namespace. If the client was created with a namespace upfront,
|
||||
@ -134,7 +134,7 @@ public protocol SocketIOClientSpec : class {
|
||||
/// - parameter event: The name of the event.
|
||||
/// - parameter data: The data that was sent with this event.
|
||||
/// - parameter isInternalMessage: Whether this event was sent internally. If `true` it is always sent to handlers.
|
||||
/// - parameter withAck: If > 0 then this event expects to get an ack back from the client.
|
||||
/// - parameter ack: If > 0 then this event expects to get an ack back from the client.
|
||||
func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int)
|
||||
|
||||
/// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
|
||||
|
||||
@ -280,7 +280,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
}
|
||||
|
||||
private func createWebSocketAndConnect() {
|
||||
ws?.delegate = nil // TODO this seems a bit defensive, is this really needed?
|
||||
var req = URLRequest(url: urlWebSocketWithSid)
|
||||
|
||||
addHeaders(to: &req)
|
||||
@ -288,10 +287,33 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
ws = WebSocket(request: req)
|
||||
ws?.callbackQueue = engineQueue
|
||||
ws?.enableCompression = compress
|
||||
ws?.delegate = self
|
||||
ws?.disableSSLCertValidation = selfSigned
|
||||
ws?.security = security?.security
|
||||
|
||||
ws?.onConnect = {[weak self] in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.websocketDidConnect()
|
||||
}
|
||||
|
||||
ws?.onDisconnect = {[weak self] error in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.websocketDidDisconnect(error: error)
|
||||
}
|
||||
|
||||
ws?.onData = {[weak self] data in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.parseEngineData(data)
|
||||
}
|
||||
|
||||
ws?.onText = {[weak self] message in
|
||||
guard let this = self else { return }
|
||||
|
||||
this.parseEngineMessage(message)
|
||||
}
|
||||
|
||||
ws?.connect()
|
||||
}
|
||||
|
||||
@ -461,8 +483,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
/// Parses a raw engine.io packet.
|
||||
///
|
||||
/// - parameter message: The message to parse.
|
||||
/// - parameter fromPolling: Whether this message is from long-polling.
|
||||
/// If `true` we might have to fix utf8 encoding.
|
||||
public func parseEngineMessage(_ message: String) {
|
||||
DefaultSocketLogger.Logger.log("Got message: \(message)", type: SocketEngine.logType)
|
||||
|
||||
@ -586,8 +606,8 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
/// Writes a message to engine.io, independent of transport.
|
||||
///
|
||||
/// - parameter msg: The message to send.
|
||||
/// - parameter withType: The type of this message.
|
||||
/// - parameter withData: Any data that this message has.
|
||||
/// - parameter type: The type of this message.
|
||||
/// - parameter data: Any data that this message has.
|
||||
public func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data]) {
|
||||
engineQueue.async {
|
||||
guard self.connected else { return }
|
||||
@ -609,10 +629,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Starscream delegate conformance
|
||||
// WebSocket Methods
|
||||
|
||||
/// Delegate method for connection.
|
||||
public func websocketDidConnect(socket: WebSocketClient) {
|
||||
private func websocketDidConnect() {
|
||||
if !forceWebsockets {
|
||||
probing = true
|
||||
probeWebSocket()
|
||||
@ -623,8 +642,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
||||
}
|
||||
}
|
||||
|
||||
/// Delegate method for disconnection.
|
||||
public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
|
||||
private func websocketDidDisconnect(error: Error?) {
|
||||
probing = false
|
||||
|
||||
if closed {
|
||||
|
||||
@ -130,15 +130,13 @@ import Starscream
|
||||
/// Parses a raw engine.io packet.
|
||||
///
|
||||
/// - parameter message: The message to parse.
|
||||
/// - parameter fromPolling: Whether this message is from long-polling.
|
||||
/// If `true` we might have to fix utf8 encoding.
|
||||
func parseEngineMessage(_ message: String)
|
||||
|
||||
/// Writes a message to engine.io, independent of transport.
|
||||
///
|
||||
/// - parameter msg: The message to send.
|
||||
/// - parameter withType: The type of this message.
|
||||
/// - parameter withData: Any data that this message has.
|
||||
/// - parameter type: The type of this message.
|
||||
/// - parameter data: Any data that this message has.
|
||||
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data])
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ import Foundation
|
||||
import Starscream
|
||||
|
||||
/// Protocol that is used to implement socket.io WebSocket support
|
||||
public protocol SocketEngineWebsocket : SocketEngineSpec, WebSocketDelegate {
|
||||
public protocol SocketEngineWebsocket : SocketEngineSpec {
|
||||
// MARK: Methods
|
||||
|
||||
/// Sends an engine.io message through the WebSocket transport.
|
||||
@ -66,16 +66,4 @@ extension SocketEngineWebsocket {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Starscream delegate methods
|
||||
|
||||
/// Delegate method for when a message is received.
|
||||
public func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
|
||||
parseEngineMessage(text)
|
||||
}
|
||||
|
||||
/// Delegate method for when binary is received.
|
||||
public func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
|
||||
parseEngineData(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +241,7 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
/// This will remove the socket for the manager's control, and make the socket instance useless and ready for
|
||||
/// releasing.
|
||||
///
|
||||
/// - parameter forNamespace: The namespace to disconnect from.
|
||||
/// - parameter nsp: The namespace to disconnect from.
|
||||
open func disconnectSocket(forNamespace nsp: String) {
|
||||
guard let socket = nsps.removeValue(forKey: nsp) else {
|
||||
DefaultSocketLogger.Logger.log("Could not find socket for \(nsp) to disconnect",
|
||||
@ -282,7 +282,7 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
/// Same as `emitAll(_:_:)`, but meant for Objective-C.
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter withItems: The data to send with this event.
|
||||
/// - parameter items: The data to send with this event.
|
||||
open func emitAll(_ event: String, withItems items: [Any]) {
|
||||
forAll {socket in
|
||||
socket.emit(event, with: items)
|
||||
@ -508,7 +508,7 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
/// Call one of the `disconnectSocket` methods on this class to remove the socket from manager control.
|
||||
/// Or call `SocketIOClient.disconnect()` on the client.
|
||||
///
|
||||
/// - parameter forNamespace: The namespace for the socket.
|
||||
/// - parameter nsp: The namespace for the socket.
|
||||
/// - returns: A `SocketIOClient` for the given namespace.
|
||||
open func socket(forNamespace nsp: String) -> SocketIOClient {
|
||||
assert(nsp.hasPrefix("/"), "forNamespace must have a leading /")
|
||||
|
||||
@ -103,13 +103,13 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
|
||||
|
||||
/// Disconnects the socket associated with `forNamespace`.
|
||||
///
|
||||
/// - parameter forNamespace: The namespace to disconnect from.
|
||||
/// - parameter nsp: The namespace to disconnect from.
|
||||
func disconnectSocket(forNamespace nsp: String)
|
||||
|
||||
/// Sends an event to the server on all namespaces in this manager.
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter withItems: The data to send with this event.
|
||||
/// - parameter items: The data to send with this event.
|
||||
func emitAll(_ event: String, withItems items: [Any])
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
@ -133,7 +133,7 @@ public protocol SocketManagerSpec : class, SocketEngineClient {
|
||||
/// Call one of the `disconnectSocket` methods on the implementing class to remove the socket from manager control.
|
||||
/// Or call `SocketIOClient.disconnect()` on the client.
|
||||
///
|
||||
/// - parameter forNamespace: The namespace for the socket.
|
||||
/// - parameter nsp: The namespace for the socket.
|
||||
/// - returns: A `SocketIOClient` for the given namespace.
|
||||
func socket(forNamespace nsp: String) -> SocketIOClient
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ class SocketAckManagerTest : XCTestCase {
|
||||
}
|
||||
|
||||
ackManager.addAck(1, callback: callback)
|
||||
ackManager.executeAck(1, with: itemsArray, onQueue: DispatchQueue.main)
|
||||
ackManager.executeAck(1, with: itemsArray)
|
||||
|
||||
waitForExpectations(timeout: 3.0, handler: nil)
|
||||
}
|
||||
@ -44,7 +44,7 @@ class SocketAckManagerTest : XCTestCase {
|
||||
}
|
||||
|
||||
ackManager.addAck(1, callback: callback)
|
||||
ackManager.timeoutAck(1, onQueue: DispatchQueue.main)
|
||||
ackManager.timeoutAck(1)
|
||||
|
||||
waitForExpectations(timeout: 0.2, handler: nil)
|
||||
}
|
||||
|
||||
@ -38,6 +38,19 @@ class SocketSideEffectTest: XCTestCase {
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleAckWithAckEmit() {
|
||||
let expect = expectation(description: "handled ack")
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
|
||||
self.socket.emitWithAck("test").timingOut(after: 0) {data in}
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("30[\"hello world\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleAck2() {
|
||||
let expect = expectation(description: "handled ack2")
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user