Merge branch 'development'
* development: update readme and changelog for new version add changelog entry for exponential backoff config setting and test updates for reconnectWaitMax and randomizationFactor add configurable exponential backoff Fix #1147 Bump Starscream to 3.0.6 Update to Swift 4.2
This commit is contained in:
commit
00aaea935c
@ -1 +0,0 @@
|
||||
4.0
|
||||
@ -1,3 +1,9 @@
|
||||
# v14.0.0
|
||||
|
||||
- Minimum version of the client is now Swift 4.2.
|
||||
- Add exponential backoff for reconnects, with `reconnectWaitMax` and `randomizationFactor` options [#1149](https://github.com/socketio/socket.io-client-swift/pull/1149)
|
||||
- `statusChange` event's data format adds a second value, the raw value of the status. This is for use in Objective-C. [#1147](https://github.com/socketio/socket.io-client-swift/issues/1147)
|
||||
|
||||
# v13.4.0
|
||||
|
||||
- Add emits with write completion handlers. [#1096](https://github.com/socketio/socket.io-client-swift/issues/1096)
|
||||
@ -69,4 +75,3 @@ Important API changes
|
||||
- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
|
||||
- Makes the framework a single target.
|
||||
- Updates Starscream to 3.0
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// swift-tools-version:4.0
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
|
||||
10
README.md
10
README.md
@ -63,7 +63,7 @@ SocketIOClient* socket = manager.defaultSocket;
|
||||
## FAQS
|
||||
Checkout the [FAQs](https://nuclearace.github.io/Socket.IO-Client-Swift/faq.html) for commonly asked questions.
|
||||
|
||||
Checkout the [12to13](https://nuclearace.github.io/Socket.IO-Client-Swift/12to13.html) guide for migrating to v13.
|
||||
Checkout the [12to13](https://nuclearace.github.io/Socket.IO-Client-Swift/12to13.html) guide for migrating to v13+ from v12 below.
|
||||
|
||||
|
||||
## Installation
|
||||
@ -76,7 +76,7 @@ If you need Swift 3.x use v11.1.3.
|
||||
### Swift Package Manager
|
||||
Add the project as a dependency to your Package.swift:
|
||||
```swift
|
||||
// swift-tools-version:4.0
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@ -86,7 +86,7 @@ let package = Package(
|
||||
.executable(name: "socket.io-test", targets: ["YourTargetName"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "13.3.0"))
|
||||
.package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "14.0.0"))
|
||||
],
|
||||
targets: [
|
||||
.target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources")
|
||||
@ -99,7 +99,7 @@ Then import `import SocketIO`.
|
||||
### Carthage
|
||||
Add this line to your `Cartfile`:
|
||||
```
|
||||
github "socketio/socket.io-client-swift" ~> 13.3.0
|
||||
github "socketio/socket.io-client-swift" ~> 14.0.0
|
||||
```
|
||||
|
||||
Run `carthage update --platform ios,macosx`.
|
||||
@ -113,7 +113,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
|
||||
use_frameworks!
|
||||
|
||||
target 'YourApp' do
|
||||
pod 'Socket.IO-Client-Swift', '~> 13.3.0'
|
||||
pod 'Socket.IO-Client-Swift', '~> 14.0.0'
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
@ -21,9 +21,11 @@ Pod::Spec.new do |s|
|
||||
:tag => 'v13.4.0',
|
||||
:submodules => true
|
||||
}
|
||||
|
||||
s.swift_version = "4.2"
|
||||
s.pod_target_xcconfig = {
|
||||
'SWIFT_VERSION' => '4.0'
|
||||
}
|
||||
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
|
||||
s.dependency "Starscream", "~> 3.0.2"
|
||||
s.dependency "Starscream", "~> 3.0.6"
|
||||
end
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C65763817782DFAC67BE05C /* SocketManager.swift */; };
|
||||
1C6573B22DC9423CDFC32F05 /* SocketRawView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C657533E849FC3E4342C602 /* SocketRawView.swift */; };
|
||||
1C657CDE5D510E8E2E573E39 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6577B639C34EE1C8829D9A /* utils.swift */; };
|
||||
1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */; };
|
||||
1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; };
|
||||
1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; };
|
||||
@ -64,6 +65,7 @@
|
||||
1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManagerSpec.swift; sourceTree = "<group>"; };
|
||||
1C657533E849FC3E4342C602 /* SocketRawView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketRawView.swift; sourceTree = "<group>"; };
|
||||
1C65763817782DFAC67BE05C /* SocketManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManager.swift; sourceTree = "<group>"; };
|
||||
1C6577B639C34EE1C8829D9A /* utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = utils.swift; sourceTree = "<group>"; };
|
||||
1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = "<group>"; };
|
||||
1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = "<group>"; };
|
||||
1C686BD41F869AF1007D8627 /* SocketSideEffectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketSideEffectTest.swift; sourceTree = "<group>"; };
|
||||
@ -159,6 +161,7 @@
|
||||
1C686BD71F869AF1007D8627 /* SocketParserTest.swift */,
|
||||
1C686BD81F869AF1007D8627 /* SocketNamespacePacketTest.swift */,
|
||||
DD52BBAC5FAA7730D32CD5BF /* SocketMangerTest.swift */,
|
||||
1C6577B639C34EE1C8829D9A /* utils.swift */,
|
||||
);
|
||||
name = TestSocketIO;
|
||||
path = Tests/TestSocketIO;
|
||||
@ -501,6 +504,7 @@
|
||||
1C686BE81F869AFD007D8627 /* SocketNamespacePacketTest.swift in Sources */,
|
||||
DD52BCCD25EFA76E0F9B313C /* SocketMangerTest.swift in Sources */,
|
||||
DD52B53F2609D91A683DFCDD /* ManagerObjectiveCTest.m in Sources */,
|
||||
1C657CDE5D510E8E2E573E39 /* utils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@ -83,7 +83,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec {
|
||||
@objc
|
||||
public private(set) var status = SocketIOStatus.notConnected {
|
||||
didSet {
|
||||
handleClientEvent(.statusChange, data: [status])
|
||||
handleClientEvent(.statusChange, data: [status, status.rawValue])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -75,9 +75,15 @@ public enum SocketIOClientOption : ClientOption {
|
||||
/// The number of times to try and reconnect before giving up. Pass `-1` to [never give up](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
|
||||
case reconnectAttempts(Int)
|
||||
|
||||
/// The number of seconds to wait before reconnect attempts.
|
||||
/// The minimum number of seconds to wait before reconnect attempts.
|
||||
case reconnectWait(Int)
|
||||
|
||||
/// The maximum number of seconds to wait before reconnect attempts.
|
||||
case reconnectWaitMax(Int)
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
case randomizationFactor(Double)
|
||||
|
||||
/// Set `true` if your server is using secure transports.
|
||||
case secure(Bool)
|
||||
|
||||
@ -125,6 +131,10 @@ public enum SocketIOClientOption : ClientOption {
|
||||
description = "reconnectAttempts"
|
||||
case .reconnectWait:
|
||||
description = "reconnectWait"
|
||||
case .reconnectWaitMax:
|
||||
description = "reconnectWaitMax"
|
||||
case .randomizationFactor:
|
||||
description = "randomizationFactor"
|
||||
case .secure:
|
||||
description = "secure"
|
||||
case .selfSigned:
|
||||
@ -170,6 +180,10 @@ public enum SocketIOClientOption : ClientOption {
|
||||
value = attempts
|
||||
case let .reconnectWait(wait):
|
||||
value = wait
|
||||
case let .reconnectWaitMax(wait):
|
||||
value = wait
|
||||
case let .randomizationFactor(factor):
|
||||
value = factor
|
||||
case let .secure(secure):
|
||||
value = secure
|
||||
case let .security(security):
|
||||
|
||||
@ -327,6 +327,9 @@ public enum SocketClientEvent : String {
|
||||
|
||||
/// Emitted every time there is a change in the client's status.
|
||||
///
|
||||
/// The payload for data is [SocketIOClientStatus, Int]. Where the second item is the raw value. Use the second one
|
||||
/// if you are working in Objective-C.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
|
||||
@ -97,9 +97,15 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
/// If `true`, this client will try and reconnect on any disconnects.
|
||||
public var reconnects = true
|
||||
|
||||
/// The number of seconds to wait before attempting to reconnect.
|
||||
/// The minimum number of seconds to wait before attempting to reconnect.
|
||||
public var reconnectWait = 10
|
||||
|
||||
/// The maximum number of seconds to wait before attempting to reconnect.
|
||||
public var reconnectWaitMax = 30
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
public var randomizationFactor = 0.5
|
||||
|
||||
/// The status of this manager.
|
||||
public private(set) var status: SocketIOStatus = .notConnected {
|
||||
didSet {
|
||||
@ -474,7 +480,21 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
currentReconnectAttempt += 1
|
||||
connect()
|
||||
|
||||
handleQueue.asyncAfter(deadline: DispatchTime.now() + Double(reconnectWait), execute: _tryReconnect)
|
||||
let interval = reconnectInterval(attempts: currentReconnectAttempt)
|
||||
DefaultSocketLogger.Logger.log("Scheduling reconnect in \(interval)s", type: SocketManager.logType)
|
||||
handleQueue.asyncAfter(deadline: DispatchTime.now() + interval, execute: _tryReconnect)
|
||||
}
|
||||
|
||||
func reconnectInterval(attempts: Int) -> Double {
|
||||
// apply exponential factor
|
||||
let backoffFactor = pow(1.5, attempts)
|
||||
let interval = Double(reconnectWait) * Double(truncating: backoffFactor as NSNumber)
|
||||
// add in a random factor smooth thundering herds
|
||||
let rand = Double.random(in: 0 ..< 1)
|
||||
let randomFactor = rand * randomizationFactor * Double(truncating: interval as NSNumber)
|
||||
// add in random factor, and clamp to min and max values
|
||||
let combined = interval + randomFactor
|
||||
return Double(fmax(Double(reconnectWait), fmin(combined, Double(reconnectWaitMax))))
|
||||
}
|
||||
|
||||
/// Sets manager specific configs.
|
||||
@ -493,6 +513,10 @@ open class SocketManager : NSObject, SocketManagerSpec, SocketParsable, SocketDa
|
||||
self.reconnectAttempts = attempts
|
||||
case let .reconnectWait(wait):
|
||||
reconnectWait = abs(wait)
|
||||
case let .reconnectWaitMax(wait):
|
||||
reconnectWaitMax = abs(wait)
|
||||
case let .randomizationFactor(factor):
|
||||
randomizationFactor = factor
|
||||
case let .log(log):
|
||||
DefaultSocketLogger.Logger.log = log
|
||||
case let .logger(logger):
|
||||
|
||||
@ -69,9 +69,15 @@ public protocol SocketManagerSpec : AnyObject, SocketEngineClient {
|
||||
/// If `true`, this manager will try and reconnect on any disconnects.
|
||||
var reconnects: Bool { get set }
|
||||
|
||||
/// The number of seconds to wait before attempting to reconnect.
|
||||
/// The minimum number of seconds to wait before attempting to reconnect.
|
||||
var reconnectWait: Int { get set }
|
||||
|
||||
/// The maximum number of seconds to wait before attempting to reconnect.
|
||||
var reconnectWaitMax: Int { get set }
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
var randomizationFactor: Double { get set }
|
||||
|
||||
/// The URL of the socket.io server.
|
||||
var socketURL: URL { get }
|
||||
|
||||
|
||||
@ -71,6 +71,10 @@ extension Dictionary where Key == String, Value == Any {
|
||||
return .reconnectAttempts(attempts)
|
||||
case let ("reconnectWait", wait as Int):
|
||||
return .reconnectWait(wait)
|
||||
case let ("reconnectWaitMax", wait as Int):
|
||||
return .reconnectWaitMax(wait)
|
||||
case let ("randomizationFactor", factor as Double):
|
||||
return .randomizationFactor(factor)
|
||||
case let ("secure", secure as Bool):
|
||||
return .secure(secure)
|
||||
case let ("security", security as SSLSecurity):
|
||||
|
||||
@ -15,6 +15,8 @@ class SocketMangerTest : XCTestCase {
|
||||
XCTAssertEqual(manager.handleQueue, DispatchQueue.main)
|
||||
XCTAssertTrue(manager.reconnects)
|
||||
XCTAssertEqual(manager.reconnectWait, 10)
|
||||
XCTAssertEqual(manager.reconnectWaitMax, 30)
|
||||
XCTAssertEqual(manager.randomizationFactor, 0.5)
|
||||
XCTAssertEqual(manager.status, .notConnected)
|
||||
}
|
||||
|
||||
@ -28,6 +30,21 @@ class SocketMangerTest : XCTestCase {
|
||||
XCTAssertEqual(manager.config.first!, .secure(true))
|
||||
}
|
||||
|
||||
func testBackoffIntervalCalulation() {
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWaitMax))
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 0), 15)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 1), 22.5)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 2), 33.75)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 50), Double(manager.reconnectWaitMax))
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWaitMax))
|
||||
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWait))
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 0), Double(manager.reconnectWait))
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 1), 15)
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 2), 22.5)
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWait))
|
||||
}
|
||||
|
||||
func testManagerCallsConnect() {
|
||||
setUpSockets()
|
||||
|
||||
@ -90,6 +107,8 @@ class SocketMangerTest : XCTestCase {
|
||||
.forceNew(true),
|
||||
.reconnects(false),
|
||||
.reconnectWait(5),
|
||||
.reconnectWaitMax(5),
|
||||
.randomizationFactor(0.7),
|
||||
.reconnectAttempts(5)
|
||||
])
|
||||
|
||||
@ -97,6 +116,8 @@ class SocketMangerTest : XCTestCase {
|
||||
XCTAssertTrue(manager.forceNew)
|
||||
XCTAssertFalse(manager.reconnects)
|
||||
XCTAssertEqual(manager.reconnectWait, 5)
|
||||
XCTAssertEqual(manager.reconnectWaitMax, 5)
|
||||
XCTAssertEqual(manager.randomizationFactor, 0.7)
|
||||
XCTAssertEqual(manager.reconnectAttempts, 5)
|
||||
}
|
||||
|
||||
|
||||
13
Tests/TestSocketIO/utils.swift
Normal file
13
Tests/TestSocketIO/utils.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by Erik Little on 2019-01-11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import SocketIO
|
||||
|
||||
public class OBjcUtils: NSObject {
|
||||
@objc
|
||||
public static func setTestStatus(socket: SocketIOClient, status: SocketIOStatus) {
|
||||
socket.setTestStatus(status)
|
||||
}
|
||||
}
|
||||
@ -34,6 +34,8 @@
|
||||
XCTAssertEqual(self.manager.handleQueue, dispatch_get_main_queue());
|
||||
XCTAssertTrue(self.manager.reconnects);
|
||||
XCTAssertEqual(self.manager.reconnectWait, 10);
|
||||
XCTAssertEqual(self.manager.reconnectWaitMax, 30);
|
||||
XCTAssertEqual(self.manager.randomizationFactor, 0.5);
|
||||
XCTAssertEqual(self.manager.status, SocketIOStatusNotConnected);
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
// Merely tests whether the Objective-C api breaks
|
||||
//
|
||||
|
||||
#import "SocketIO_Tests-Swift.h"
|
||||
#import "SocketObjectiveCTest.h"
|
||||
|
||||
@import Dispatch;
|
||||
@ -98,6 +99,19 @@
|
||||
sec = nil;
|
||||
}
|
||||
|
||||
- (void)testStatusChangeHandler {
|
||||
XCTestExpectation* expect = [self expectationWithDescription:@"statusChange should be correctly called"];
|
||||
|
||||
[self.socket on:@"statusChange" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
XCTAssertTrue([data[1] integerValue] == SocketIOStatusConnecting);
|
||||
[expect fulfill];
|
||||
}];
|
||||
|
||||
[OBjcUtils setTestStatusWithSocket:self.socket status:SocketIOStatusConnecting];
|
||||
|
||||
[self waitForExpectationsWithTimeout:0.3 handler:nil];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user