From 05a1ebd475b965974b9aae60895cdaf8ac11e113 Mon Sep 17 00:00:00 2001 From: Bernard Gatt Date: Thu, 15 Feb 2024 08:11:46 +0100 Subject: [PATCH] feat: use new header to set polling interval (#519) Co-authored-by: Levi Bostian --- Sources/MessagingInApp/Gist/Gist.swift | 4 ++-- .../Gist/Managers/MessageQueueManager.swift | 20 +++++++++++----- .../Gist/Managers/QueueManager.swift | 23 ++++++++++++++++--- .../Gist/Network/BaseNetwork.swift | 3 ++- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Sources/MessagingInApp/Gist/Gist.swift b/Sources/MessagingInApp/Gist/Gist.swift index 00a0978ab..8cfd0ef40 100644 --- a/Sources/MessagingInApp/Gist/Gist.swift +++ b/Sources/MessagingInApp/Gist/Gist.swift @@ -2,9 +2,9 @@ import Foundation import UIKit public class Gist: GistDelegate { - private var messageQueueManager = MessageQueueManager() - private var messageManagers: [MessageManager] = [] + var messageQueueManager = MessageQueueManager() var shownMessageQueueIds: Set = [] + private var messageManagers: [MessageManager] = [] public var siteId: String = "" public var dataCenter: String = "" diff --git a/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift b/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift index fb6088815..351316274 100644 --- a/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift +++ b/Sources/MessagingInApp/Gist/Managers/MessageQueueManager.swift @@ -2,23 +2,26 @@ import Foundation import UIKit class MessageQueueManager { + var interval: Double = 600 private var queueTimer: Timer! // The local message store is used to keep messages that can't be displayed because the route rule doesnt match. private var localMessageStore: [String: Message] = [:] - func setup() { + func setup(skipQueueCheck: Bool = false) { queueTimer = Timer.scheduledTimer( - timeInterval: 10, + timeInterval: interval, target: self, selector: #selector(fetchUserMessages), userInfo: nil, repeats: true ) - // Since on app launch there's a short period where the applicationState is still set to "background" - // We wait 1 second for the app to become active before checking for messages. - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - self.fetchUserMessages() + if !skipQueueCheck { + // Since on app launch there's a short period where the applicationState is still set to "background" + // We wait 1 second for the app to become active before checking for messages. + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.fetchUserMessages() + } } } @@ -68,7 +71,12 @@ class MessageQueueManager { QueueManager(siteId: Gist.shared.siteId, dataCenter: Gist.shared.dataCenter) .fetchUserQueue(userToken: userToken, completionHandler: { response in switch response { + case .success(nil): + Logger.instance.info(message: "No changes to remote queue") case .success(let responses): + guard let responses else { + return + } // To prevent us from showing expired / revoked messages, clear user messages from local queue. self.clearUserMessagesFromLocalStore() Logger.instance.info(message: "Gist queue service found \(responses.count) new messages") diff --git a/Sources/MessagingInApp/Gist/Managers/QueueManager.swift b/Sources/MessagingInApp/Gist/Managers/QueueManager.swift index 708140f09..69be30d94 100644 --- a/Sources/MessagingInApp/Gist/Managers/QueueManager.swift +++ b/Sources/MessagingInApp/Gist/Managers/QueueManager.swift @@ -9,15 +9,20 @@ class QueueManager { self.dataCenter = dataCenter } - func fetchUserQueue(userToken: String, completionHandler: @escaping (Result<[UserQueueResponse], Error>) -> Void) { + func fetchUserQueue(userToken: String, completionHandler: @escaping (Result<[UserQueueResponse]?, Error>) -> Void) { do { try GistQueueNetwork(siteId: siteId, dataCenter: dataCenter, userToken: userToken) .request(QueueEndpoint.getUserQueue, completionHandler: { response in switch response { case .success(let (data, response)): - if response.statusCode == 204 { + self.updatePollingInterval(headers: response.allHeaderFields) + switch response.statusCode { + case 204: completionHandler(.success([])) - } else { + case 304: + // No changes to the remote queue, returning nil so we don't clear local store. + completionHandler(.success(nil)) + default: do { var userQueue = [UserQueueResponse]() if let userQueueResponse = @@ -46,4 +51,16 @@ class QueueManager { completionHandler(.failure(error)) } } + + private func updatePollingInterval(headers: [AnyHashable: Any]) { + if let newPollingIntervalString = headers["x-gist-queue-polling-interval"] as? String, + let newPollingInterval = Double(newPollingIntervalString), + newPollingInterval != Gist.shared.messageQueueManager.interval { + DispatchQueue.main.async { + Gist.shared.messageQueueManager.interval = newPollingInterval + Gist.shared.messageQueueManager.setup(skipQueueCheck: true) + Logger.instance.info(message: "Polling interval changed to: \(newPollingInterval) seconds") + } + } + } } diff --git a/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift b/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift index 97b0853b1..1ce7efcb7 100644 --- a/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift +++ b/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift @@ -15,6 +15,7 @@ enum BaseNetwork { completionHandler: @escaping (Result) -> Void ) throws { var urlRequest = urlRequest + urlRequest.cachePolicy = .reloadIgnoringCacheData switch request.parameters { case .body(let body): urlRequest.httpBody = try JSONSerialization.data(withJSONObject: body.asDictionary(), options: []) @@ -31,7 +32,7 @@ enum BaseNetwork { URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, response, error in if let error = error { completionHandler(.failure(error)) } guard let data = data, let response = response as? HTTPURLResponse, - (200 ... 299).contains(response.statusCode) + (200 ... 304).contains(response.statusCode) else { completionHandler(.failure(GistNetworkError.serverError)) return