1
1
package io .ably .lib .transport ;
2
2
3
3
import io .ably .lib .http .HttpUtils ;
4
+ import io .ably .lib .network .WebSocketClient ;
5
+ import io .ably .lib .network .WebSocketEngine ;
6
+ import io .ably .lib .network .WebSocketEngineConfig ;
7
+ import io .ably .lib .network .WebSocketEngineFactory ;
8
+ import io .ably .lib .network .WebSocketListener ;
9
+ import io .ably .lib .network .NotConnectedException ;
4
10
import io .ably .lib .types .AblyException ;
5
11
import io .ably .lib .types .ErrorInfo ;
6
12
import io .ably .lib .types .Param ;
7
13
import io .ably .lib .types .ProtocolMessage ;
8
14
import io .ably .lib .types .ProtocolSerializer ;
15
+ import io .ably .lib .util .ClientOptionsUtils ;
9
16
import io .ably .lib .util .Log ;
10
- import org .java_websocket .WebSocket ;
11
- import org .java_websocket .client .WebSocketClient ;
12
- import org .java_websocket .exceptions .WebsocketNotConnectedException ;
13
- import org .java_websocket .framing .CloseFrame ;
14
- import org .java_websocket .framing .Framedata ;
15
- import org .java_websocket .handshake .ServerHandshake ;
16
-
17
- import javax .net .ssl .HttpsURLConnection ;
17
+
18
18
import javax .net .ssl .SSLContext ;
19
- import javax .net .ssl .SSLParameters ;
20
- import javax .net .ssl .SSLSession ;
21
- import java .net .URI ;
22
19
import java .nio .ByteBuffer ;
23
20
import java .util .Timer ;
24
21
import java .util .TimerTask ;
@@ -50,7 +47,7 @@ public class WebSocketTransport implements ITransport {
50
47
private final boolean channelBinaryMode ;
51
48
private String wsUri ;
52
49
private ConnectListener connectListener ;
53
- private WsClient wsConnection ;
50
+ private WebSocketClient webSocketClient ;
54
51
/******************
55
52
* protected constructor
56
53
******************/
@@ -81,15 +78,26 @@ public void connect(ConnectListener connectListener) {
81
78
82
79
Log .d (TAG , "connect(); wsUri = " + wsUri );
83
80
synchronized (this ) {
84
- wsConnection = new WsClient (URI .create (wsUri ), this ::receive );
81
+ WebSocketEngineFactory engineFactory = WebSocketEngineFactory .getFirstAvailable ();
82
+ Log .v (TAG , String .format ("Using %s WebSocket Engine" , engineFactory .getEngineType ().name ()));
83
+
84
+ WebSocketEngineConfig .WebSocketEngineConfigBuilder configBuilder = WebSocketEngineConfig .builder ();
85
+ configBuilder
86
+ .tls (isTls )
87
+ .host (params .host )
88
+ .proxy (ClientOptionsUtils .covertToProxyConfig (params .getClientOptions ()));
89
+
85
90
if (isTls ) {
86
91
SSLContext sslContext = SSLContext .getInstance ("TLS" );
87
92
sslContext .init (null , null , null );
88
93
SafeSSLSocketFactory factory = new SafeSSLSocketFactory (sslContext .getSocketFactory ());
89
- wsConnection . setSocketFactory (factory );
94
+ configBuilder . sslSocketFactory (factory );
90
95
}
96
+
97
+ WebSocketEngine engine = engineFactory .create (configBuilder .build ());
98
+ webSocketClient = engine .create (wsUri , new WebSocketHandler (this ::receive ));
91
99
}
92
- wsConnection .connect ();
100
+ webSocketClient .connect ();
93
101
} catch (AblyException e ) {
94
102
Log .e (TAG , "Unexpected exception attempting connection; wsUri = " + wsUri , e );
95
103
connectListener .onTransportUnavailable (this , e .errorInfo );
@@ -103,9 +111,9 @@ public void connect(ConnectListener connectListener) {
103
111
public void close () {
104
112
Log .d (TAG , "close()" );
105
113
synchronized (this ) {
106
- if (wsConnection != null ) {
107
- wsConnection .close ();
108
- wsConnection = null ;
114
+ if (webSocketClient != null ) {
115
+ webSocketClient .close ();
116
+ webSocketClient = null ;
109
117
}
110
118
}
111
119
}
@@ -127,14 +135,14 @@ public void send(ProtocolMessage msg) throws AblyException {
127
135
ProtocolMessage decodedMsg = ProtocolSerializer .readMsgpack (encodedMsg );
128
136
Log .v (TAG , "send(): " + decodedMsg .action + ": " + new String (ProtocolSerializer .writeJSON (decodedMsg )));
129
137
}
130
- wsConnection .send (encodedMsg );
138
+ webSocketClient .send (encodedMsg );
131
139
} else {
132
140
// Check the logging level to avoid performance hit associated with building the message
133
141
if (Log .level <= Log .VERBOSE )
134
142
Log .v (TAG , "send(): " + new String (ProtocolSerializer .writeJSON (msg )));
135
- wsConnection .send (ProtocolSerializer .writeJSON (msg ));
143
+ webSocketClient .send (ProtocolSerializer .writeJSON (msg ));
136
144
}
137
- } catch (WebsocketNotConnectedException e ) {
145
+ } catch (NotConnectedException e ) {
138
146
if (connectListener != null ) {
139
147
connectListener .onTransportUnavailable (this , AblyException .fromThrowable (e ).errorInfo );
140
148
} else
@@ -180,7 +188,7 @@ public WebSocketTransport getTransport(TransportParams params, ConnectionManager
180
188
* WebSocketHandler methods
181
189
**************************/
182
190
183
- class WsClient extends WebSocketClient {
191
+ class WebSocketHandler implements WebSocketListener {
184
192
private final WebSocketReceiver receiver ;
185
193
/***************************
186
194
* WsClient private members
@@ -189,38 +197,16 @@ class WsClient extends WebSocketClient {
189
197
private Timer timer = new Timer ();
190
198
private TimerTask activityTimerTask = null ;
191
199
private long lastActivityTime ;
192
- private boolean shouldExplicitlyVerifyHostname = true ;
193
200
194
- WsClient (URI serverUri , WebSocketReceiver receiver ) {
195
- super (serverUri );
201
+ WebSocketHandler (WebSocketReceiver receiver ) {
196
202
this .receiver = receiver ;
197
203
}
198
204
199
205
@ Override
200
- public void onOpen (ServerHandshake handshakedata ) {
206
+ public void onOpen () {
201
207
Log .d (TAG , "onOpen()" );
202
- if (params .options .tls && shouldExplicitlyVerifyHostname && !isHostnameVerified (params .host )) {
203
- close ();
204
- } else {
205
- connectListener .onTransportAvailable (WebSocketTransport .this );
206
- flagActivity ();
207
- }
208
- }
209
-
210
- /**
211
- * Added because we had to override the onSetSSLParameters() that usually performs this verification.
212
- * When the minSdkVersion will be updated to 24 we should remove this method and its usages.
213
- * https://github.com/TooTallNate/Java-WebSocket/wiki/No-such-method-error-setEndpointIdentificationAlgorithm#workaround
214
- */
215
- private boolean isHostnameVerified (String hostname ) {
216
- final SSLSession session = getSSLSession ();
217
- if (HttpsURLConnection .getDefaultHostnameVerifier ().verify (hostname , session )) {
218
- Log .v (TAG , "Successfully verified hostname" );
219
- return true ;
220
- } else {
221
- Log .e (TAG , "Hostname verification failed, expected " + hostname + ", found " + session .getPeerHost ());
222
- return false ;
223
- }
208
+ connectListener .onTransportAvailable (WebSocketTransport .this );
209
+ flagActivity ();
224
210
}
225
211
226
212
@ Override
@@ -253,16 +239,14 @@ public void onMessage(String string) {
253
239
254
240
/* This allows us to detect a websocket ping, so we don't need Ably pings. */
255
241
@ Override
256
- public void onWebsocketPing (WebSocket conn , Framedata f ) {
242
+ public void onWebsocketPing () {
257
243
Log .d (TAG , "onWebsocketPing()" );
258
- /* Call superclass to ensure the pong is sent. */
259
- super .onWebsocketPing (conn , f );
260
244
flagActivity ();
261
245
}
262
246
263
247
@ Override
264
- public void onClose (final int wsCode , final String wsReason , final boolean remote ) {
265
- Log .d (TAG , "onClose(): wsCode = " + wsCode + "; wsReason = " + wsReason + "; remote = " + remote );
248
+ public void onClose (final int wsCode , final String wsReason ) {
249
+ Log .d (TAG , "onClose(): wsCode = " + wsCode + "; wsReason = " + wsReason + "; remote = " + false );
266
250
267
251
ErrorInfo reason ;
268
252
switch (wsCode ) {
@@ -301,23 +285,14 @@ public void onClose(final int wsCode, final String wsReason, final boolean remot
301
285
}
302
286
303
287
@ Override
304
- public void onError (final Exception e ) {
305
- Log .e (TAG , "Connection error " , e );
306
- connectListener .onTransportUnavailable (WebSocketTransport .this , new ErrorInfo (e .getMessage (), 503 , 80000 ));
288
+ public void onError (Throwable throwable ) {
289
+ Log .e (TAG , "Connection error " , throwable );
290
+ connectListener .onTransportUnavailable (WebSocketTransport .this , new ErrorInfo (throwable .getMessage (), 503 , 80000 ));
307
291
}
308
292
309
293
@ Override
310
- protected void onSetSSLParameters (SSLParameters sslParameters ) {
311
- try {
312
- super .onSetSSLParameters (sslParameters );
313
- shouldExplicitlyVerifyHostname = false ;
314
- } catch (NoSuchMethodError exception ) {
315
- // This error will be thrown on Android below level 24.
316
- // When the minSdkVersion will be updated to 24 we should remove this overridden method.
317
- // https://github.com/TooTallNate/Java-WebSocket/wiki/No-such-method-error-setEndpointIdentificationAlgorithm#workaround
318
- Log .w (TAG , "Error when trying to set SSL parameters, most likely due to an old Java API version" , exception );
319
- shouldExplicitlyVerifyHostname = true ;
320
- }
294
+ public void onOldJavaVersionDetected (Throwable throwable ) {
295
+ Log .w (TAG , "Error when trying to set SSL parameters, most likely due to an old Java API version" , throwable );
321
296
}
322
297
323
298
private synchronized void dispose () {
@@ -391,7 +366,7 @@ private synchronized void onActivityTimerExpiry() {
391
366
// If we have no time remaining, then close the connection
392
367
if (timeRemaining <= 0 ) {
393
368
Log .e (TAG , "No activity for " + getActivityTimeout () + "ms, closing connection" );
394
- closeConnection ( CloseFrame . ABNORMAL_CLOSE , "timed out" );
369
+ webSocketClient . cancel ( ABNORMAL_CLOSE , "timed out" );
395
370
return ;
396
371
}
397
372
0 commit comments