@@ -35,6 +35,7 @@ import OneSignalOSCore
35
35
*/
36
36
class OSUserExecutor {
37
37
var userRequestQueue : [ OSUserRequest ] = [ ]
38
+ var pendingAuthRequests : [ String : [ OSUserRequest ] ] = [ String: [ OSUserRequest] ] ( )
38
39
private let newRecordsState : OSNewRecordsState
39
40
let jwtConfig : OSUserJwtConfig
40
41
@@ -289,6 +290,22 @@ extension OSUserExecutor {
289
290
appendToQueue ( request)
290
291
executePendingRequests ( )
291
292
}
293
+
294
+ func pendRequestUntilAuthUpdated( _ request: OSUserRequest , externalId: String ? ) {
295
+ self . dispatchQueue. async {
296
+ self . userRequestQueue. removeAll ( where: { $0 == request} )
297
+ guard let externalId = externalId else {
298
+ return
299
+ }
300
+ var requests = self . pendingAuthRequests [ externalId] ?? [ ]
301
+ let inQueue = requests. contains ( where: { $0 == request} )
302
+ guard !inQueue else {
303
+ return
304
+ }
305
+ requests. append ( request)
306
+ self . pendingAuthRequests [ externalId] = requests
307
+ }
308
+ }
292
309
293
310
func executeCreateUserRequest( _ request: OSRequestCreateUser ) {
294
311
guard !request. sentToClient else {
@@ -301,6 +318,11 @@ extension OSUserExecutor {
301
318
request. pushSubscriptionModel = pushSubscriptionModel
302
319
request. updatePushSubscriptionModel ( pushSubscriptionModel)
303
320
}
321
+
322
+ guard request. addJWTHeaderIsValid ( identityModel: request. identityModel) else {
323
+ pendRequestUntilAuthUpdated ( request, externalId: request. identityModel. externalId)
324
+ return
325
+ }
304
326
305
327
guard request. prepareForExecution ( newRecordsState: newRecordsState)
306
328
else {
@@ -344,7 +366,7 @@ extension OSUserExecutor {
344
366
OneSignalLog . onesignalLog ( . LL_ERROR, message: " OSUserExecutor no externalId for unauthorized request. " )
345
367
return
346
368
}
347
- self . handleUnauthorizedError ( externalId: externalId, error: nsError)
369
+ self . handleUnauthorizedError ( externalId: externalId, error: nsError, request : request )
348
370
request. sentToClient = false
349
371
} else if responseType != . retryable {
350
372
// A failed create user request would leave the SDK in a bad state
@@ -361,8 +383,9 @@ extension OSUserExecutor {
361
383
}
362
384
}
363
385
364
- func handleUnauthorizedError( externalId: String , error: NSError ) {
386
+ func handleUnauthorizedError( externalId: String , error: NSError , request : OSUserRequest ) {
365
387
if ( jwtConfig. isRequired ?? false ) {
388
+ self . pendRequestUntilAuthUpdated ( request, externalId: externalId)
366
389
OneSignalUserManagerImpl . sharedInstance. invalidateJwtForExternalId ( externalId: externalId, error: error)
367
390
}
368
391
}
@@ -376,6 +399,7 @@ extension OSUserExecutor {
376
399
377
400
/**
378
401
For migrating legacy players from 3.x to 5.x. This request will fetch the identity object for a subscription ID, and we will use the returned onesignalId to fetch and hydrate the local user.
402
+ ECM can this ever succeed with identity verification on?
379
403
*/
380
404
func executeFetchIdentityBySubscriptionRequest( _ request: OSRequestFetchIdentityBySubscription ) {
381
405
guard !request. sentToClient else {
@@ -485,7 +509,7 @@ extension OSUserExecutor {
485
509
// This will hydrate the OneSignal ID for any pending requests
486
510
self . createUser ( aliasLabel: request. aliasLabel, aliasId: request. aliasId, identityModel: request. identityModelToUpdate)
487
511
}
488
- } else if responseType == . invalid || responseType == . unauthorized {
512
+ } else if responseType == . invalid || responseType == . unauthorized { //Identify User should never be called with identity verification on
489
513
// Failed, no retry
490
514
self . removeFromQueue ( request)
491
515
self . executePendingRequests ( )
@@ -574,7 +598,7 @@ extension OSUserExecutor {
574
598
OneSignalUserManagerImpl . sharedInstance. _logout ( )
575
599
} else if responseType == . unauthorized && ( self . jwtConfig. isRequired ?? false ) {
576
600
if let externalId = request. identityModel. externalId {
577
- self . handleUnauthorizedError ( externalId: externalId, error: nsError)
601
+ self . handleUnauthorizedError ( externalId: externalId, error: nsError, request : request )
578
602
}
579
603
request. sentToClient = false
580
604
} else if responseType != . retryable {
@@ -707,15 +731,23 @@ extension OSUserExecutor: OSUserJwtConfigListener {
707
731
}
708
732
709
733
func onJwtUpdated( externalId: String , token: String ? ) {
710
- /*
711
- ECM
712
- Do we actually even need this callback?
713
- Requests that are invalidated do not pass prepare for execution
714
- Once they are valid they will pass prepare for execution.
715
- We could use this callback to optimize sending requests immediately
716
- */
734
+ reQueuePendingRequestsForExternalId ( externalId: externalId)
717
735
print ( " ❌ OSUserExecutor onJwtUpdated for \( externalId) to \( String ( describing: token) ) " )
718
736
}
737
+
738
+ private func reQueuePendingRequestsForExternalId( externalId: String ) {
739
+ self . dispatchQueue. async {
740
+ guard let requests = self . pendingAuthRequests [ externalId] else {
741
+ return
742
+ }
743
+ for request in requests {
744
+ self . userRequestQueue. append ( request)
745
+ }
746
+ self . pendingAuthRequests [ externalId] = nil
747
+ OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self . userRequestQueue)
748
+ self . executePendingRequests ( withDelay: true )
749
+ }
750
+ }
719
751
720
752
private func removeInvalidRequests( ) {
721
753
self . dispatchQueue. async {
0 commit comments