From 1910c8806cd5d394e17bbdacde78ad8163947297 Mon Sep 17 00:00:00 2001 From: samirakash248-max Date: Wed, 14 Oct 2026 13:04:02 +0530 Subject: [PATCH] Refactor RCTReconnectingWebSocket connection methods --- .../WebSocket/RCTReconnectingWebSocket.m | 132 ++++++++++++++---- 1 file changed, 104 insertions(+), 28 deletions(-) diff --git a/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m b/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m index ce64e0af0aca..5d7f6df78577 100644 --- a/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m +++ b/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m @@ -15,6 +15,9 @@ #if RCT_DEV // Only supported in dev mode +static const NSTimeInterval RCTReconnectInitialDelay = 2.0; +static const NSTimeInterval RCTReconnectMaxDelay = 120.0; + @interface RCTReconnectingWebSocket () @end @@ -22,6 +25,9 @@ @implementation RCTReconnectingWebSocket { NSURL *_url; SRWebSocket *_socket; BOOL _stopped; + BOOL _reconnectPending; + NSTimeInterval _reconnectDelay; + uint64_t _reconnectToken; } - (instancetype)initWithURL:(NSURL *)url queue:(dispatch_queue_t)queue @@ -29,6 +35,7 @@ - (instancetype)initWithURL:(NSURL *)url queue:(dispatch_queue_t)queue if (self = [super init]) { _url = url; _delegateDispatchQueue = queue; + _reconnectDelay = RCTReconnectInitialDelay; } return self; } @@ -40,62 +47,126 @@ - (instancetype)initWithURL:(NSURL *)url - (void)send:(id)data { - [_socket sendData:data error:nil]; + SRWebSocket *socket; + @synchronized (self) { + socket = _socket; + } + [socket sendData:data error:nil]; } -- (void)start +- (void)connect { - [self stop]; - _stopped = NO; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; - [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; - _socket = [[SRWebSocket alloc] initWithURLRequest:request]; - _socket.delegate = self; - [_socket setDelegateDispatchQueue:_delegateDispatchQueue]; - [_socket open]; + SRWebSocket *socketToClose = nil; + NSMutableURLRequest *request = nil; + SRWebSocket *socket = nil; + + @synchronized (self) { + if (_stopped) { + return; + } + _reconnectPending = NO; + + socketToClose = _socket; + _socket.delegate = nil; + _socket = nil; + + request = [NSMutableURLRequest requestWithURL:_url]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; + socket = [[SRWebSocket alloc] initWithURLRequest:request]; + socket.delegate = self; + [socket setDelegateDispatchQueue:_delegateDispatchQueue]; + _socket = socket; + } + + [socketToClose closeWithCode:1000 reason:@"Invalidated"]; + [socket open]; } -- (void)stop +- (void)start { - _stopped = YES; - _socket.delegate = nil; - [_socket closeWithCode:1000 reason:@"Invalidated"]; - _socket = nil; + @synchronized (self) { + _stopped = NO; + _reconnectPending = NO; + _reconnectToken++; + _reconnectDelay = RCTReconnectInitialDelay; + } + [self connect]; } -- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message +- (void)stop { - [_delegate reconnectingWebSocket:self didReceiveMessage:message]; + SRWebSocket *socketToClose = nil; + @synchronized (self) { + _stopped = YES; + _reconnectPending = NO; + _reconnectToken++; + _reconnectDelay = RCTReconnectInitialDelay; + socketToClose = _socket; + _socket.delegate = nil; + _socket = nil; + } + [socketToClose closeWithCode:1000 reason:@"Invalidated"]; } - (void)reconnect { - if (_stopped) { - return; + NSTimeInterval delay; + uint64_t token; + @synchronized (self) { + if (_stopped || _reconnectPending) { + return; + } + _reconnectPending = YES; + token = ++_reconnectToken; + delay = _reconnectDelay; + _reconnectDelay = MIN(_reconnectDelay * 2, RCTReconnectMaxDelay); } - __weak SRWebSocket *socket = _socket; __weak __typeof(self) weakSelf = self; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [weakSelf start]; - if (!socket) { - [weakSelf reconnect]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; } + @synchronized (strongSelf) { + if (strongSelf->_stopped || strongSelf->_reconnectToken != token) { + return; + } + } + [strongSelf connect]; }); } - (void)webSocketDidOpen:(SRWebSocket *)webSocket { + @synchronized (self) { + if (webSocket != _socket) { + return; + } + _reconnectDelay = RCTReconnectInitialDelay; + } [_delegate reconnectingWebSocketDidOpen:self]; } +- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message +{ + @synchronized (self) { + if (webSocket != _socket) { + return; + } + } + [_delegate reconnectingWebSocket:self didReceiveMessage:message]; +} + - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error { - [_delegate reconnectingWebSocketDidClose:self]; - if ([error code] != ECONNREFUSED) { - [self reconnect]; + @synchronized (self) { + if (webSocket != _socket) { + return; + } } + [_delegate reconnectingWebSocketDidClose:self]; + [self reconnect]; } - (void)webSocket:(SRWebSocket *)webSocket @@ -103,6 +174,11 @@ - (void)webSocket:(SRWebSocket *)webSocket reason:(NSString *)reason wasClean:(BOOL)wasClean { + @synchronized (self) { + if (webSocket != _socket) { + return; + } + } [_delegate reconnectingWebSocketDidClose:self]; [self reconnect]; }