11package io .ably .lib .transport ;
22
33import 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 ;
410import io .ably .lib .types .AblyException ;
511import io .ably .lib .types .ErrorInfo ;
612import io .ably .lib .types .Param ;
713import io .ably .lib .types .ProtocolMessage ;
814import io .ably .lib .types .ProtocolSerializer ;
15+ import io .ably .lib .util .ClientOptionsUtils ;
916import 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+
1818import javax .net .ssl .SSLContext ;
19- import javax .net .ssl .SSLParameters ;
20- import javax .net .ssl .SSLSession ;
21- import java .net .URI ;
2219import java .nio .ByteBuffer ;
2320import java .util .Timer ;
2421import java .util .TimerTask ;
@@ -50,7 +47,7 @@ public class WebSocketTransport implements ITransport {
5047 private final boolean channelBinaryMode ;
5148 private String wsUri ;
5249 private ConnectListener connectListener ;
53- private WsClient wsConnection ;
50+ private WebSocketClient webSocketClient ;
5451 /******************
5552 * protected constructor
5653 ******************/
@@ -81,15 +78,26 @@ public void connect(ConnectListener connectListener) {
8178
8279 Log .d (TAG , "connect(); wsUri = " + wsUri );
8380 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+
8590 if (isTls ) {
8691 SSLContext sslContext = SSLContext .getInstance ("TLS" );
8792 sslContext .init (null , null , null );
8893 SafeSSLSocketFactory factory = new SafeSSLSocketFactory (sslContext .getSocketFactory ());
89- wsConnection . setSocketFactory (factory );
94+ configBuilder . sslSocketFactory (factory );
9095 }
96+
97+ WebSocketEngine engine = engineFactory .create (configBuilder .build ());
98+ webSocketClient = engine .create (wsUri , new WebSocketHandler (this ::receive ));
9199 }
92- wsConnection .connect ();
100+ webSocketClient .connect ();
93101 } catch (AblyException e ) {
94102 Log .e (TAG , "Unexpected exception attempting connection; wsUri = " + wsUri , e );
95103 connectListener .onTransportUnavailable (this , e .errorInfo );
@@ -103,9 +111,9 @@ public void connect(ConnectListener connectListener) {
103111 public void close () {
104112 Log .d (TAG , "close()" );
105113 synchronized (this ) {
106- if (wsConnection != null ) {
107- wsConnection .close ();
108- wsConnection = null ;
114+ if (webSocketClient != null ) {
115+ webSocketClient .close ();
116+ webSocketClient = null ;
109117 }
110118 }
111119 }
@@ -127,14 +135,14 @@ public void send(ProtocolMessage msg) throws AblyException {
127135 ProtocolMessage decodedMsg = ProtocolSerializer .readMsgpack (encodedMsg );
128136 Log .v (TAG , "send(): " + decodedMsg .action + ": " + new String (ProtocolSerializer .writeJSON (decodedMsg )));
129137 }
130- wsConnection .send (encodedMsg );
138+ webSocketClient .send (encodedMsg );
131139 } else {
132140 // Check the logging level to avoid performance hit associated with building the message
133141 if (Log .level <= Log .VERBOSE )
134142 Log .v (TAG , "send(): " + new String (ProtocolSerializer .writeJSON (msg )));
135- wsConnection .send (ProtocolSerializer .writeJSON (msg ));
143+ webSocketClient .send (ProtocolSerializer .writeJSON (msg ));
136144 }
137- } catch (WebsocketNotConnectedException e ) {
145+ } catch (NotConnectedException e ) {
138146 if (connectListener != null ) {
139147 connectListener .onTransportUnavailable (this , AblyException .fromThrowable (e ).errorInfo );
140148 } else
@@ -180,7 +188,7 @@ public WebSocketTransport getTransport(TransportParams params, ConnectionManager
180188 * WebSocketHandler methods
181189 **************************/
182190
183- class WsClient extends WebSocketClient {
191+ class WebSocketHandler implements WebSocketListener {
184192 private final WebSocketReceiver receiver ;
185193 /***************************
186194 * WsClient private members
@@ -189,38 +197,16 @@ class WsClient extends WebSocketClient {
189197 private Timer timer = new Timer ();
190198 private TimerTask activityTimerTask = null ;
191199 private long lastActivityTime ;
192- private boolean shouldExplicitlyVerifyHostname = true ;
193200
194- WsClient (URI serverUri , WebSocketReceiver receiver ) {
195- super (serverUri );
201+ WebSocketHandler (WebSocketReceiver receiver ) {
196202 this .receiver = receiver ;
197203 }
198204
199205 @ Override
200- public void onOpen (ServerHandshake handshakedata ) {
206+ public void onOpen () {
201207 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 ();
224210 }
225211
226212 @ Override
@@ -253,16 +239,14 @@ public void onMessage(String string) {
253239
254240 /* This allows us to detect a websocket ping, so we don't need Ably pings. */
255241 @ Override
256- public void onWebsocketPing (WebSocket conn , Framedata f ) {
242+ public void onWebsocketPing () {
257243 Log .d (TAG , "onWebsocketPing()" );
258- /* Call superclass to ensure the pong is sent. */
259- super .onWebsocketPing (conn , f );
260244 flagActivity ();
261245 }
262246
263247 @ 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 );
266250
267251 ErrorInfo reason ;
268252 switch (wsCode ) {
@@ -301,23 +285,14 @@ public void onClose(final int wsCode, final String wsReason, final boolean remot
301285 }
302286
303287 @ 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 ));
307291 }
308292
309293 @ 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 );
321296 }
322297
323298 private synchronized void dispose () {
@@ -391,7 +366,7 @@ private synchronized void onActivityTimerExpiry() {
391366 // If we have no time remaining, then close the connection
392367 if (timeRemaining <= 0 ) {
393368 Log .e (TAG , "No activity for " + getActivityTimeout () + "ms, closing connection" );
394- closeConnection ( CloseFrame . ABNORMAL_CLOSE , "timed out" );
369+ webSocketClient . cancel ( ABNORMAL_CLOSE , "timed out" );
395370 return ;
396371 }
397372
0 commit comments