Skip to content

Commit 1910c88

Browse files
Refactor RCTReconnectingWebSocket connection methods
1 parent b8ec87e commit 1910c88

1 file changed

Lines changed: 104 additions & 28 deletions

File tree

‎packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m‎

Lines changed: 104 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,27 @@
1515

1616
#if RCT_DEV // Only supported in dev mode
1717

18+
static const NSTimeInterval RCTReconnectInitialDelay = 2.0;
19+
static const NSTimeInterval RCTReconnectMaxDelay = 120.0;
20+
1821
@interface RCTReconnectingWebSocket () <SRWebSocketDelegate>
1922
@end
2023

2124
@implementation RCTReconnectingWebSocket {
2225
NSURL *_url;
2326
SRWebSocket *_socket;
2427
BOOL _stopped;
28+
BOOL _reconnectPending;
29+
NSTimeInterval _reconnectDelay;
30+
uint64_t _reconnectToken;
2531
}
2632

2733
- (instancetype)initWithURL:(NSURL *)url queue:(dispatch_queue_t)queue
2834
{
2935
if (self = [super init]) {
3036
_url = url;
3137
_delegateDispatchQueue = queue;
38+
_reconnectDelay = RCTReconnectInitialDelay;
3239
}
3340
return self;
3441
}
@@ -40,69 +47,138 @@ - (instancetype)initWithURL:(NSURL *)url
4047

4148
- (void)send:(id)data
4249
{
43-
[_socket sendData:data error:nil];
50+
SRWebSocket *socket;
51+
@synchronized (self) {
52+
socket = _socket;
53+
}
54+
[socket sendData:data error:nil];
4455
}
4556

46-
- (void)start
57+
- (void)connect
4758
{
48-
[self stop];
49-
_stopped = NO;
50-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url];
51-
[[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request];
52-
_socket = [[SRWebSocket alloc] initWithURLRequest:request];
53-
_socket.delegate = self;
54-
[_socket setDelegateDispatchQueue:_delegateDispatchQueue];
55-
[_socket open];
59+
SRWebSocket *socketToClose = nil;
60+
NSMutableURLRequest *request = nil;
61+
SRWebSocket *socket = nil;
62+
63+
@synchronized (self) {
64+
if (_stopped) {
65+
return;
66+
}
67+
_reconnectPending = NO;
68+
69+
socketToClose = _socket;
70+
_socket.delegate = nil;
71+
_socket = nil;
72+
73+
request = [NSMutableURLRequest requestWithURL:_url];
74+
[[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request];
75+
socket = [[SRWebSocket alloc] initWithURLRequest:request];
76+
socket.delegate = self;
77+
[socket setDelegateDispatchQueue:_delegateDispatchQueue];
78+
_socket = socket;
79+
}
80+
81+
[socketToClose closeWithCode:1000 reason:@"Invalidated"];
82+
[socket open];
5683
}
5784

58-
- (void)stop
85+
- (void)start
5986
{
60-
_stopped = YES;
61-
_socket.delegate = nil;
62-
[_socket closeWithCode:1000 reason:@"Invalidated"];
63-
_socket = nil;
87+
@synchronized (self) {
88+
_stopped = NO;
89+
_reconnectPending = NO;
90+
_reconnectToken++;
91+
_reconnectDelay = RCTReconnectInitialDelay;
92+
}
93+
[self connect];
6494
}
6595

66-
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
96+
- (void)stop
6797
{
68-
[_delegate reconnectingWebSocket:self didReceiveMessage:message];
98+
SRWebSocket *socketToClose = nil;
99+
@synchronized (self) {
100+
_stopped = YES;
101+
_reconnectPending = NO;
102+
_reconnectToken++;
103+
_reconnectDelay = RCTReconnectInitialDelay;
104+
socketToClose = _socket;
105+
_socket.delegate = nil;
106+
_socket = nil;
107+
}
108+
[socketToClose closeWithCode:1000 reason:@"Invalidated"];
69109
}
70110

71111
- (void)reconnect
72112
{
73-
if (_stopped) {
74-
return;
113+
NSTimeInterval delay;
114+
uint64_t token;
115+
@synchronized (self) {
116+
if (_stopped || _reconnectPending) {
117+
return;
118+
}
119+
_reconnectPending = YES;
120+
token = ++_reconnectToken;
121+
delay = _reconnectDelay;
122+
_reconnectDelay = MIN(_reconnectDelay * 2, RCTReconnectMaxDelay);
75123
}
76124

77-
__weak SRWebSocket *socket = _socket;
78125
__weak __typeof(self) weakSelf = self;
79-
80-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
81-
[weakSelf start];
82-
if (!socket) {
83-
[weakSelf reconnect];
126+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
127+
__typeof(self) strongSelf = weakSelf;
128+
if (!strongSelf) {
129+
return;
84130
}
131+
@synchronized (strongSelf) {
132+
if (strongSelf->_stopped || strongSelf->_reconnectToken != token) {
133+
return;
134+
}
135+
}
136+
[strongSelf connect];
85137
});
86138
}
87139

88140
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
89141
{
142+
@synchronized (self) {
143+
if (webSocket != _socket) {
144+
return;
145+
}
146+
_reconnectDelay = RCTReconnectInitialDelay;
147+
}
90148
[_delegate reconnectingWebSocketDidOpen:self];
91149
}
92150

151+
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
152+
{
153+
@synchronized (self) {
154+
if (webSocket != _socket) {
155+
return;
156+
}
157+
}
158+
[_delegate reconnectingWebSocket:self didReceiveMessage:message];
159+
}
160+
93161
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error
94162
{
95-
[_delegate reconnectingWebSocketDidClose:self];
96-
if ([error code] != ECONNREFUSED) {
97-
[self reconnect];
163+
@synchronized (self) {
164+
if (webSocket != _socket) {
165+
return;
166+
}
98167
}
168+
[_delegate reconnectingWebSocketDidClose:self];
169+
[self reconnect];
99170
}
100171

101172
- (void)webSocket:(SRWebSocket *)webSocket
102173
didCloseWithCode:(NSInteger)code
103174
reason:(NSString *)reason
104175
wasClean:(BOOL)wasClean
105176
{
177+
@synchronized (self) {
178+
if (webSocket != _socket) {
179+
return;
180+
}
181+
}
106182
[_delegate reconnectingWebSocketDidClose:self];
107183
[self reconnect];
108184
}

0 commit comments

Comments
 (0)