From c03fc96f04972856c430be9d5f8fc16b376c6875 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Sat, 14 Oct 2017 10:15:36 -0400 Subject: [PATCH] Add ability to track ping/pongs --- Source/SocketIO/Client/SocketIOClient.swift | 22 ++++++ .../SocketIO/Client/SocketIOClientSpec.swift | 72 +++++++++++++++++-- Source/SocketIO/Engine/SocketEngine.swift | 4 ++ .../SocketIO/Engine/SocketEngineClient.swift | 6 ++ Tests/TestSocketIO/SocketSideEffectTest.swift | 24 +++++++ 5 files changed, 123 insertions(+), 5 deletions(-) diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index 5928e76..73fc10b 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -455,6 +455,28 @@ open class SocketIOClient : NSObject, SocketIOClientSpec, SocketEngineClient, So joinNamespace(nsp) } + /// Called when the engine receives a pong message. + open func engineDidReceivePong() { + handleQueue.async { + self._engineDidReceivePong() + } + } + + private func _engineDidReceivePong() { + handleClientEvent(.gotPong, data: []) + } + + /// Called when the sends a ping to the server. + open func engineDidSendPing() { + handleQueue.async { + self._engineDidSendPing() + } + } + + private func _engineDidSendPing() { + handleClientEvent(.sentPing, data: []) + } + /// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called. /// /// - parameter ack: The number for this ack. diff --git a/Source/SocketIO/Client/SocketIOClientSpec.swift b/Source/SocketIO/Client/SocketIOClientSpec.swift index 0616a6e..de52421 100644 --- a/Source/SocketIO/Client/SocketIOClientSpec.swift +++ b/Source/SocketIO/Client/SocketIOClientSpec.swift @@ -245,18 +245,80 @@ public enum SocketClientEvent : String { /// ``` case connect - /// Called when the socket has disconnected and will not attempt to try to reconnect. + /// Emitted when the socket has disconnected and will not attempt to try to reconnect. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .disconnect) {data, ack in + /// // Some cleanup logic + /// } + /// ``` case disconnect - /// Called when an error occurs. + /// Emitted when an error occurs. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .error) {data, ack in + /// // Some logging + /// } + /// ``` case error - /// Called when the client begins the reconnection process. + /// Emitted whenever the engine gets a pong. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .gotPong) {_, _ in + /// // Maybe keep track of latency? + /// } + /// ``` + case gotPong + + /// Emitted when the client begins the reconnection process. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .reconnect) {data, ack in + /// // Some reconnect event logic + /// } + /// ``` case reconnect - /// Called each time the client tries to reconnect to the server. + /// Emitted each time the client tries to reconnect to the server. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .reconnectAttempt) {data, ack in + /// // Some reconnect attempt logging + /// } + /// ``` case reconnectAttempt - /// Called every time there is a change in the client's status. + /// Emitted whenever the engine sends a ping. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .sentPing) {_, _ in + /// // Maybe keep track of latency? + /// } + /// ``` + case sentPing + + /// Emitted every time there is a change in the client's status. + /// + /// Usage: + /// + /// ```swift + /// socket.on(clientEvent: .statusChange) {data, ack in + /// // Some status changing logging + /// } + /// ``` case statusChange } diff --git a/Source/SocketIO/Engine/SocketEngine.swift b/Source/SocketIO/Engine/SocketEngine.swift index c5ba48d..d83bc9e 100644 --- a/Source/SocketIO/Engine/SocketEngine.swift +++ b/Source/SocketIO/Engine/SocketEngine.swift @@ -485,6 +485,8 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll if message == "3probe" { upgradeTransport() } + + client?.engineDidReceivePong() } /// Parses raw binary received from engine.io. @@ -566,6 +568,8 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll engineQueue.asyncAfter(deadline: DispatchTime.now() + .milliseconds(pingInterval)) {[weak self] in self?.sendPing() } + + client?.engineDidSendPing() } // Moves from long-polling to websockets diff --git a/Source/SocketIO/Engine/SocketEngineClient.swift b/Source/SocketIO/Engine/SocketEngineClient.swift index dc2692c..d6383a3 100644 --- a/Source/SocketIO/Engine/SocketEngineClient.swift +++ b/Source/SocketIO/Engine/SocketEngineClient.swift @@ -44,6 +44,12 @@ import Foundation /// - parameter reason: The reason the engine opened. func engineDidOpen(reason: String) + /// Called when the engine receives a pong message. + func engineDidReceivePong() + + /// Called when the sends a ping to the server. + func engineDidSendPing() + /// Called when the engine has a message that must be parsed. /// /// - parameter msg: The message that needs parsing. diff --git a/Tests/TestSocketIO/SocketSideEffectTest.swift b/Tests/TestSocketIO/SocketSideEffectTest.swift index d3466b1..892e848 100644 --- a/Tests/TestSocketIO/SocketSideEffectTest.swift +++ b/Tests/TestSocketIO/SocketSideEffectTest.swift @@ -412,6 +412,30 @@ class SocketSideEffectTest: XCTestCase { XCTAssertEqual(socket.nsp, "/", "It should set the namespace after creation") } + func testClientCallsSentPingHandler() { + let expect = expectation(description: "The client should emit a sentPing event") + + socket.on(clientEvent: .sentPing) {data, ack in + expect.fulfill() + } + + socket.engineDidSendPing() + + waitForExpectations(timeout: 0.2) + } + + func testClientCallsGotPongHandler() { + let expect = expectation(description: "The client should emit a gotPong event") + + socket.on(clientEvent: .gotPong) {data, ack in + expect.fulfill() + } + + socket.engineDidReceivePong() + + waitForExpectations(timeout: 0.2) + } + let data = "test".data(using: String.Encoding.utf8)! let data2 = "test2".data(using: String.Encoding.utf8)! private var socket: SocketIOClient!