Skip to content

Commit 01c2069

Browse files
committed
cache the pending auth requests in executors
* Uncaching now involves more queues, can be refactored when op repo is refactored * Some executors added a helper to remove requests from the active queue and cache the queue after removal.
1 parent d90f0d2 commit 01c2069

File tree

5 files changed

+272
-185
lines changed

5 files changed

+272
-185
lines changed

iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCommonDefines.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,23 +347,27 @@ typedef enum {GET, POST, HEAD, PUT, DELETE, OPTIONS, CONNECT, TRACE, PATCH} HTTP
347347
#define OS_USER_EXECUTOR @"OS_USER_EXECUTOR"
348348
#define OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY @"OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY"
349349
#define OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY @"OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY"
350+
#define OS_USER_EXECUTOR_PENDING_QUEUE_KEY @"OS_USER_EXECUTOR_PENDING_QUEUE_KEY"
350351

351352
// Identity Executor
352353
#define OS_IDENTITY_EXECUTOR @"OS_IDENTITY_EXECUTOR"
353354
#define OS_IDENTITY_EXECUTOR_DELTA_QUEUE_KEY @"OS_IDENTITY_EXECUTOR_DELTA_QUEUE_KEY"
354355
#define OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY @"OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY"
355356
#define OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY @"OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY"
357+
#define OS_IDENTITY_EXECUTOR_PENDING_QUEUE_KEY @"OS_IDENTITY_EXECUTOR_PENDING_QUEUE_KEY"
356358

357359
// Property Executor
358360
#define OS_PROPERTIES_EXECUTOR @"OS_PROPERTIES_EXECUTOR"
359361
#define OS_PROPERTIES_EXECUTOR_DELTA_QUEUE_KEY @"OS_PROPERTIES_EXECUTOR_DELTA_QUEUE_KEY"
360362
#define OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY @"OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY"
363+
#define OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY @"OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY"
361364

362365
// Subscription Executor
363366
#define OS_SUBSCRIPTION_EXECUTOR_DELTA_QUEUE_KEY @"OS_SUBSCRIPTION_EXECUTOR_DELTA_QUEUE_KEY"
364367
#define OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY @"OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY"
365368
#define OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY @"OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY"
366369
#define OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY @"OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY"
370+
#define OS_SUBSCRIPTION_EXECUTOR_PENDING_QUEUE_KEY @"OS_SUBSCRIPTION_EXECUTOR_PENDING_QUEUE_KEY"
367371

368372
// Live Activies Executor
369373
#define OS_LIVE_ACTIVITIES_EXECUTOR_UPDATE_TOKENS_KEY @"OS_LIVE_ACTIVITIES_EXECUTOR_UPDATE_TOKENS_KEY"

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
4848
print("❌ OSIdentityOperationExecutor init(\(jwtConfig.isRequired))")
4949
// Read unfinished deltas and requests from cache, if any...
5050
uncacheDeltas()
51-
uncacheAddAliasRequests()
52-
uncacheRemoveAliasRequests()
51+
uncacheRequests()
5352
}
5453

5554
private func uncacheDeltas() {
@@ -82,19 +81,42 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
8281
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_DELTA_QUEUE_KEY, withValue: self.deltaQueue)
8382
}
8483

85-
private func uncacheAddAliasRequests() {
86-
guard var addRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestAddAliases] else {
87-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor error encountered reading from cache for \(OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY)")
88-
return
84+
private func uncacheRequests() {
85+
var addRequestQueue: [OSRequestAddAliases] = []
86+
var removeRequestQueue: [OSRequestRemoveAlias] = []
87+
88+
if let cachedAddRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestAddAliases] {
89+
addRequestQueue = cachedAddRequestQueue
90+
}
91+
92+
if let cachedRemoveRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestRemoveAlias] {
93+
removeRequestQueue = cachedRemoveRequestQueue
94+
}
95+
96+
if let pendingRequests = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_IDENTITY_EXECUTOR_PENDING_QUEUE_KEY, defaultValue: [:]) as? [String: [OSUserRequest]] {
97+
for requests in pendingRequests.values {
98+
for request in requests {
99+
if request.isKind(of: OSRequestAddAliases.self), let req = request as? OSRequestAddAliases {
100+
addRequestQueue.append(req)
101+
} else if request.isKind(of: OSRequestRemoveAlias.self), let req = request as? OSRequestRemoveAlias {
102+
removeRequestQueue.append(req)
103+
}
104+
}
105+
}
89106
}
90107

