Skip to content

Commit 2c61afb

Browse files
ncooke3paulb777
authored andcommitted
[Config] Follow-up to 'RCNRealtime' port (#14303)
1 parent ad91636 commit 2c61afb

File tree

1 file changed

+36
-26
lines changed

1 file changed

+36
-26
lines changed

FirebaseRemoteConfig/SwiftNew/ConfigRealtime.swift

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
417417
}
418418
if status == .success {
419419
if Int(self.configFetch.templateVersionNumber) ?? 0 >= targetVersion {
420+
// Only notify listeners if there is a change.
420421
if let update = update, !update.updatedKeys.isEmpty {
421422
self.realtimeLockQueue.async { [weak self] in
422423
guard let self else { return }
@@ -443,15 +444,19 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
443444

444445
@objc(scheduleFetch:targetVersion:) public
445446
func scheduleFetch(remainingAttempts: Int, targetVersion: Int) {
447+
// Needs fetch to occur between 0 - 3 seconds. Randomize to not cause DDoS
448+
// alerts in backend.
446449
let delay = TimeInterval.random(in: 0 ... 3) // Random delay between 0 and 3 seconds
447450
realtimeLockQueue.asyncAfter(deadline: .now() + delay) {
448451
self.fetchLatestConfig(remainingAttempts: remainingAttempts, targetVersion: targetVersion)
449452
}
450453
}
451454

455+
/// Perform fetch and handle developers callbacks.
452456
@objc(autoFetch:targetVersion:) public
453457
func autoFetch(attempts: Int, targetVersion: Int) {
454-
realtimeLockQueue.async {
458+
realtimeLockQueue.async { [weak self] in
459+
guard let self else { return }
455460
guard attempts > 0 else {
456461
let error = NSError(domain: RemoteConfigUpdateErrorDomain,
457462
code: RemoteConfigUpdateError.notFetched.rawValue,
@@ -468,13 +473,13 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
468473

469474
// MARK: - URLSessionDataDelegate
470475

476+
/// Delegate to asynchronously handle every new notification that comes over
477+
/// the wire. Auto-fetches and runs callback for each new notification.
471478
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask,
472479
didReceive data: Data) {
473-
if !session.isEqual(self.session) {
474-
return
475-
}
476-
477480
let strData = String(data: data, encoding: .utf8) ?? ""
481+
// If response data contains the API enablement link, return the entire
482+
// message to the user in the form of a error.
478483
if strData.contains(serverForbiddenStatusCode) {
479484
let error = NSError(domain: RemoteConfigUpdateErrorDomain,
480485
code: RemoteConfigUpdateError.streamError.rawValue,
@@ -496,7 +501,13 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
496501
evaluateStreamResponse(response)
497502
}
498503
} catch {
499-
propagateErrors(error)
504+
let wrappedError = NSError(domain: RemoteConfigUpdateErrorDomain,
505+
code: RemoteConfigUpdateError.messageInvalid.rawValue,
506+
userInfo: [
507+
NSLocalizedDescriptionKey: "Unable to parse ConfigUpdate. \(strData)",
508+
NSUnderlyingErrorKey: error,
509+
])
510+
propagateErrors(wrappedError)
500511
return
501512
}
502513
}
@@ -534,13 +545,10 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
534545
statusCode == fetchResponseHTTPStatusCodeGatewayTimeout
535546
}
536547

548+
/// Delegate to handle initial reply from the server.
537549
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask,
538550
didReceive response: URLResponse,
539551
completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
540-
if !session.isEqual(self.session) {
541-
completionHandler(.cancel) // Cancel if not current session
542-
return
543-
}
544552
isRequestInProgress = false
545553
if let httpResponse = response as? HTTPURLResponse {
546554
let statusCode = httpResponse.statusCode
@@ -555,8 +563,6 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
555563

556564
if isStatusCodeRetryable(statusCode) {
557565
retryHTTPConnection()
558-
completionHandler(.cancel) // cancel the failing task
559-
560566
} else {
561567
let error = NSError(
562568
domain: RemoteConfigUpdateErrorDomain,
@@ -568,16 +574,17 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
568574
)
569575
RCLog.error("I-RCN000021", "Cannot establish connection. Error: \(error)")
570576
propagateErrors(error)
571-
completionHandler(.cancel) // cancel the failing task
572577
}
573578
} else {
579+
// On success, reset retry parameters.
574580
remainingRetryCount = maxRetries
575581
settings.realtimeRetryCount = 0
576-
completionHandler(.allow)
577582
}
583+
completionHandler(.allow)
578584
}
579585
}
580586

587+
/// Delegate to handle data task completion.
581588
public func urlSession(_ session: URLSession, task: URLSessionTask,
582589
didCompleteWithError error: Error?) {
583590
if !session.isEqual(self.session) {
@@ -591,10 +598,8 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
591598
retryHTTPConnection()
592599
}
593600

601+
/// Delegate to handle session invalidation.
594602
public func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
595-
if !session.isEqual(self.session) {
596-
return
597-
}
598603
if !isRequestInProgress {
599604
if let _ = error {
600605
settings.updateRealtimeExponentialBackoffTime()
@@ -608,13 +613,15 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
608613

609614
@objc public
610615
func beginRealtimeStream() {
611-
realtimeLockQueue.async {
616+
realtimeLockQueue.async { [weak self] in
617+
guard let self else { return }
618+
guard self.settings.realtimeBackoffInterval() <= 0.0 else {
619+
self.retryHTTPConnection()
620+
return
621+
}
612622
if self.canMakeConnection() {
613-
guard self.settings.realtimeBackoffInterval() <= 0.0 else {
614-
self.retryHTTPConnection()
615-
return
616-
}
617-
self.createRequestBody { requestBody in
623+
self.createRequestBody { [weak self] requestBody in
624+
guard let self else { return }
618625
var request = self.request
619626
request.httpBody = requestBody
620627
self.isRequestInProgress = true
@@ -627,7 +634,8 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
627634

628635
@objc public
629636
func pauseRealtimeStream() {
630-
realtimeLockQueue.async {
637+
realtimeLockQueue.async { [weak self] in
638+
guard let self else { return }
631639
if let task = self.dataTask {
632640
task.cancel()
633641
self.dataTask = nil
@@ -639,7 +647,8 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
639647
@objc public func addConfigUpdateListener(_ listener: @Sendable @escaping (RemoteConfigUpdate?,
640648
Error?) -> Void)
641649
-> ConfigUpdateListenerRegistration {
642-
realtimeLockQueue.async {
650+
realtimeLockQueue.async { [weak self] in
651+
guard let self else { return }
643652
let temp = self.listeners.mutableCopy() as! NSMutableOrderedSet
644653
temp.add(listener)
645654
self.listeners = temp
@@ -650,7 +659,8 @@ class ConfigRealtime: NSObject, URLSessionDataDelegate {
650659

651660
@objc public func removeConfigUpdateListener(_ listener: @escaping (RemoteConfigUpdate?, Error?)
652661
-> Void) {
653-
realtimeLockQueue.async {
662+
realtimeLockQueue.async { [weak self] in
663+
guard let self else { return }
654664
let temp: NSMutableOrderedSet = self.listeners.mutableCopy() as! NSMutableOrderedSet
655665
temp.remove(listener)
656666
self.listeners = temp

0 commit comments

Comments
 (0)