Skip to content
This repository was archived by the owner on Nov 2, 2020. It is now read-only.

Commit 2ac2951

Browse files
Ping optimization + custom encode / decode support
1 parent 215fdd6 commit 2ac2951

File tree

10 files changed

+163
-82
lines changed

10 files changed

+163
-82
lines changed

ClusterWS-Client-Swift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'ClusterWS-Client-Swift'
3-
s.version = '2.0.9'
3+
s.version = '3.0.0'
44
s.summary = 'Swift Client for ClusterWS'
55
s.description = 'Swift Client for ClusterWS - lightweight, fast and powerful framework for building horizontally & vertically scalable WebSocket applications in Node.js'
66
s.homepage = 'https://github.com/ClusterWS/ClusterWS-Client-Swift'

Docs/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
<h1 align="center">ClusterWS Swift Client</h1>
2-
<h6 align="center">Build Scalable Node.js WebSocket Applications</h6>
2+
<h6 align="center">Build Scalable Node.js WebSockets Applications</h6>
33

44
<p align="center">
5-
<img src="https://cdn.rawgit.com/goriunov/159120ca6a883d8d4e75543ec395d361/raw/146220360173a2428fceb44e7fc9b2cda8a17832/clusterws.svg" width="450">
5+
<img src="https://cdn.rawgit.com/goriunov/159120ca6a883d8d4e75543ec395d361/raw/d22028ecc726d7d3cc30a2a85cc7cc454b0afada/clusterws.svg" width="450">
66
</p>
77

88
<p align="center">
9-
<a title="Cocoapod Version" href="https://cocoapods.org/pods/ClusterWS-Client-Swift"><img src="https://img.shields.io/cocoapods/v/ClusterWS-Client-Swift.svg?style=for-the-badge"></a>
10-
<a title="Platforms" href="https://github.com/ClusterWS/ClusterWS-Client-Swift"><img src="https://img.shields.io/cocoapods/p/ClusterWS-Client-Swift.svg?style=for-the-badge"></a>
11-
<a title="License" href="https://github.com/ClusterWS/ClusterWS-Client-Swift/blob/master/LICENSE"><img src="https://img.shields.io/cocoapods/l/ClusterWS-Client-Swift.svg?style=for-the-badge"></a>
9+
<a title="Cocoapod Version" href="https://cocoapods.org/pods/ClusterWS-Client-Swift"><img src="https://img.shields.io/cocoapods/v/ClusterWS-Client-Swift.svg?colorB=AE1E80&style=for-the-badge"></a>
10+
<a title="Platforms" href="https://github.com/ClusterWS/ClusterWS-Client-Swift"><img src="https://img.shields.io/badge/platforms-ios | tvos | osx-AE1E80.svg?style=for-the-badge"></a>
11+
<a title="License" href="https://github.com/ClusterWS/ClusterWS-Client-Swift/blob/master/LICENSE"><img src="https://img.shields.io/badge/LICENSE-MIT-AE1E80.svg?style=for-the-badge"></a>
1212
</p>
1313

1414
<p align="center">
15-
<i>Official Swift Client library for <a href="https://github.com/ClusterWS/ClusterWS">ClusterWS</a> - lightweight, fast and powerful framework for building horizontally & vertically scalable WebSocket applications in Node.js</i>
15+
<i>Official <strong>Swift Client</strong> library for <a href="https://github.com/ClusterWS/ClusterWS">ClusterWS</a> - <strong>lightweight</strong>, <strong>fast</strong> and <strong>powerful</strong> framework for building <strong>scalable</strong> WebSockets applications in Node.js.</i>
1616
</p>
1717

1818
<h1></h1>

Sources/CWSChannel.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
import Foundation
1010

