Skip to content

Commit babfe30

Browse files
committed
Don't reuse web socket task after it's been closed
1 parent ed8dced commit babfe30

File tree

2 files changed

+123
-18
lines changed

2 files changed

+123
-18
lines changed

Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ public final class ParseLiveQuery: NSObject {
5353
let notificationQueue: DispatchQueue
5454

5555
//Task
56-
var task: URLSessionWebSocketTask!
56+
var task: URLSessionWebSocketTask! {
57+
willSet {
58+
if newValue == nil && isSocketEstablished == true {
59+
isSocketEstablished = false
60+
}
61+
}
62+
}
5763
var url: URL!
5864
var clientId: String!
5965
var attempts: Int = 1 {
@@ -205,14 +211,19 @@ public final class ParseLiveQuery: NSObject {
205211
close(useDedicatedQueue: false)
206212
authenticationDelegate = nil
207213
receiveDelegate = nil
208-
URLSession.liveQuery.delegates.removeValue(forKey: task)
214+
if task != nil {
215+
URLSession.liveQuery.delegates.removeValue(forKey: task)
216+
} else {
217+
task = nil
218+
}
209219
}
210220
}
211221

212222
// MARK: Helpers
213223
@available(macOS 10.15, iOS 13.0, macCatalyst 13.0, watchOS 6.0, tvOS 13.0, *)
214224
extension ParseLiveQuery {
215225

226+
/// Current LiveQuery client.
216227
public private(set) static var client = try? ParseLiveQuery()
217228

218229
var reconnectInterval: Int {
@@ -533,7 +544,10 @@ extension ParseLiveQuery {
533544
self.task.cancel()
534545
self.isDisconnectedByUser = true
535546
}
536-
URLSession.liveQuery.delegates.removeValue(forKey: self.task)
547+
if task != nil {
548+
URLSession.liveQuery.delegates.removeValue(forKey: self.task)
549+
}
550+
self.task = nil
537551
}
538552
}
539553

@@ -568,7 +582,9 @@ extension ParseLiveQuery {
568582
if self.isConnected {
569583
self.task.cancel()
570584
}
571-
URLSession.liveQuery.delegates.removeValue(forKey: self.task)
585+
if self.task != nil {
586+
URLSession.liveQuery.delegates.removeValue(forKey: self.task)
587+
}
572588
}
573589
}
574590

@@ -577,6 +593,8 @@ extension ParseLiveQuery {
577593
self.pendingSubscriptions.append((requestId, record))
578594
if self.isConnected {
579595
URLSession.liveQuery.send(record.messageData, task: self.task, completion: completion)
596+
} else {
597+
self.open(completion: completion)
580598
}
581599
}
582600
}

Tests/ParseSwiftTests/ParseLiveQueryTests.swift

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ParseLiveQueryTests: XCTestCase {
5050
masterKey: "masterKey",
5151
serverURL: url,
5252
testing: true)
53-
ParseLiveQuery.client = try? ParseLiveQuery(isDefault: true)
53+
ParseLiveQuery.setDefault(try ParseLiveQuery(isDefault: true))
5454
}
5555

5656
override func tearDownWithError() throws {
@@ -314,24 +314,28 @@ class ParseLiveQueryTests: XCTestCase {
314314
XCTFail("Should be able to get client")
315315
return
316316
}
317-
client.isSocketEstablished = true // Socket neets to be true
317+
client.isSocketEstablished = true // Socket needs to be true
318318
client.isConnecting = true
319319
client.attempts = 50
320320
client.isConnected = true
321321
client.clientId = "yolo"
322-
323-
XCTAssertEqual(client.isSocketEstablished, true)
324-
XCTAssertEqual(client.isConnecting, false)
325-
XCTAssertEqual(client.clientId, "yolo")
326-
XCTAssertEqual(client.attempts, 1)
322+
let expectation1 = XCTestExpectation(description: "Synch")
323+
client.synchronizationQueue.sync {
324+
XCTAssertEqual(client.isSocketEstablished, true)
325+
XCTAssertEqual(client.isConnecting, false)
326+
XCTAssertEqual(client.clientId, "yolo")
327+
XCTAssertEqual(client.attempts, 1)
328+
expectation1.fulfill()
329+
}
330+
wait(for: [expectation1], timeout: 20.0)
327331
}
328332