108+
linkAddAliasRequests(requests: &addRequestQueue)
109+
linkRemoveAliasRequests(requests: &removeRequestQueue)
110+
}
111+
112+
private func linkAddAliasRequests(requests: inout [OSRequestAddAliases]) {
91113
// Hook each uncached Request to the model in the store
92-
for (index, request) in addRequestQueue.enumerated().reversed() {
114+
for (index, request) in requests.enumerated().reversed() {
93115
if jwtConfig.isRequired == true,
94116
request.identityModel.externalId == nil
95117
{
96118
// remove if jwt is on but the model does not have external ID
97-
addRequestQueue.remove(at: index)
119+
requests.remove(at: index)
98120
continue
99121
}
100122

@@ -107,27 +129,22 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
107129
} else {
108130
// 3. The model do not exist AND this request cannot be sent, drop this Request
109131
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor.init dropped \(request)")
110-
addRequestQueue.remove(at: index)
132+
requests.remove(at: index)
111133
}
112134
}
113135

114-
self.addRequestQueue = addRequestQueue
136+
self.addRequestQueue = requests
115137
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
116138
}
117139

118-
private func uncacheRemoveAliasRequests() {
119-
guard var removeRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestRemoveAlias] else {
120-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor error encountered reading from cache for \(OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY)")
121-
return
122-
}
123-
140+
private func linkRemoveAliasRequests(requests: inout [OSRequestRemoveAlias]) {
124141
// Hook each uncached Request to the model in the store
125-
for (index, request) in removeRequestQueue.enumerated().reversed() {
142+
for (index, request) in requests.enumerated().reversed() {
126143
if jwtConfig.isRequired == true,
127144
request.identityModel.externalId == nil
128145
{
129146
// remove if jwt is on but the model does not have external ID
130-
removeRequestQueue.remove(at: index)
147+
requests.remove(at: index)
131148
continue
132149
}
133150

@@ -140,11 +157,11 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
140157
} else {
141158
// 3. The model do not exist AND this request cannot be sent, drop this Request
142159
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor.init dropped \(request)")
143-
removeRequestQueue.remove(at: index)
160+
requests.remove(at: index)
144161
}
145162
}
146163

147-
self.removeRequestQueue = removeRequestQueue
164+
self.removeRequestQueue = requests
148165
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
149166
}
150167

@@ -161,6 +178,19 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
161178
}
162179
}
163180

