@@ -16,11 +16,13 @@ To install, simply:
16
16
17
17
#### Swift Package Manager
18
18
19
+ #### ⚠️ For iOS before 13 version, please use 0.4.0
20
+
19
21
Add the following line to your ` Package.swift `
20
22
21
23
``` swift
22
24
// ...
23
- .package (name : " ActionCableSwift" , url : " https://github.com/nerzh/Action-Cable-Swift.git" , from : " 0.3.2 " ),
25
+ .package (name : " ActionCableSwift" , url : " https://github.com/nerzh/Action-Cable-Swift.git" , from : " 1.0.0 " ),
24
26
targets: [
25
27
.target (
26
28
name : " YourPackageName" ,
@@ -30,292 +32,8 @@ Add the following line to your `Package.swift`
30
32
// ...
31
33
```
32
34
33
- #### Cocoa Pods
34
-
35
- Add the following line to your ` Podfile `
36
-
37
- ``` ruby
38
- pod ' ActionCableSwift'
39
- ```
40
-
41
- and you can import ActionCableSwift
42
-
43
- ``` swift
44
- import ActionCableSwift
45
- ```
46
35
# Usage
47
36
48
- ---
49
-
50
- ## Your WebSocketService should to implement the ` ACWebSocketProtocol ` protocol.
51
-
52
- ---
53
-
54
- ### Use with [ Websocket-kit] ( https://github.com/vapor/websocket-kit )
55
-
56
- #### I highly recommend not using Starscream to implement a WebSocket, because they have a strange implementation that does not allow conveniently reconnecting to a remote server after disconnecting. There is also a cool and fast alternative from the [ Swift Server Work Group (SSWG)] ( https://swift.org/server/ ) , package named [ Websocket-kit] ( https://github.com/vapor/websocket-kit ) .
57
-
58
- [ Websocket-kit] ( https://github.com/vapor/websocket-kit ) is SPM(Swift Package Manager) client library built on [ Swift-NIO] ( https://github.com/apple/swift-nio )
59
-
60
- Package.swift
61
- ``` swift
62
- // ...
63
- dependencies: [
64
- .package (name : " ActionCableSwift" , url : " https://github.com/nerzh/Action-Cable-Swift.git" , from : " 0.3.0" ),
65
- .package (name : " websocket-kit" , url : " https://github.com/vapor/websocket-kit.git" , .upToNextMinor (from : " 2.0.0" ))
66
- ],
67
- targets: [
68
- .target (
69
- name : " YourPackageName" ,
70
- dependencies : [
71
- .product (name : " ActionCableSwift" , package : " ActionCableSwift" ),
72
- .product (name : " WebSocketKit" , package : " websocket-kit" )
73
- ])
74
- // ...
75
- ```
76
-
77
-
78
- or inside xcode
79
-
80
-
81
- <img width =" 733 " alt =" Снимок экрана 2020-08-28 в 14 05 21 " src =" https://user-images.githubusercontent.com/10519803/91554329-975aba00-e937-11ea-9a98-eaff35191197.png " >
82
-
83
-
84
- <details >
85
- <summary >SPOILER: Recommended implementation WSS based on Websocket-kit(Swift-NIO)</summary >
86
-
87
-
88
- This is propertyWrapper for threadsafe access to webSocket instance
89
-
90
- ``` swift
91
- import Foundation
92
-
93
- @propertyWrapper
94
- struct Atomic <Value > {
95
-
96
- private var value: Value
97
- private let lock = NSLock ()
98
-
99
- init (wrappedValue value : Value ) {
100
- self .value = value
101
- }
102
-
103
- var wrappedValue: Value {
104
- get { return load () }
105
- set { store (newValue : newValue) }
106
- }
107
-
108
- func load () -> Value {
109
- lock.lock ()
110
- defer { lock.unlock () }
111
- return value
112
- }
113
-
114
- mutating func store (newValue : Value ) {
115
- lock.lock ()
116
- defer { lock.unlock () }
117
- value = newValue
118
- }
119
- }
120
-
121
- ```
122
-
123
- This is implementation WSS
124
-
125
- ``` swift
126
- import NIO
127
- import NIOHTTP1
128
- import NIOWebSocket
129
- import WebSocketKit
130
-
131
- final class WSS : ACWebSocketProtocol {
132
-
133
- var url: URL
134
- private var eventLoopGroup: EventLoopGroup
135
- @Atomic var ws: WebSocket?
136
-
137
- init (stringURL : String , coreCount : Int = System.coreCount ) {
138
- url = URL (string : stringURL)!
139
- eventLoopGroup = MultiThreadedEventLoopGroup (numberOfThreads : coreCount)
140
- }
141
-
142
- var onConnected: ((_ headers: [String : String ]? ) -> Void )?
143
- var onDisconnected: ((_ reason: String ? ) -> Void )?
144
- var onCancelled: (() -> Void )?
145
- var onText: ((_ text: String ) -> Void )?
146
- var onBinary: ((_ data: Data) -> Void )?
147
- var onPing: (() -> Void )?
148
- var onPong: (() -> Void )?
149
-
150
- func connect (headers : [String : String ]? ) {
151
-
152
- var httpHeaders: HTTPHeaders = .init ()
153
- headers? .forEach ({ (name, value) in
154
- httpHeaders.add (name : name, value : value)
155
- })
156
- let promise: EventLoopPromise<Void > = eventLoopGroup.next ().makePromise (of : Void .self )
157
-
158
- WebSocket.connect (to : url.absoluteString ,
159
- headers : httpHeaders,
160
- on : eventLoopGroup
161
- ) { ws in
162
- self .ws = ws
163
-
164
- ws.onPing { [weak self ] (ws) in
165
- self ? .onPing ? ()
166
- }
167
-
168
- ws.onPong { [weak self ] (ws) in
169
- self ? .onPong ? ()
170
- }
171
-
172
- ws.onClose .whenComplete { [weak self ] (result) in
173
- switch result {
174
- case .success :
175
- self ? .onDisconnected ? (nil )
176
- self ? .onCancelled ? ()
177
- case let .failure (error):
178
- self ? .onDisconnected ? (error.localizedDescription )
179
- self ? .onCancelled ? ()
180
- }
181
- }
182
-
183
- ws.onText { (ws, text) in
184
- self .onText ? (text)
185
- }
186
-
187
- ws.onBinary { (ws, buffer) in
188
- var data: Data = Data ()
189
- data.append (contentsOf : buffer.readableBytesView )
190
- self .onBinary ? (data)
191
- }
192
-
193
- }.cascade (to : promise)
194
-
195
- promise.futureResult .whenSuccess { [weak self ] (_ ) in
196
- guard let self = self else { return }
197
- self .onConnected ? (nil )
198
- }
199
- }
200
-
201
- func disconnect () {
202
- ws? .close (promise : nil )
203
- }
204
-
205
- func send (data : Data) {
206
- ws? .send ([UInt8 ](data))
207
- }
208
-
209
- func send (data : Data, _ completion : (() -> Void )? ) {
210
- let promise: EventLoopPromise<Void >? = ws? .eventLoop .next ().makePromise (of : Void .self )
211
- ws? .send ([UInt8 ](data), promise : promise)
212
- promise? .futureResult .whenComplete { (_ ) in
213
- completion? ()
214
- }
215
- }
216
-
217
- func send (text : String ) {
218
- ws? .send (text)
219
- }
220
-
221
- func send (text : String , _ completion : (() -> Void )? ) {
222
- let promise: EventLoopPromise<Void >? = ws? .eventLoop .next ().makePromise (of : Void .self )
223
- ws? .send (text, promise : promise)
224
- promise? .futureResult .whenComplete { (_ ) in
225
- completion? ()
226
- }
227
- }
228
- }
229
- ```
230
- </details >
231
-
232
- ---
233
-
234
- ### Use with [ Starscream] ( https://github.com/daltoniam/Starscream )
235
-
236
- ``` ruby
237
- pod ' Starscream' , ' ~> 4.0.0'
238
- ```
239
- <details >
240
- <summary >SPOILER: If you still want to use "Starscream", then you can to copy this code for websocket client</summary >
241
-
242
- ``` swift
243
- import Foundation
244
- import Starscream
245
-
246
- class WSS : ACWebSocketProtocol , WebSocketDelegate {
247
-
248
- var url: URL
249
- var ws: WebSocket
250
-
251
- init (stringURL : String ) {
252
- url = URL (string : stringURL)!
253
- ws = WebSocket (request : URLRequest (url : url))
254
- ws.delegate = self
255
- }
256
-
257
- var onConnected: ((_ headers: [String : String ]? ) -> Void )?
258
- var onDisconnected: ((_ reason: String ? ) -> Void )?
259
- var onCancelled: (() -> Void )?
260
- var onText: ((_ text: String ) -> Void )?
261
- var onBinary: ((_ data: Data) -> Void )?
262
- var onPing: (() -> Void )?
263
- var onPong: (() -> Void )?
264
-
265
- func connect (headers : [String : String ]? ) {
266
- ws.request .allHTTPHeaderFields = headers
267
- ws.connect ()
268
- }
269
-
270
- func disconnect () {
271
- ws.disconnect ()
272
- }
273
-
274
- func send (data : Data) {
275
- ws.write (data : data)
276
- }
277
-
278
- func send (data : Data, _ completion : (() -> Void )? ) {
279
- ws.write (data : data, completion : completion)
280
- }
281
-
282
- func send (text : String ) {
283
- ws.write (string : text)
284
- }
285
-
286
- func send (text : String , _ completion : (() -> Void )? ) {
287
- ws.write (string : text, completion : completion)
288
- }
289
-
290
- func didReceive (event : WebSocketEvent, client : WebSocket) {
291
- switch event {
292
- case .connected (let headers):
293
- onConnected? (headers)
294
- case .disconnected (let reason, let code):
295
- onDisconnected? (reason)
296
- case .text (let string):
297
- onText? (string)
298
- case .binary (let data):
299
- onBinary? (data)
300
- case .ping (_ ):
301
- onPing? ()
302
- case .pong (_ ):
303
- onPong? ()
304
- case .cancelled :
305
- onCancelled? ()
306
- default : break
307
- }
308
- }
309
- }
310
-
311
- ```
312
- </details >
313
-
314
- ---
315
-
316
- ### Next step to use ActionCableSwift
317
-
318
-
319
37
``` swift
320
38
import ActionCableSwift
321
39
@@ -324,7 +42,7 @@ let ws: WSS = .init(stringURL: "ws://localhost:3001/cable")
324
42
325
43
/// action cable client
326
44
let clientOptions: ACClientOptions = .init (debug : false , reconnect : true )
327
- let client: ACClient = .init (ws : ws , options : clientOptions)
45
+ let client: ACClient = .init (stringURL : " ws://localhost:3001/cable " , options : clientOptions)
328
46
/// pass headers to connect
329
47
/// on server you can get this with env['HTTP_COOKIE']
330
48
client.headers = [" COOKIE" : " Value" ]
@@ -402,13 +120,23 @@ client.headers = [
402
120
403
121
---
404
122
405
- ## Requirements
123
+ # If you want to implement your own WebSocket Provider, you should to implement the ` ACWebSocketProtocol ` protocol and use another initializator for ACClient
406
124
407
- Any Web Socket Library, e.g.
125
+ ``` swift
126
+ import ActionCableSwift
408
127
409
- [ Websocket-kit] ( https://github.com/vapor/websocket-kit )
128
+ /// web socket client
129
+ let ws: YourWSS = .init (stringURL : " ws://localhost:3001/cable" )
130
+
131
+ /// action cable client
132
+ let clientOptions: ACClientOptions = .init (debug : false , reconnect : true )
133
+ let client: ACClient = .init (ws : ws, options : clientOptions)
134
+ ```
410
135
411
- [ Starscream] ( https://github.com/daltoniam/Starscream )
136
+ ---
137
+ ## Requirements
138
+
139
+ [ Websocket-kit] ( https://github.com/vapor/websocket-kit )
412
140
413
141
## Author
414
142
0 commit comments