329333
func testDisconnectedState() throws {
330334
guard let client = ParseLiveQuery.getDefault() else {
331335
XCTFail("Should be able to get client")
332336
return
333337
}
334-
client.isSocketEstablished = true // Socket neets to be true
338+
client.isSocketEstablished = true // Socket needs to be true
335339
client.isConnecting = true
336340
client.isConnected = true
337341
client.clientId = "yolo"
@@ -352,7 +356,7 @@ class ParseLiveQueryTests: XCTestCase {
352356
XCTFail("Should be able to get client")
353357
return
354358
}
355-
client.isSocketEstablished = true // Socket neets to be true
359+
client.isSocketEstablished = true // Socket needs to be true
356360
client.isConnecting = true
357361
client.isConnected = true
358362
client.clientId = "yolo"
@@ -384,11 +388,13 @@ class ParseLiveQueryTests: XCTestCase {
384388
XCTAssertEqual(client.clientId, "yolo")
385389
client.close()
386390

387-
XCTAssertEqual(client.isSocketEstablished, true)
388-
XCTAssertEqual(client.isConnected, false)
389-
XCTAssertEqual(client.isConnecting, false)
390-
XCTAssertNil(client.clientId)
391-
XCTAssertEqual(client.isDisconnectedByUser, true)
391+
DispatchQueue.main.asyncAfter(deadline: .now()) {
392+
XCTAssertEqual(client.isSocketEstablished, true)
393+
XCTAssertEqual(client.isConnected, false)
394+
XCTAssertEqual(client.isConnecting, false)
395+
XCTAssertNil(client.clientId)
396+
XCTAssertEqual(client.isDisconnectedByUser, true)
397+
}
392398
}
393399

394400
func testReconnectInterval() throws {
@@ -584,6 +590,87 @@ class ParseLiveQueryTests: XCTestCase {
584590
wait(for: [expectation1, expectation2], timeout: 20.0)
585591
}
586592

593+
func testSubscribeCloseSubscribe() throws {
594+
let query = GameScore.query("score" > 9)
595+
let handler = SubscriptionCallback(query: query)
596+
var subscription = try Query<GameScore>.subscribe(handler)
597+
598+
guard let client = ParseLiveQuery.getDefault() else {
599+
XCTFail("Should be able to get client")
600+
return
601+
}
602+
XCTAssertEqual(subscription.query, query)
603+
604+
let expectation1 = XCTestExpectation(description: "Subscribe Handler")
605+
let expectation2 = XCTestExpectation(description: "Resubscribe Handler")
606+
var count = 0
607+
var originalTask: URLSessionWebSocketTask?
608+
subscription.handleSubscribe { subscribedQuery, isNew in
609+
XCTAssertEqual(query, subscribedQuery)
610+
if count == 0 {
611+
XCTAssertTrue(isNew)
612+
XCTAssertEqual(client.pendingSubscriptions.count, 0)
613+
XCTAssertEqual(client.subscriptions.count, 1)
614+
XCTAssertNotNil(ParseLiveQuery.client?.task)
615+
originalTask = ParseLiveQuery.client?.task
616+
expectation1.fulfill()
617+
} else if count == 2 {
618+
XCTAssertNotNil(ParseLiveQuery.client?.task)
619+
XCTAssertFalse(originalTask == ParseLiveQuery.client?.task)
620+
expectation2.fulfill()
621+
return
622+
}
623+
624+
ParseLiveQuery.client?.close()
625+
ParseLiveQuery.client?.synchronizationQueue.sync {
626+
XCTAssertNil(ParseLiveQuery.client?.task)
627+
if let socketEstablished = ParseLiveQuery.client?.isSocketEstablished {
628+
XCTAssertFalse(socketEstablished)
629+
} else {
630+
XCTFail("Should have socket that isn't established")
631+
}
632+
633+
//Resubscribe
634+
do {
635+
count += 1
636+
subscription = try Query<GameScore>.subscribe(handler)
637+
} catch {
638+
XCTFail("\(error)")
639+
}
640+
641+
try? self.pretendToBeConnected()
642+
643+
let response2 = PreliminaryMessageResponse(op: .subscribed,
644+
requestId: 2,
645+
clientId: "yolo",
646+
installationId: "naw")
647+
guard let encoded2 = try? ParseCoding.jsonEncoder().encode(response2) else {
648+
expectation2.fulfill()
649+
return
650+
}
651+
client.received(encoded2)
652+
}
653+
}
654+
655+
XCTAssertFalse(try client.isSubscribed(query))
656+
XCTAssertTrue(try client.isPendingSubscription(query))
657+
XCTAssertEqual(client.subscriptions.count, 0)
658+
XCTAssertEqual(client.pendingSubscriptions.count, 1)
659+
try pretendToBeConnected()
660+
let response = PreliminaryMessageResponse(op: .subscribed,
661+
requestId: 1,
662+
clientId: "yolo",
663+
installationId: "naw")
664+
let encoded = try ParseCoding.jsonEncoder().encode(response)
665+
client.received(encoded)
666+
XCTAssertTrue(try client.isSubscribed(query))
667+
XCTAssertFalse(try client.isPendingSubscription(query))
668+
XCTAssertEqual(client.subscriptions.count, 1)
669+
XCTAssertEqual(client.pendingSubscriptions.count, 0)
670+
671+
wait(for: [expectation1, expectation2], timeout: 20.0)
672+
}
673+
587674
func testServerRedirectResponse() throws {
588675
guard let client = ParseLiveQuery.getDefault() else {
589676
XCTFail("Should be able to get client")

0 commit comments

Comments
 (0)