Merge branch 'development'
* development: ack emits should allow custom types Report errors in SocketData to users. Resolves #677 Fixes #676 fix method name in docs
This commit is contained in:
commit
62eeba69e8
@ -221,6 +221,81 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
waitForExpectations(timeout: 0.2)
|
waitForExpectations(timeout: 0.2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testConnectTimesOutIfNotConnected() {
|
||||||
|
let expect = expectation(description: "The client should call the timeout function")
|
||||||
|
|
||||||
|
socket.setTestStatus(.notConnected)
|
||||||
|
|
||||||
|
socket.connect(timeoutAfter: 1, withHandler: {
|
||||||
|
expect.fulfill()
|
||||||
|
})
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testConnectDoesNotTimeOutIfConnected() {
|
||||||
|
let expect = expectation(description: "The client should not call the timeout function")
|
||||||
|
|
||||||
|
socket.setTestStatus(.notConnected)
|
||||||
|
|
||||||
|
socket.connect(timeoutAfter: 1, withHandler: {
|
||||||
|
XCTFail("Should not call timeout handler if status is connected")
|
||||||
|
})
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) {
|
||||||
|
// Fake connecting
|
||||||
|
self.socket.setTestStatus(.connected)
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.1) {
|
||||||
|
expect.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testErrorInCustomSocketDataCallsErrorHandler() {
|
||||||
|
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
|
||||||
|
"custom data")
|
||||||
|
|
||||||
|
socket.on(clientEvent: .error) {data, ack in
|
||||||
|
guard data.count == 3, data[0] as? String == "myEvent",
|
||||||
|
data[2] is ThrowingData.ThrowingError else {
|
||||||
|
XCTFail("Incorrect error call")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expect.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit("myEvent", ThrowingData())
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testErrorInCustomSocketDataCallsErrorHandler_ack() {
|
||||||
|
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
|
||||||
|
"custom data")
|
||||||
|
|
||||||
|
socket.on(clientEvent: .error) {data, ack in
|
||||||
|
guard data.count == 3, data[0] as? String == "myEvent",
|
||||||
|
data[2] is ThrowingData.ThrowingError else {
|
||||||
|
XCTFail("Incorrect error call")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expect.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emitWithAck("myEvent", ThrowingData()).timingOut(after: 1, callback: {_ in
|
||||||
|
XCTFail("Ack callback should not be called")
|
||||||
|
})
|
||||||
|
|
||||||
|
waitForExpectations(timeout: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
let data = "test".data(using: String.Encoding.utf8)!
|
let data = "test".data(using: String.Encoding.utf8)!
|
||||||
let data2 = "test2".data(using: String.Encoding.utf8)!
|
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||||
private var socket: SocketIOClient!
|
private var socket: SocketIOClient!
|
||||||
@ -231,3 +306,14 @@ class SocketSideEffectTest: XCTestCase {
|
|||||||
socket.setTestable()
|
socket.setTestable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ThrowingData : SocketData {
|
||||||
|
enum ThrowingError : Error {
|
||||||
|
case error
|
||||||
|
}
|
||||||
|
|
||||||
|
func socketRepresentation() throws -> SocketData {
|
||||||
|
throw ThrowingError.error
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -48,11 +48,18 @@ public final class SocketAckEmitter : NSObject {
|
|||||||
|
|
||||||
/// Call to ack receiving this event.
|
/// Call to ack receiving this event.
|
||||||
///
|
///
|
||||||
|
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||||
|
/// will be emitted. The structure of the error data is `[ackNum, items, theError]`
|
||||||
|
///
|
||||||
/// - parameter items: A variable number of items to send when acking.
|
/// - parameter items: A variable number of items to send when acking.
|
||||||
public func with(_ items: SocketData...) {
|
public func with(_ items: SocketData...) {
|
||||||
guard ackNum != -1 else { return }
|
guard ackNum != -1 else { return }
|
||||||
|
|
||||||
socket.emitAck(ackNum, with: items)
|
do {
|
||||||
|
socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() }))
|
||||||
|
} catch let err {
|
||||||
|
socket.handleClientEvent(.error, data: [ackNum, items, err])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call to ack receiving this event.
|
/// Call to ack receiving this event.
|
||||||
@ -98,7 +105,7 @@ public final class OnAckCallback : NSObject {
|
|||||||
/// - parameter callback: The callback called when an ack is received, or when a timeout happens.
|
/// - parameter callback: The callback called when an ack is received, or when a timeout happens.
|
||||||
/// To check for timeout, use `SocketAckStatus`'s `noAck` case.
|
/// To check for timeout, use `SocketAckStatus`'s `noAck` case.
|
||||||
public func timingOut(after seconds: Int, callback: @escaping AckCallback) {
|
public func timingOut(after seconds: Int, callback: @escaping AckCallback) {
|
||||||
guard let socket = self.socket else { return }
|
guard let socket = self.socket, ackNumber != -1 else { return }
|
||||||
|
|
||||||
socket.ackHandlers.addAck(ackNumber, callback: callback)
|
socket.ackHandlers.addAck(ackNumber, callback: callback)
|
||||||
socket._emit(items, ack: ackNumber)
|
socket._emit(items, ack: ackNumber)
|
||||||
|
|||||||
@ -184,10 +184,8 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
|
|
||||||
guard timeoutAfter != 0 else { return }
|
guard timeoutAfter != 0 else { return }
|
||||||
|
|
||||||
let time = DispatchTime.now() + Double(UInt64(timeoutAfter) * NSEC_PER_SEC) / Double(NSEC_PER_SEC)
|
handleQueue.asyncAfter(deadline: DispatchTime.now() + Double(timeoutAfter)) {[weak self] in
|
||||||
|
guard let this = self, this.status == .connecting || this.status == .notConnected else { return }
|
||||||
handleQueue.asyncAfter(deadline: time) {[weak self] in
|
|
||||||
guard let this = self, this.status != .connected && this.status != .disconnected else { return }
|
|
||||||
|
|
||||||
this.status = .disconnected
|
this.status = .disconnected
|
||||||
this.engine?.disconnect(reason: "Connect timeout")
|
this.engine?.disconnect(reason: "Connect timeout")
|
||||||
@ -232,13 +230,19 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
|
|
||||||
/// Send an event to the server, with optional data items.
|
/// Send an event to the server, with optional data items.
|
||||||
///
|
///
|
||||||
|
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||||
|
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||||
|
///
|
||||||
/// - parameter event: The event to send.
|
/// - parameter event: The event to send.
|
||||||
/// - parameter items: The items to send with this event. May be left out.
|
/// - parameter items: The items to send with this event. May be left out.
|
||||||
open func emit(_ event: String, _ items: SocketData...) {
|
open func emit(_ event: String, _ items: SocketData...) {
|
||||||
do {
|
do {
|
||||||
emit(event, with: try items.map({ try $0.socketRepresentation() }))
|
emit(event, with: try items.map({ try $0.socketRepresentation() }))
|
||||||
} catch {
|
} catch let err {
|
||||||
fatalError("Error creating socketRepresentation for emit: \(event), \(items)")
|
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||||
|
type: logType)
|
||||||
|
|
||||||
|
handleClientEvent(.error, data: [event, items, err])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +264,9 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||||
/// Check that your server's api will ack the event being sent.
|
/// Check that your server's api will ack the event being sent.
|
||||||
///
|
///
|
||||||
|
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||||
|
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||||
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
///
|
///
|
||||||
/// ```swift
|
/// ```swift
|
||||||
@ -274,8 +281,13 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||||
do {
|
do {
|
||||||
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
|
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
|
||||||
} catch {
|
} catch let err {
|
||||||
fatalError("Error creating socketRepresentation for emit: \(event), \(items)")
|
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||||
|
type: logType)
|
||||||
|
|
||||||
|
handleClientEvent(.error, data: [event, items, err])
|
||||||
|
|
||||||
|
return OnAckCallback(ackNumber: -1, items: [], socket: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +438,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
|
|
||||||
/// Removes handler(s) based on an event name.
|
/// Removes handler(s) based on an event name.
|
||||||
///
|
///
|
||||||
/// If you wish to remove a specific event, call the `off(if:)` with the UUID received from its `on` call.
|
/// If you wish to remove a specific event, call the `off(id:)` with the UUID received from its `on` call.
|
||||||
///
|
///
|
||||||
/// - parameter event: The event to remove handlers for.
|
/// - parameter event: The event to remove handlers for.
|
||||||
open func off(_ event: String) {
|
open func off(_ event: String) {
|
||||||
@ -555,9 +567,9 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func _tryReconnect() {
|
private func _tryReconnect() {
|
||||||
guard reconnecting else { return }
|
guard reconnects && reconnecting && status != .disconnected else { return }
|
||||||
|
|
||||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts {
|
||||||
return didDisconnect(reason: "Reconnect Failed")
|
return didDisconnect(reason: "Reconnect Failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user