181+
/**
182+
This method does not handle concurrency; it should be called with thread-safe usage.
183+
*/
184+
private func removeFromRequestQueueAndPersist(_ request: OSUserRequest) {
185+
if request.isKind(of: OSRequestAddAliases.self) {
186+
self.addRequestQueue.removeAll(where: { $0 == request})
187+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
188+
} else if request.isKind(of: OSRequestRemoveAlias.self) {
189+
self.removeRequestQueue.removeAll(where: { $0 == request})
190+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
191+
}
192+
}
193+
164194
func processDeltaQueue(inBackground: Bool) {
165195
self.dispatchQueue.async {
166196
if !self.deltaQueue.isEmpty {
@@ -238,8 +268,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
238268

239269
func pendRequestUntilAuthUpdated(_ request: OSUserRequest, externalId: String?) {
240270
self.dispatchQueue.async {
241-
self.addRequestQueue.removeAll(where: { $0 == request})
242-
self.removeRequestQueue.removeAll(where: { $0 == request})
271+
self.removeFromRequestQueueAndPersist(request)
243272
guard let externalId = externalId else {
244273
return
245274
}
@@ -250,6 +279,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
250279
}
251280
requests.append(request)
252281
self.pendingAuthRequests[externalId] = requests
282+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_PENDING_QUEUE_KEY, withValue: self.pendingAuthRequests)
253283
}
254284
}
255285

@@ -277,8 +307,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
277307
// No hydration from response
278308
// On success, remove request from cache
279309
self.dispatchQueue.async {
280-
self.addRequestQueue.removeAll(where: { $0 == request})
281-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
310+
self.removeFromRequestQueueAndPersist(request)
282311
if inBackground {
283312
OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier)
284313
}
@@ -288,9 +317,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
288317
if let nsError = error as? NSError {
289318
let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code)
290319
if responseType == .missing {
291-
// Remove from cache and queue
292-
self.addRequestQueue.removeAll(where: { $0 == request})
293-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
320+
self.removeFromRequestQueueAndPersist(request)
294321
// Logout if the user in the SDK is the same
295322
guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel)
296323
else {
@@ -309,8 +336,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
309336
request.sentToClient = false
310337
} else if responseType != .retryable {
311338
// Fail, no retry, remove from cache and queue
312-
self.addRequestQueue.removeAll(where: { $0 == request})
313-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
339+
self.removeFromRequestQueueAndPersist(request)
314340
}
315341
}
316342
if inBackground {
@@ -344,8 +370,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
344370
// There is nothing to hydrate
345371
// On success, remove request from cache
346372
self.dispatchQueue.async {
347-
self.removeRequestQueue.removeAll(where: { $0 == request})
348-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
373+
self.removeFromRequestQueueAndPersist(request)
349374
if inBackground {
350375
OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier)
351376
}
@@ -363,8 +388,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
363388
} else if responseType != .retryable {
364389
// Fail, no retry, remove from cache and queue
365390
// A response of .missing could mean the alias doesn't exist on this user OR this user has been deleted
366-
self.removeRequestQueue.removeAll(where: { $0 == request})
367-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
391+
self.removeFromRequestQueueAndPersist(request)
368392
}
369393
}
370394
if inBackground {
@@ -404,6 +428,7 @@ extension OSIdentityOperationExecutor: OSUserJwtConfigListener {
404428
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
405429
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
406430
self.pendingAuthRequests[externalId] = nil
431+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_PENDING_QUEUE_KEY, withValue: self.pendingAuthRequests)
407432
self.processRequestQueue(inBackground: false)
408433
}
409434
}
@@ -446,6 +471,7 @@ extension OSIdentityOperationExecutor: OSLoggable {
446471
addRequestQueue: \(self.addRequestQueue)
447472
removeRequestQueue: \(self.removeRequestQueue)
448473
deltaQueue: \(self.deltaQueue)
474+
pendingAuthRequests: \(self.pendingAuthRequests)
449475
"""
450476
)
451477
}

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,22 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
110110
}
111111

112112
private func uncacheUpdateRequests() {
113-
print("❌ OSPropertyOperationExecutor uncacheUpdateRequests called")
113+
var updateRequestQueue: [OSRequestUpdateProperties] = []
114114

115-
guard var updateRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestUpdateProperties] else {
116-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSPropertyOperationExecutor error encountered reading from cache for \(OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY)")
117-
return
115+
if let cachedQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestUpdateProperties] {
116+
updateRequestQueue = cachedQueue
118117
}
119118

119+
if let pendingRequests = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY, defaultValue: [:]) as? [String: [OSRequestUpdateProperties]] {
120+
print("❌ prop executor uncached pending \(pendingRequests)")
121+
122+
for requests in pendingRequests.values {
123+
for request in requests {
124+
updateRequestQueue.append(request)
125+
}
126+
}
127+
}
128+
print("❌ prop executor uncached requests \(updateRequestQueue)")
120129
// Hook each uncached Request to the model in the store
121130
for (index, request) in updateRequestQueue.enumerated().reversed() {
122131
if jwtConfig.isRequired == true,
@@ -279,6 +288,7 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
279288
func pendRequestUntilAuthUpdated(_ request: OSRequestUpdateProperties, externalId: String?) {
280289
self.dispatchQueue.async {
281290
self.updateRequestQueue.removeAll(where: { $0 == request})
291+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue)
282292
guard let externalId = externalId else {
283293
return
284294
}
@@ -289,6 +299,7 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
289299
}
290300
requests.append(request)
291301
self.pendingAuthRequests[externalId] = requests
302+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY, withValue: self.pendingAuthRequests)
292303
}
293304
}
294305

@@ -386,6 +397,7 @@ extension OSPropertyOperationExecutor: OSUserJwtConfigListener {
386397
}
387398
self.pendingAuthRequests[externalId] = nil
388399
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue)
400+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY, withValue: self.pendingAuthRequests)
389401
self.processRequestQueue(inBackground: false)
390402
}
391403
}
@@ -422,6 +434,7 @@ extension OSPropertyOperationExecutor: OSLoggable {
422434
💛 OSPropertyOperationExecutor has the following queues:
423435
updateRequestQueue: \(self.updateRequestQueue)
424436
deltaQueue: \(self.deltaQueue)
437+
pendingAuthRequests: \(self.pendingAuthRequests)
425438
"""
426439
)
427440
}

0 commit comments

Comments
 (0)