11-
// MARK: Properties & Initialization
1211
open class CWSChannel: Equatable {
12+
13+
// MARK: - Properties
14+
1315
public static func ==(lhs: CWSChannel, rhs: CWSChannel) -> Bool {
1416
if lhs.mChannelName == rhs.mChannelName {
1517
return true
@@ -22,15 +24,19 @@ open class CWSChannel: Equatable {
2224
private var mCompletion: CompletionHandler?
2325
private let mSocket: ClusterWS
2426

27+
// MARK: - Init
28+
2529
public init(channelName: String, socket: ClusterWS) {
2630
self.mChannelName = channelName
2731
self.mSocket = socket
2832
self.subscribe()
2933
}
3034
}
3135

32-
//MARK: Public methods
36+
// MARK: - Public
37+
3338
extension CWSChannel {
39+
3440
public func watch(completion: @escaping CompletionHandler) -> CWSChannel {
3541
self.mCompletion = completion
3642
return self
@@ -47,17 +53,21 @@ extension CWSChannel {
4753
}
4854
}
4955

50-
//MARK: Open methods
56+
// MARK: - Open methods
57+
5158
extension CWSChannel {
59+
5260
open func onMessage(data: Any) {
5361
if let completion = self.mCompletion {
5462
completion(data)
5563
}
5664
}
5765
}
5866

59-
//MARK: Private methods
67+
// MARK: - Private methods
68+
6069
extension CWSChannel {
70+
6171
private func subscribe() {
6272
self.mSocket.send(event: SystemEventType.subscribe.rawValue, data: self.mChannelName, type: .system)
6373
}

Sources/CWSDelegate.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,31 @@ import Foundation
1111
ClusterWS delegate methods
1212
*/
1313
public protocol CWSDelegate: class {
14+
15+
/// Called when socket is connected
1416
func onConnect()
17+
18+
/// Called when socket disconnected
1519
func onDisconnect(code: Int?, reason: String?)
20+
21+
/// Called on error
22+
/// - Parameter error: thrown error
1623
func onError(error: Error)
24+
25+
func decode(message: Any?) -> Any?
26+
27+
func encode(message: Any?) -> Any?
28+
}
29+
30+
extension CWSDelegate {
31+
32+
/// Custom decode that user can implement
33+
func decode(message: Any?) -> Any? {
34+
return nil
35+
}
36+
37+
/// Custom encode that user can implement
38+
func encode(message: Any?) -> Any? {
39+
return nil
40+
}
1741
}

Sources/CWSErrors.swift renamed to Sources/CWSError.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import Foundation
1010

11-
public enum CWSErrors: Error, LocalizedError {
11+
public enum CWSError: Error, LocalizedError {
1212
case invalidURL(String)
1313
case JSONStringConversionError(String)
1414
case JSONStringifyError(Any?)
@@ -17,6 +17,8 @@ public enum CWSErrors: Error, LocalizedError {
1717
case pingIntervalCastError(Any)
1818
case binaryCastError(Any)
1919
case binaryDecodeError(Any)
20+
case binaryEncodeError(Any)
21+
case failedToCastPingTimer
2022
public var localizedDescription: String {
2123
switch self {
2224
case .invalidURL(let url): return "Invalid URL: \(url)."
@@ -27,6 +29,8 @@ public enum CWSErrors: Error, LocalizedError {
2729
case .pingIntervalCastError(let json): return "Cannot cast ping interval as 'Double' from ping JSON, JSON: \(json)."
2830
case .binaryCastError(let json): return "Cannot cast ping binary as 'Bool' from ping JSON, JSON: \(json)."
2931
case .binaryDecodeError(let message): return "Cannot convert binary message to string using UTF8, message: \(message)"
32+
case .binaryEncodeError(let ping): return "Cannot encode ping message to binary, ping message: \(ping)"
33+
case .failedToCastPingTimer: return "Failed to get ping timer from settings, might be a server set up error"
3034
}
3135
}
3236
}

Sources/CWSParser.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ public enum MessageType: String {
1111
case publish
1212
case emit
1313
case system
14-
case ping
1514
}
1615

1716
public enum SystemEventType: String {
@@ -27,17 +26,20 @@ public enum SystemEventType: String {
2726
}
2827
}
2928

30-
// MARK: Properties & Initialization
29+
// MARK: - Properties & Initialization
3130
open class CWSParser {
31+
3232
private let mSocket: ClusterWS
3333

3434
public init(socket: ClusterWS) {
3535
self.mSocket = socket
3636
}
3737
}
3838

39-
//MARK: Open methods
39+
// MARK: - Open methods
40+
4041
extension CWSParser {
42+
4143
open func encode(event: String, data: Any? = nil, type: MessageType) -> String? {
4244
var jsonDict: [String: Any]
4345
switch type {
@@ -52,19 +54,21 @@ extension CWSParser {
5254
case .unsubscribe:
5355
jsonDict = ["#": ["s", "u", data]]
5456
}
55-
case .ping:
56-
return event
5757
}
5858
return self.JSONStringify(value: jsonDict)
5959
}
6060

61+
open func encode(message: String) -> Data? {
62+
return message.data(using: .utf8, allowLossyConversion: false)
63+
}
64+
6165
open func handleMessage(with string: String) {
6266
guard let jsonDict = self.convertToJSON(text: string) else {
63-
self.mSocket.delegate?.onError(error: CWSErrors.JSONStringConversionError(string))
67+
self.mSocket.delegate?.onError(error: CWSError.JSONStringConversionError(string))
6468
return
6569
}
6670
guard let jsonArray = jsonDict["#"] as? [Any] else {
67-
self.mSocket.delegate?.onError(error: CWSErrors.hashArrayCastError(jsonDict))
71+
self.mSocket.delegate?.onError(error: CWSError.hashArrayCastError(jsonDict))
6872
return
6973
}
7074
switch String(describing: jsonArray[0]) {
@@ -80,8 +84,10 @@ extension CWSParser {
8084
}
8185
}
8286

83-
//MARK: Private methods
87+
// MARK: - Private methods
88+
8489
extension CWSParser {
90+
8591
private func convertToJSON(text: String) -> [String: Any]? {
8692
if let data = text.data(using: .utf8) {
8793
do {
@@ -111,31 +117,33 @@ extension CWSParser {
111117

112118
private func handleP(with data: [Any]) {
113119
let channelName = String(describing: data[1])
114-
self.mSocket.getChannel(by: channelName)?.onMessage(data: data[2])
120+
let decodedMessage = self.mSocket.delegate?.decode(message: data[2]) ?? data[2]
121+
self.mSocket.getChannel(by: channelName)?.onMessage(data: decodedMessage)
115122
}
116123

117124
private func handleE(with data: [Any]) {
118125
let event = String(describing: data[1])
119-
let data = data[2]
120-
self.mSocket.emit(event: event, data: data)
126+
let decodedMessage = self.mSocket.delegate?.decode(message: data[2]) ?? data[2]
127+
self.mSocket.emit(event: event, data: decodedMessage)
121128
}
122129

123130
private func handleS(with data: [Any]) {
124131
switch String(describing: data[1]) {
125132
case "c":
126-
guard let pingJSON = data[2] as? [String: Any] else {
127-
self.mSocket.delegate?.onError(error: CWSErrors.pingJSONCastError(data[2]))
133+
let decodedMessage = self.mSocket.delegate?.decode(message: data[2]) ?? data[2]
134+
guard let pingJSON = decodedMessage as? [String: Any] else {
135+
self.mSocket.delegate?.onError(error: CWSError.pingJSONCastError(decodedMessage))
128136
return
129137
}
130138
guard let pingInterval = pingJSON["ping"] as? Double else {
131-
self.mSocket.delegate?.onError(error: CWSErrors.pingIntervalCastError(pingJSON))
139+
self.mSocket.delegate?.onError(error: CWSError.pingIntervalCastError(pingJSON))
132140
return
133141
}
134142
guard let binary = pingJSON["binary"] as? Bool else {
135-
self.mSocket.delegate?.onError(error: CWSErrors.binaryCastError(pingJSON))
143+
self.mSocket.delegate?.onError(error: CWSError.binaryCastError(pingJSON))
136144
return
137145
}
138-
self.mSocket.startPinging(with: pingInterval)
146+
self.mSocket.setPingInterval(pingInterval * 2 + 100)
139147
self.mSocket.setBinary(to: binary)
140148
self.mSocket.delegate?.onConnect()
141149
default:

Sources/CWSPing.swift

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,25 @@
88

99
import Foundation
1010

11-
// MARK: Properties & Initialization
1211
open class CWSPing {
13-
private var mMissedPing: Int = 0
12+
13+
// MARK: - Properties
14+
1415
private var mPingTimer: Timer?
1516
}
1617

17-
//MARK: Open methods
18+
// MARK: - Open methods
19+
1820
extension CWSPing {
19-
open func resetMissedPing() {
20-
self.mMissedPing = 0
21-
}
2221

23-
private func resetPingTimer() {
22+
open func stop() {
2423
self.mPingTimer?.invalidate()
2524
self.mPingTimer = nil
2625
}
2726

2827
@objc private func executionBlock(_ socket: ClusterWS) {
2928
func block(_ socket: ClusterWS) {
30-
if self.mMissedPing < 3 {
31-
self.mMissedPing += 1
32-
} else {
33-
if socket.getState() != .closed {
34-
socket.disconnect(closeCode: 4001, reason: "No pings")
35-
self.resetPingTimer()
36-
}
37-
}
29+
socket.disconnect(closeCode: 4001, reason: "No pings")
3830
}
3931

4032
guard let userInfoWS = self.mPingTimer?.userInfo as? ClusterWS else {
@@ -45,24 +37,20 @@ extension CWSPing {
4537
block(userInfoWS)
4638
}
4739

48-
open func stop() {
49-
self.mMissedPing = 0
50-
self.resetPingTimer()
51-
}
52-
53-
open func start(interval: TimeInterval, socket: ClusterWS) {
40+
open func restart(with interval: TimeInterval, socket: ClusterWS) {
41+
self.stop()
5442
if #available(iOS 10.0, *, OSX 10.12, tvOS 10.0, *) {
5543
self.mPingTimer = Timer.scheduledTimer(withTimeInterval: interval / 1000,
56-
repeats: true,
44+
repeats: false,
5745
block: { (timer) in
5846
self.executionBlock(socket)
5947
})
6048
} else {
61-
self.mPingTimer = Timer(timeInterval: interval,
49+
self.mPingTimer = Timer(timeInterval: interval / 1000,
6250
target: self,
6351
selector: #selector(executionBlock(_:)),
6452
userInfo: socket,
65-
repeats: true)
53+
repeats: false)
6654
self.mPingTimer?.fire()
6755
}
6856
}

Sources/CWSReconnection.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
import Foundation
1010

11-
// MARK: Properties & Initialization
1211
open class CWSReconnection {
12+
13+
// MARK: - Properties
14+
1315
private var mReconnectionTimer: Timer?
1416
private var mAutoReconnect: Bool
1517
private var mReconnectionAttempts: Int
@@ -18,6 +20,8 @@ open class CWSReconnection {
1820
private var mCurrentReconnectionAttempted: Int = 0
1921
private let mSocket: ClusterWS
2022

23+
// MARK: - Initialization
24+
2125
public init(socket: ClusterWS) {
2226
self.mSocket = socket
2327
self.mAutoReconnect = false
@@ -27,8 +31,10 @@ open class CWSReconnection {
2731
}
2832
}
2933

30-
//MARK: Open methods
34+
// MARK: - Open methods
35+
3136
extension CWSReconnection {
37+
3238
open func onConnected() {
3339
self.resetTimer()
3440
self.mReconnectionAttempts = 0
@@ -75,8 +81,10 @@ extension CWSReconnection {
7581
}
7682
}
7783

78-
//MARK: Private methods
84+
// MARK: Private methods
85+
7986
extension CWSReconnection {
87+
8088
private func resubscribe() {
8189
let channels = self.mSocket.getChannels()
8290
channels.forEach { _ = self.mSocket.subscribe($0.mChannelName) }

0 commit comments

Comments
 (0)