@@ -47,7 +47,7 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
47
47
init ( newRecordsState: OSNewRecordsState , jwtConfig: OSUserJwtConfig ) {
48
48
self . newRecordsState = newRecordsState
49
49
self . jwtConfig = jwtConfig
50
- // Read unfinished deltas and requests from cache, if any...
50
+ self . jwtConfig . subscribe ( self , key : OS_SUBSCRIPTION_EXECUTOR )
51
51
uncacheDeltas ( )
52
52
uncacheRequests ( )
53
53
}
@@ -141,17 +141,30 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
141
141
private func linkDeleteSubscriptionRequests( requests: inout [ OSRequestDeleteSubscription ] ) {
142
142
// Hook each uncached Request to the model in the store
143
143
for (index, request) in requests. enumerated ( ) . reversed ( ) {
144
+ // 1. Hook up the subscription model
144
145
if let subscriptionModel = getSubscriptionModelFromStores ( modelId: request. subscriptionModel. modelId) {
145
- // 1 . The model exists in the store, set it to be the Request's model
146
+ // a . The model exists in the store, set it to be the Request's model
146
147
request. subscriptionModel = subscriptionModel
147
148
} else if let subscriptionModel = subscriptionModels [ request. subscriptionModel. modelId] {
148
- // 2 . The model exists in the dict of seen subscription models
149
+ // b . The model exists in the dict of seen subscription models
149
150
request. subscriptionModel = subscriptionModel
150
151
} else if !request. prepareForExecution ( newRecordsState: newRecordsState) {
151
- // 3 . The model does not exist AND this request cannot be sent, drop this Request
152
+ // c . The model does not exist AND this request cannot be sent, drop this Request
152
153
OneSignalLog . onesignalLog ( . LL_ERROR, message: " OSSubscriptionOperationExecutor.init dropped \( request) " )
153
154
requests. remove ( at: index)
154
155
}
156
+ // 2. Hook up the identity model
157
+ if let identityModel = OneSignalUserManagerImpl . sharedInstance. getIdentityModel ( request. identityModel. modelId) {
158
+ // a. The model exist in the repo
159
+ request. identityModel = identityModel
160
+ } else if request. prepareForExecution ( newRecordsState: newRecordsState) {
161
+ // b. The request can be sent, add the model to the repo
162
+ OneSignalUserManagerImpl . sharedInstance. addIdentityModelToRepo ( request. identityModel)
163
+ } else {
164
+ // c. The model do not exist AND this request cannot be sent, drop this Request
165
+ OneSignalLog . onesignalLog ( . LL_WARN, message: " OSSubscriptionOperationExecutor.init dropped: \( request) " )
166
+ requests. remove ( at: index)
167
+ }
155
168
}
156
169
self . removeRequestQueue = requests
157
170
OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self . removeRequestQueue)
@@ -254,8 +267,20 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
254
267
self . addRequestQueue. append ( request)
255
268
256
269
case OS_REMOVE_SUBSCRIPTION_DELTA:
270
+ // Only create the request if the identity model exists
271
+ guard let identityModel = OneSignalUserManagerImpl . sharedInstance. getIdentityModel ( delta. identityModelId) else {
272
+ OneSignalLog . onesignalLog ( . LL_ERROR, message: " OSSubscriptionOperationExecutor.processDeltaQueue dropped \( delta) " )
273
+ continue
274
+ }
275
+
276
+ // If JWT is on but the external ID does not exist, drop this Delta
277
+ if self . jwtConfig. isRequired == true , identityModel. externalId == nil {
278
+ print ( " ❌ \( delta) is Invalid with JWT, being dropped " )
279
+ }
280
+
257
281
let request = OSRequestDeleteSubscription (
258
- subscriptionModel: subModel
282
+ subscriptionModel: subModel,
283
+ identityModel: identityModel
259
284
)
260
285
self . removeRequestQueue. append ( request)
261
286
@@ -317,31 +342,11 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
317
342
}
318
343
}
319
344
}
345
+ }
320
346
321
- func handleUnauthorizedError( externalId: String , error: NSError , request: OSUserRequest ) {
322
- if jwtConfig. isRequired ?? false {
323
- self . pendRequestUntilAuthUpdated ( request, externalId: externalId)
324
- OneSignalUserManagerImpl . sharedInstance. invalidateJwtForExternalId ( externalId: externalId, error: error)
325
- }
326
- }
327
-
328
- func pendRequestUntilAuthUpdated( _ request: OSUserRequest , externalId: String ? ) {
329
- self . dispatchQueue. async {
330
- self . removeFromRequestQueueAndPersist ( request)
331
- guard let externalId = externalId else {
332
- return
333
- }
334
- var requests = self . pendingAuthRequests [ externalId] ?? [ ]
335
- let inQueue = requests. contains ( where: { $0 == request} )
336
- guard !inQueue else {
337
- return
338
- }
339
- requests. append ( request)
340
- self . pendingAuthRequests [ externalId] = requests
341
- OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_PENDING_QUEUE_KEY, withValue: self . pendingAuthRequests)
342
- }
343
- }
347
+ // MARK: - Execution
344
348
349
+ extension OSSubscriptionOperationExecutor {
345
350
func executeCreateSubscriptionRequest( _ request: OSRequestCreateSubscription , inBackground: Bool ) {
346
351
guard !request. sentToClient else {
347
352
return
@@ -416,7 +421,7 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
416
421
guard !request. sentToClient else {
417
422
return
418
423
}
419
- // ECM TODO
424
+ // ECM TODO - Delete Subscription, not supported on JWT yet (9-23-2024)
420
425
// guard request.addJWTHeaderIsValid(identityModel: request.identityModel) else {
421
426
// pendRequestUntilAuthUpdated(request, externalId:request.identityModel.externalId)
422
427
// return
@@ -448,8 +453,7 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
448
453
if let nsError = error as? NSError {
449
454
let responseType = OSNetworkingUtils . getResponseStatusType ( nsError. code)
450
455
if responseType == . unauthorized && ( self . jwtConfig. isRequired ?? false ) {
451
- // ECM The delete subscription request doesn't have an identity model?
452
- if let externalId = OneSignalUserManagerImpl . sharedInstance. user. identityModel. externalId {
456
+ if let externalId = request. identityModel. externalId {
453
457
self . handleUnauthorizedError ( externalId: externalId, error: nsError, request: request)
454
458
}
455
459
request. sentToClient = false
@@ -470,11 +474,6 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
470
474
guard !request. sentToClient else {
471
475
return
472
476
}
473
- // ECM TODO
474
- // guard request.addJWTHeaderIsValid(identityModel: request.identityModel) else {
475
- // pendRequestUntilAuthUpdated(request, externalId:request.identityModel.externalId)
476
- // return
477
- // }
478
477
guard request. prepareForExecution ( newRecordsState: newRecordsState) else {
479
478
return
480
479
}
@@ -499,11 +498,7 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
499
498
if let nsError = error as? NSError {
500
499
let responseType = OSNetworkingUtils . getResponseStatusType ( nsError. code)
501
500
if responseType == . unauthorized && ( self . jwtConfig. isRequired ?? false ) {
502
- // ECM The update subscription request doesn't have an identity model?
503
- if let externalId = OneSignalUserManagerImpl . sharedInstance. user. identityModel. externalId {
504
- self . handleUnauthorizedError ( externalId: externalId, error: nsError, request: request)
505
- }
506
- request. sentToClient = false
501
+ // TODO: Jwt, do we need to handle this case, as this request does not use user JWT
507
502
} else if responseType != . retryable {
508
503
// Fail, no retry, remove from cache and queue
509
504
self . removeFromRequestQueueAndPersist ( request)
@@ -520,14 +515,40 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
520
515
extension OSSubscriptionOperationExecutor : OSUserJwtConfigListener {
521
516
func onRequiresUserAuthChanged( from: OneSignalOSCore . OSRequiresUserAuth , to: OneSignalOSCore . OSRequiresUserAuth ) {
522
517
print ( " ❌ OSSubscriptionOperationExecutor onUserAuthChanged from \( String ( describing: from) ) to \( String ( describing: to) ) " )
523
- // ECM TODO If auth changed from false or unknown to true, process requests
518
+ if to == . on {
519
+ removeInvalidDeltasAndRequests ( )
520
+ }
524
521
}
525
522
526
523
func onJwtUpdated( externalId: String , token: String ? ) {
527
524
print ( " ❌ OSSubscriptionOperationExecutor onJwtUpdated for \( externalId) to \( String ( describing: token) ) " )
528
525
reQueuePendingRequestsForExternalId ( externalId: externalId)
529
526
}
530
527
528
+ func handleUnauthorizedError( externalId: String , error: NSError , request: OSUserRequest ) {
529
+ if jwtConfig. isRequired ?? false {
530
+ self . pendRequestUntilAuthUpdated ( request, externalId: externalId)
531
+ OneSignalUserManagerImpl . sharedInstance. invalidateJwtForExternalId ( externalId: externalId, error: error)
532
+ }
533
+ }
534
+
535
+ func pendRequestUntilAuthUpdated( _ request: OSUserRequest , externalId: String ? ) {
536
+ self . dispatchQueue. async {
537
+ self . removeFromRequestQueueAndPersist ( request)
538
+ guard let externalId = externalId else {
539
+ return
540
+ }
541
+ var requests = self . pendingAuthRequests [ externalId] ?? [ ]
542
+ let inQueue = requests. contains ( where: { $0 == request} )
543
+ guard !inQueue else {
544
+ return
545
+ }
546
+ requests. append ( request)
547
+ self . pendingAuthRequests [ externalId] = requests
548
+ OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_PENDING_QUEUE_KEY, withValue: self . pendingAuthRequests)
549
+ }
550
+ }
551
+
531
552
private func reQueuePendingRequestsForExternalId( externalId: String ) {
532
553
self . dispatchQueue. async {
533
554
guard let requests = self . pendingAuthRequests [ externalId] else {
@@ -538,18 +559,52 @@ extension OSSubscriptionOperationExecutor: OSUserJwtConfigListener {
538
559
self . addRequestQueue. append ( addRequest)
539
560
} else if let removeRequest = request as? OSRequestDeleteSubscription {
540
561
self . removeRequestQueue. append ( removeRequest)
541
- } else if let updateRequest = request as? OSRequestUpdateSubscription {
542
- self . updateRequestQueue. append ( updateRequest)
543
562
}
544
563
}
545
564
OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self . addRequestQueue)
546
565
OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self . removeRequestQueue)
547
- OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self . updateRequestQueue)
548
566
self . pendingAuthRequests [ externalId] = nil
549
567
OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_PENDING_QUEUE_KEY, withValue: self . pendingAuthRequests)
550
568
self . processRequestQueue ( inBackground: false )
551
569
}
552
570
}
571
+
572
+ /**
573
+ Drops deltas and requests that add and remove subscriptions on unidentified users.
574
+ Subscription updates are used only for push subscriptions, which are kept as they do not use User JWT.
575
+ */
576
+ private func removeInvalidDeltasAndRequests( ) {
577
+ self . dispatchQueue. async {
578
+ print ( " ❌ OSSubscriptionOperationExecutor.removeInvalidDeltasAndRequests called " )
579
+
580
+ for (index, delta) in self . deltaQueue. enumerated ( ) . reversed ( ) {
581
+ if delta. name != OS_UPDATE_SUBSCRIPTION_DELTA,
582
+ let identityModel = OneSignalUserManagerImpl . sharedInstance. getIdentityModel ( delta. identityModelId) ,
583
+ identityModel. externalId == nil
584
+ {
585
+ print ( " \( delta) is Invalid, being removed " )
586
+ self . deltaQueue. remove ( at: index)
587
+ }
588
+ }
589
+ OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_DELTA_QUEUE_KEY, withValue: self . deltaQueue)
590
+
591
+ for (index, request) in self . addRequestQueue. enumerated ( ) . reversed ( ) {
592
+ if request. identityModel. externalId == nil {
593
+ print ( " \( request) is Invalid, being removed " )
594
+ self . addRequestQueue. remove ( at: index)
595
+ }
596
+ }
597
+ OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self . updateRequestQueue)
598
+
599
+ for (index, request) in self . removeRequestQueue. enumerated ( ) . reversed ( ) {
600
+ if request. identityModel. externalId == nil {
601
+ print ( " \( request) is Invalid, being removed " )
602
+ self . removeRequestQueue. remove ( at: index)
603
+ }
604
+ }
605
+ OneSignalUserDefaults . initShared ( ) . saveCodeableData ( forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self . updateRequestQueue)
606
+ }
607
+ }
553
608
}
554
609
555
610
extension OSSubscriptionOperationExecutor : OSLoggable {
0 commit comments