From a754a479f0bbcdaeba27124e8e3602ed8aacf0e0 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 23 Jul 2021 13:48:19 -0300 Subject: [PATCH 1/3] fix: updates on native EventSource implementations --- .../http/HttpRequestTransportHandler.java | 36 ++--- .../http/HttpRequestDelegateImpl.java | 10 +- .../transport/ws/WebSocketDelegateImpl.java | 141 +++++++++--------- example/src/App.tsx | 5 +- .../TRVSEventSource/TRVSEventSource.m | 20 ++- package.json | 4 +- src/platform/RNSignalListener.ts | 6 +- 7 files changed, 121 insertions(+), 101 deletions(-) diff --git a/android/src/main/java/org/kaazing/gateway/client/impl/http/HttpRequestTransportHandler.java b/android/src/main/java/org/kaazing/gateway/client/impl/http/HttpRequestTransportHandler.java index 36da8f0..473432c 100755 --- a/android/src/main/java/org/kaazing/gateway/client/impl/http/HttpRequestTransportHandler.java +++ b/android/src/main/java/org/kaazing/gateway/client/impl/http/HttpRequestTransportHandler.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2007-2014 Kaazing Corporation. All rights reserved. - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,9 +8,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,17 +34,17 @@ public class HttpRequestTransportHandler extends HttpRequestHandlerAdapter { private static final Logger LOG = Logger.getLogger(CLASS_NAME); public static HttpRequestHandlerFactory DEFAULT_FACTORY = new HttpRequestHandlerFactory() { - + @Override public HttpRequestHandler createHandler() { HttpRequestHandler requestHandler = new HttpRequestTransportHandler(); - + if (LOG.isLoggable(Level.FINE)) { HttpRequestLoggingHandler loggingHandler = new HttpRequestLoggingHandler(); loggingHandler.setNextHandler(requestHandler); requestHandler = loggingHandler; } - + return requestHandler; } }; @@ -52,49 +52,49 @@ public HttpRequestHandler createHandler() { @Override public void processOpen(HttpRequest request) { LOG.entering(CLASS_NAME, "processOpen: "+request); - + HttpRequestHandler transportHandler; if (WebSocketTransportHandler.useBridge(request.getUri().getURI())) { transportHandler = new HttpRequestBridgeHandler(); } - else { + else { // Used by Android transportHandler = new HttpRequestDelegateHandler(); } - + request.transportHandler = transportHandler; transportHandler.setListener(new HttpRequestListener() { - + @Override public void requestReady(HttpRequest request) { listener.requestReady(request); } - + @Override public void requestProgressed(HttpRequest request, WrappedByteBuffer payload) { listener.requestProgressed(request, payload); } - + @Override public void requestOpened(HttpRequest request) { listener.requestOpened(request); } - + @Override public void requestLoaded(HttpRequest request, HttpResponse response) { listener.requestLoaded(request, response); } - + @Override public void requestClosed(HttpRequest request) { listener.requestClosed(request); } - + @Override public void requestAborted(HttpRequest request) { listener.requestAborted(request); } - + @Override public void errorOccurred(HttpRequest request, Exception exception) { listener.errorOccurred(request, exception); @@ -107,7 +107,7 @@ public void errorOccurred(HttpRequest request, Exception exception) { @Override public void processSend(HttpRequest request, WrappedByteBuffer buffer) { LOG.entering(CLASS_NAME, "processSend: "+request); - + HttpRequestHandler transportHandler = request.transportHandler; transportHandler.processSend(request, buffer); } @@ -115,7 +115,7 @@ public void processSend(HttpRequest request, WrappedByteBuffer buffer) { @Override public void processAbort(HttpRequest request) { LOG.entering(CLASS_NAME, "processAbort: "+request); - + HttpRequestHandler transportHandler = request.transportHandler; transportHandler.processAbort(request); } diff --git a/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java b/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java index ce31cc4..67008b3 100755 --- a/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java +++ b/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java @@ -42,6 +42,10 @@ import org.kaazing.gateway.client.transport.ReadyStateChangedEvent; public class HttpRequestDelegateImpl implements HttpRequestDelegate { + + private final static long SSE_CONNECT_TIMEOUT_MILLIS = 30000; + private final static long SSE_SOCKET_TIMEOUT_MILLIS = 70000; + private static final String CLASS_NAME = HttpRequestDelegateImpl.class.getName(); private static final Logger LOG = Logger.getLogger(CLASS_NAME); @@ -143,7 +147,11 @@ public void processOpen(String method, URL url, String origin, boolean async, lo connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod(method); connection.setInstanceFollowRedirects(false); - connection.setConnectTimeout((int) connectTimeout); + + // Don't use `connectTimeout` param, which is 0 by default + connection.setConnectTimeout((int) SSE_CONNECT_TIMEOUT_MILLIS); + // Ably keepalive comments (or heartbeat events if heartbeats=true) are sent every 60 secs aprox. + connection.setReadTimeout((int) SSE_SOCKET_TIMEOUT_MILLIS); if (!origin.equalsIgnoreCase("null") && !origin.startsWith("privileged")) { URL originUrl = new URL(origin); diff --git a/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java b/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java index 31b18bc..38e30d1 100755 --- a/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java +++ b/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2007-2014 Kaazing Corporation. All rights reserved. - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,9 +8,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -75,7 +75,10 @@ public class WebSocketDelegateImpl implements WebSocketDelegate { private static final String WEBSOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; public static final int CLOSE_NO_STATUS = 1005; public static final int CLOSE_ABNORMAL = 1006; - + + private final static long SSE_CONNECT_TIMEOUT_MILLIS = 30000; + private final static int SSE_SOCKET_TIMEOUT_MILLIS = 70000; + static enum ConnectionStatus { START, STATUS_101_READ, CONNECTION_UPGRADE_READ, COMPLETED, ERRORED } @@ -83,7 +86,7 @@ static enum ConnectionStatus { public static enum ReadyState { CONNECTING, OPEN, CLOSING, CLOSED; } - + private static final byte[] HTTP_1_1_BYTES = "HTTP/1.1".getBytes(); private static final byte[] COLON_BYTES = ":".getBytes(); private static final byte[] SPACE_BYTES = " ".getBytes(); @@ -102,7 +105,7 @@ public static enum ReadyState { private static final String WEB_SOCKET_LOWERCASE = "websocket"; private static final String HEADER_COOKIE = "Cookie"; private static final Charset UTF8 = Charset.forName("UTF-8"); - + private BridgeSocket socket; private boolean stopReaderThread; private boolean connectionUpgraded = false; @@ -116,30 +119,30 @@ public static enum ReadyState { private String authorize = null; private AtomicBoolean closed = new AtomicBoolean(false); String websocketKey; - + private final long connectTimeout; //--------Idle Timeout-------------// private final AtomicInteger idleTimeout = new AtomicInteger(); private final AtomicLong lastMessageTimestamp = new AtomicLong(); private Timer idleTimer = null; - + //WebSocket rfc6455 properties - private ReadyState readyState = ReadyState.CONNECTING; + private ReadyState readyState = ReadyState.CONNECTING; public ReadyState getReadyState(){ return readyState; } - + int bufferedAmount; public int getBufferedAmount() { return bufferedAmount; } - + private String secProtocol; public String getSecProtocol() { return secProtocol; } - + private String extensions; public String getExtensions() { return extensions; @@ -148,7 +151,7 @@ public String getExtensions() { private boolean wasClean = false; private int code = CLOSE_ABNORMAL; private String reason = ""; - + HttpRequestDelegateFactory HTTP_REQUEST_DELEGATE_FACTORY = new HttpRequestDelegateFactory() { @Override public HttpRequestDelegate createHttpRequestDelegate() { @@ -165,7 +168,7 @@ public BridgeSocket createSocket(boolean secure) throws IOException { /** * WebSocket Java API for use in Java Web Start applications - * + * * @param url * WebSocket URL location * @param origin @@ -203,27 +206,27 @@ public WebSocketDelegateImpl(URI url, URI origin, String[] protocols, long conne this.connectTimeout = connectTimeout; } - + //------------------------------Idle Timer Start/Stop/Handler---------------------// - + private void startIdleTimer(long delayInMilliseconds) { LOG.fine("Starting idle timer"); if (this.idleTimer != null) { idleTimer.cancel(); idleTimer = null; } - + idleTimer = new Timer("IdleTimer", true); idleTimer.schedule(new TimerTask() { - + @Override public void run() { idleTimerHandler(); } - + }, delayInMilliseconds); } - + private void idleTimerHandler() { LOG.fine("Idle timer scheduled"); long idleDuration = System.currentTimeMillis() - lastMessageTimestamp.get(); @@ -237,7 +240,7 @@ private void idleTimerHandler() { startIdleTimer(idleTimeout.get() - idleDuration); } } - + private void stopIdleTimer() { LOG.fine("Stopping idle timer"); if (idleTimer != null) { @@ -245,7 +248,7 @@ private void stopIdleTimer() { idleTimer = null; } } - + @Override public void setIdleTimeout(int milliSecond) { idleTimeout.set(milliSecond); @@ -258,7 +261,7 @@ public void setIdleTimeout(int milliSecond) { stopIdleTimer(); } } - + //-------------------------------------------------------------------------------// public void processOpen() { @@ -283,19 +286,19 @@ public void processOpen() { final HttpRequestDelegate cookiesRequest = HTTP_REQUEST_DELEGATE_FACTORY.createHttpRequestDelegate(); cookiesRequest.setListener(new HttpRequestDelegateListener() { - + @Override public void opened(OpenEvent event) { } - + @Override public void readyStateChanged(ReadyStateChangedEvent event) { } - + @Override public void progressed(ProgressEvent progressEvent) { } - + @Override public void loaded(LoadEvent event) { switch (cookiesRequest.getStatusCode()) { @@ -323,7 +326,7 @@ public void loaded(LoadEvent event) { case 307: String location = cookiesRequest.getResponseHeader(HEADER_LOCATION); LOG.finest("Redirect to " + location); - + URI uri; try { uri = new URI(location); @@ -379,11 +382,11 @@ else if (!wwwAuthenticate.startsWith(APPLICATION_PREFIX)) { throw new IllegalStateException("Unsupported wrapped response with HTTP status code " + statusCode); } } - + @Override public void closed(CloseEvent event) { } - + @Override public void errorOccurred(ErrorEvent event) { WebSocketDelegateImpl.this.readyState = ReadyState.CLOSED; @@ -472,9 +475,11 @@ protected void nativeConnect() { try { LOG.fine("WebSocketDelegate.nativeConnect(): Connecting to "+host+":"+port); socket = BRIDGE_SOCKET_FACTORY.createSocket(secure); - socket.connect(new InetSocketAddress(host, port), connectTimeout); + + // Not used in Android, but just in case we update the connect and socket timeouts, which are 0 by default. + socket.connect(new InetSocketAddress(host, port), SSE_CONNECT_TIMEOUT_MILLIS /* connectTimeout */); socket.setKeepAlive(true); - socket.setSoTimeout(0); // continuously read from the socket + socket.setSoTimeout(SSE_SOCKET_TIMEOUT_MILLIS); } catch (Exception e) { LOG.log(Level.FINE, "WebSocketDelegateImpl nativeConnect(): "+e.getMessage(), e); @@ -512,7 +517,7 @@ private void negotiateWebSocketConnection(BridgeSocket socket) { if (requestedProtocols != null && requestedProtocols.length > 0) { headerNames[headerIndex] = HEADER_PROTOCOL; - + String value; if (requestedProtocols.length == 1) { value = requestedProtocols[0]; @@ -526,7 +531,7 @@ private void negotiateWebSocketConnection(BridgeSocket socket) { value += requestedProtocols[i]; } } - + headerValues[headerIndex++] = value; } @@ -561,10 +566,10 @@ private void negotiateWebSocketConnection(BridgeSocket socket) { } public byte[] encodeGetRequest(URI requestURI, String[] names, String[] values) { - + // Any changes to this method should result in the getEncodeRequestSize method below // to get accurate length of the buffer that needs to be allocated. - + LOG.entering(CLASS_NAME, "encodeGetRequest", new Object[] {requestURI, names, values}); int requestSize = getEncodeRequestSize(requestURI, names, values); ByteBuffer buf = ByteBuffer.allocate(requestSize); @@ -639,7 +644,7 @@ private int getEncodeRequestSize(URI requestURI, String[] names, String[] values public void processDisconnect() throws IOException { processDisconnect((short) 0, null); } - + public void processDisconnect(short code, String reason) throws IOException { LOG.entering(CLASS_NAME, "disconnect"); //stopReaderThread = true; --- rfc 6455 donot stop SockectReader, wait for CloseFrame @@ -667,13 +672,13 @@ public void processDisconnect(short code, String reason) throws IOException { } data = ByteBuffer.allocate(2 + (reasonBuf == null ? 0 : reasonBuf.remaining())); data.putShort(code); - + if (reasonBuf != null) { - data.put(reasonBuf); + data.put(reasonBuf); } - + data.flip(); - } + } this.send(WsFrameEncodingSupport.rfc6455Encode(new WsMessage(data, Kind.CLOSE), new Random().nextInt())); } else if (readyState == ReadyState.CONNECTING) { @@ -681,21 +686,21 @@ else if (readyState == ReadyState.CONNECTING) { stopReaderThread = true; handleClose(null); } - - // Do not close the underlying socket connection immediately. As per the RFC spec - - // After both sending and receiving a Close message, an endpoint considers the WebSocket + + // Do not close the underlying socket connection immediately. As per the RFC spec - + // After both sending and receiving a Close message, an endpoint considers the WebSocket // connection closed and MUST close the underlying TCP connection. - // Schedule a timer to close the underlying Socket connection if the CLOSE frame is not + // Schedule a timer to close the underlying Socket connection if the CLOSE frame is not // received from the Gateway within 5 seconds. Timer t = new Timer("SocketCloseTimer", true); t.schedule(new TimerTask() { - + @Override public void run() { try { if (WebSocketDelegateImpl.this.readyState != ReadyState.CLOSED) { stopIdleTimer(); - closeSocket(); + closeSocket(); } } finally { @@ -703,7 +708,7 @@ public void run() { } } }, 5000); - + //else do nothing for CLOSING and CLOSED } @@ -722,14 +727,14 @@ public void processSend(ByteBuffer data) { send(frame); // send(data); } - + @Override public void processSend(String data) { LOG.entering(CLASS_NAME, "processSend", data); ByteBuffer buf = null; try { buf = ByteBuffer.wrap(data.getBytes("UTF-8")); - } + } catch (UnsupportedEncodingException e) { // this should not be reached String s = "The platform should have already been checked to see if UTF-8 encoding is supported"; @@ -740,7 +745,7 @@ public void processSend(String data) { send(frame); // send(data); } - + private void send(ByteBuffer frame) { LOG.entering(CLASS_NAME, "send", frame); if (socket == null) { @@ -770,21 +775,21 @@ protected URI getOrigin() { LOG.exiting(CLASS_NAME, "getOrigin", originUri); return originUri; } - + private void closeSocket() { try { LOG.log(Level.FINE, "Closing socket"); - + // Sleep for a tenth-of-second before closing the socket. Thread.sleep(100); - + if ((socket != null) && (readyState != ReadyState.CLOSED)) { socket.close(); } } catch (IOException e) { LOG.log(Level.FINE, "While closing socket: "+e.getMessage(), e); - } + } catch (InterruptedException e) { LOG.log(Level.FINE, "While closing socket: "+e.getMessage(), e); } @@ -793,7 +798,7 @@ private void closeSocket() { socket = null; } } - + private void handleClose(Exception ex) { if (closed.compareAndSet(false, true)) { try { @@ -821,14 +826,14 @@ private void handleError(Exception ex) { } } } - + private byte[] randomBytes(int size) { byte[] bytes = new byte[size]; Random r = new Random(); r.nextBytes(bytes); return bytes; } - + private String base64Encode(byte[] bytes) { return Base64Util.encode(ByteBuffer.wrap(bytes)); @@ -904,7 +909,7 @@ public void run() { break; } } //end of while loop - + if (!connectionUpgraded && !stopReaderThread) { throw new IllegalArgumentException("WebSocket Connection upgrade unsuccessful"); } @@ -924,7 +929,7 @@ else if (messageType == "PING") { //PING received, send PONG ByteBuffer frame = WsFrameEncodingSupport.rfc6455Encode(new WsMessage(buffer, Kind.PONG), new Random().nextInt()); WebSocketDelegateImpl.this.send(frame); - + } else if (messageType == "CLOSE") { WebSocketDelegateImpl.this.wasClean = true; @@ -933,7 +938,7 @@ else if (messageType == "CLOSE") { } else { WebSocketDelegateImpl.this.code = buffer.getShort(); - + if (buffer.hasRemaining()) { WebSocketDelegateImpl.this.reason = UTF8.decode(buffer).toString(); } @@ -949,7 +954,7 @@ else if (messageType == "CLOSE") { if (WebSocketDelegateImpl.this.readyState == ReadyState.CONNECTING) { WebSocketDelegateImpl.this.readyState = ReadyState.CLOSING; } - + } else { //unknown type @@ -966,7 +971,7 @@ else if (messageType == "CLOSE") { LOG.fine("SocketReader: Stopping reader thread; closing socket"); break; } - + if (!frameProcessor.process(inputStream)) { LOG.fine("SocketReader: end of stream"); break; @@ -1011,7 +1016,7 @@ private String readLine(InputStream reader) throws Exception { private void processLine(String line) throws Exception { LOG.entering(CLASS_NAME, "processLine", line); - + switch (state) { case START: if (line.equals(HTTP_101_MESSAGE)) { @@ -1044,18 +1049,18 @@ else if (line.indexOf(WEBSOCKET_ACCEPT) == 0) { break; } } - + /** * Compute the Sec-WebSocket-Accept key (RFC-6455) - * + * * @param key * @return - * @throws NoSuchAlgorithmException + * @throws NoSuchAlgorithmException * @throws Exception */ public String AcceptHash(String key) throws NoSuchAlgorithmException { String input = key + WEBSOCKET_GUID; - + MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); byte[] hash = sha1.digest(input.getBytes());; diff --git a/example/src/App.tsx b/example/src/App.tsx index 74722e4..f6e7d2e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -35,7 +35,7 @@ import { SplitFactory, DebugLogger } from 'splitio-react-native-private'; // Ignore Android JS timers warning. No need to worry about it: https://github.com/facebook/react-native/issues/12981#issuecomment-652745831 LogBox.ignoreLogs(['Setting a timer']); -const config = { +const config: SplitIO.IReactNativeSettings = { core: { authorizationKey: 'CLINT-SIDE-API-KEY', key: 'main_user_key', @@ -44,7 +44,8 @@ const config = { featuresRefreshRate: 30000, segmentsRefreshRate: 30000, impressionsRefreshRate: 30000, - eventsPushRate: 30000 + eventsPushRate: 30000, + eventsQueueSize: 2 }, debug: DebugLogger(), streamingEnabled: true, diff --git a/ios/RNEventSource/TRVSEventSource/TRVSEventSource.m b/ios/RNEventSource/TRVSEventSource/TRVSEventSource.m index 6f0a056..41c61a6 100755 --- a/ios/RNEventSource/TRVSEventSource/TRVSEventSource.m +++ b/ios/RNEventSource/TRVSEventSource/TRVSEventSource.m @@ -72,9 +72,13 @@ @implementation TRVSEventSource #pragma mark - Public - (instancetype)initWithURL:(NSURL *)URL { + NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + + // Ably keepalive comments (or heartbeat events if heartbeats=true) are sent every 60 secs aprox. + sessionConfig.timeoutIntervalForRequest = 70.0; // 70 secs + return [self initWithURL:URL - sessionConfiguration:NSURLSessionConfiguration - .defaultSessionConfiguration]; + sessionConfiguration:sessionConfig]; } - (instancetype)initWithURL:(NSURL *)URL @@ -175,31 +179,31 @@ - (void)URLSession:(NSURLSession *)session [self.buffer appendString:string]; NSRange range = [self.buffer rangeOfString:@"\n\n"]; - + NSError *error; TRVSServerSentEvent *event; while (range.location != NSNotFound) @autoreleasepool { error = nil; event = [TRVSServerSentEvent eventWithFields:TRVSServerSentEventFieldsFromString([self.buffer substringToIndex:range.location], &error)]; [self.buffer deleteCharactersInRange:NSMakeRange(0, range.location + 2)]; - + if (error) [self transitionToFailedWithError:error]; - + if (error || !event) return; - + [[self.listenersKeyedByEvent objectForKey:event.event] enumerateKeysAndObjectsUsingBlock: ^(id _, TRVSEventSourceEventHandler eventHandler, BOOL *stop) { eventHandler(event, nil); }]; - + if ([self.delegate respondsToSelector:@selector(eventSource:didReceiveEvent:)]) { [self.delegate eventSource:self didReceiveEvent:event]; } - + range = [self.buffer rangeOfString:@"\n\n"]; } } diff --git a/package.json b/package.json index 3f7a41e..fb88b3b 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,9 @@ }, "jest": { "preset": "react-native", - "testMatch": ["/src/**/__tests__/**/?(*.)+(spec|test).[jt]s"], + "testMatch": [ + "/src/**/__tests__/**/?(*.)+(spec|test).[jt]s" + ], "modulePathIgnorePatterns": [ "/lib/" ], diff --git a/src/platform/RNSignalListener.ts b/src/platform/RNSignalListener.ts index 9eadf05..e75b4c8 100644 --- a/src/platform/RNSignalListener.ts +++ b/src/platform/RNSignalListener.ts @@ -42,7 +42,7 @@ export class RNSignalListener implements ISignalListener { switch (action) { case TO_FOREGROUND: - this.settings.log.debug(`App transition to foreground${this.syncManager.pushManager ? ': attempting to resume streaming' : ''}`); + this.settings.log.debug(`App transition to foreground${this.syncManager.pushManager ? '. Attempting to resume streaming' : ''}`); // This branch is called when app transition to foreground or it is launched, // in which case calling pushManager.start has no effect (it has been already started). @@ -52,8 +52,8 @@ export class RNSignalListener implements ISignalListener { break; case TO_BACKGROUND: this.settings.log.debug( - `App transition to background${this.syncManager.pushManager ? ': pausing streaming' : ''}${ - this.settings.flushDataOnBackground ? ': flushing events and impressions' : '' + `App transition to background${this.syncManager.pushManager ? '. Pausing streaming' : ''}${ + this.settings.flushDataOnBackground ? '. Flushing events and impressions' : '' }` ); From 6be64e26e848b7572d561c6785341cef4ac06dee Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 26 Jul 2021 13:47:20 -0300 Subject: [PATCH 2/3] refactor: long to int constants --- .../client/transport/http/HttpRequestDelegateImpl.java | 8 ++++---- .../client/transport/ws/WebSocketDelegateImpl.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java b/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java index 67008b3..1c53405 100755 --- a/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java +++ b/android/src/main/java/org/kaazing/gateway/client/transport/http/HttpRequestDelegateImpl.java @@ -43,8 +43,8 @@ public class HttpRequestDelegateImpl implements HttpRequestDelegate { - private final static long SSE_CONNECT_TIMEOUT_MILLIS = 30000; - private final static long SSE_SOCKET_TIMEOUT_MILLIS = 70000; + private final static int SSE_CONNECT_TIMEOUT_MILLIS = 30000; + private final static int SSE_SOCKET_TIMEOUT_MILLIS = 70000; private static final String CLASS_NAME = HttpRequestDelegateImpl.class.getName(); private static final Logger LOG = Logger.getLogger(CLASS_NAME); @@ -149,9 +149,9 @@ public void processOpen(String method, URL url, String origin, boolean async, lo connection.setInstanceFollowRedirects(false); // Don't use `connectTimeout` param, which is 0 by default - connection.setConnectTimeout((int) SSE_CONNECT_TIMEOUT_MILLIS); + connection.setConnectTimeout(SSE_CONNECT_TIMEOUT_MILLIS); // Ably keepalive comments (or heartbeat events if heartbeats=true) are sent every 60 secs aprox. - connection.setReadTimeout((int) SSE_SOCKET_TIMEOUT_MILLIS); + connection.setReadTimeout(SSE_SOCKET_TIMEOUT_MILLIS); if (!origin.equalsIgnoreCase("null") && !origin.startsWith("privileged")) { URL originUrl = new URL(origin); diff --git a/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java b/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java index 38e30d1..a3df9e9 100755 --- a/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java +++ b/android/src/main/java/org/kaazing/gateway/client/transport/ws/WebSocketDelegateImpl.java @@ -76,7 +76,7 @@ public class WebSocketDelegateImpl implements WebSocketDelegate { public static final int CLOSE_NO_STATUS = 1005; public static final int CLOSE_ABNORMAL = 1006; - private final static long SSE_CONNECT_TIMEOUT_MILLIS = 30000; + private final static int SSE_CONNECT_TIMEOUT_MILLIS = 30000; private final static int SSE_SOCKET_TIMEOUT_MILLIS = 70000; static enum ConnectionStatus { From dac330eb4119c2dcf8fdff784f23a6a1d1e540be Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 27 Jul 2021 17:25:02 -0300 Subject: [PATCH 3/3] fix --- package-lock.json | 6 +++--- package.json | 2 +- src/platform/EventSource/EventSource.ts | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d68eb42..bbbcde8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2453,9 +2453,9 @@ } }, "@splitsoftware/splitio-commons": { - "version": "0.1.1-canary.11", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-0.1.1-canary.11.tgz", - "integrity": "sha512-zbTmbEfpMiG8FynCLg8nVoDToXTDSVNGIpE7SIyw3gsKg2gJlzGAHkr419pV4c0uXTq+N6BvfwrdKxlmsSUgFg==", + "version": "0.1.1-canary.12", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-0.1.1-canary.12.tgz", + "integrity": "sha512-BvrRilTTMzF2kDzq3u9JrnzgQaSoVDKp6es8NCiIHgR3rBbP/tetfZPzuKRqDNpncI28JgCBJZOGs/GSRuVobQ==", "requires": { "object-assign": "^4.1.1", "tslib": "^2.1.0" diff --git a/package.json b/package.json index fb88b3b..df796ac 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "registry": "https://splitio.jfrog.io/artifactory/api/npm/npm-split/" }, "dependencies": { - "@splitsoftware/splitio-commons": "0.1.1-canary.11" + "@splitsoftware/splitio-commons": "0.1.1-canary.12" }, "devDependencies": { "@react-native-community/eslint-config": "^2.0.0", diff --git a/src/platform/EventSource/EventSource.ts b/src/platform/EventSource/EventSource.ts index 0ba13c5..55a6738 100644 --- a/src/platform/EventSource/EventSource.ts +++ b/src/platform/EventSource/EventSource.ts @@ -85,7 +85,9 @@ class EventSource extends EventSourceBase { this.dispatchEvent(event); }), DeviceEventEmitter.addListener('eventsourceFailed', (ev) => { - if (ev.id !== id) { + // Don't handle error event if it corresponds to another connection instance or the instance has been closed. + // Last condition is necessary for Android implementation of EventSource, which emits an error when closing the connection explicitly. + if (ev.id !== id || this.readyState === this.CLOSED) { return; } var event = new EventSourceEvent('error');