Skip to content

Commit 658663c

Browse files
committed
Deprecate Transfer Subscription
* The SDK will longer make Transfer Subscription calls now that requests via external ID are removed, and all requests are expected to use OneSignal ID. * The Transfer Subscription request was previously used in an Identify User 409 conflict to transfer the push subscription to that External ID. * Instead these will translate to Create User which will contain the External ID and the push subscription in the payload. * Deprecate this request class but keep a skeleton in order to uncache them
1 parent 461c377 commit 658663c

File tree

3 files changed

+41
-136
lines changed

3 files changed

+41
-136
lines changed

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

Lines changed: 25 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@ import OneSignalOSCore
3131

3232
/**
3333
Involved in the login process and responsible for Identify User and Create User.
34-
Can execute `OSRequestCreateUser`, `OSRequestIdentifyUser`, `OSRequestTransferSubscription`, `OSRequestFetchUser`, `OSRequestFetchIdentityBySubscription`.
34+
Can execute `OSRequestCreateUser`, `OSRequestIdentifyUser`, `OSRequestFetchUser`, `OSRequestFetchIdentityBySubscription`.
3535
*/
3636
class OSUserExecutor {
3737
static var userRequestQueue: [OSUserRequest] = []
38-
static var transferSubscriptionRequestQueue: [OSRequestTransferSubscription] = []
3938

4039
// The User executor dispatch queue, serial. This synchronizes access to the request queues.
4140
private static let dispatchQueue = DispatchQueue(label: "OneSignal.OSUserExecutor", target: .global())
@@ -99,30 +98,28 @@ class OSUserExecutor {
9998
}
10099
self.userRequestQueue = userRequestQueue
101100
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self.userRequestQueue)
102-
// Read unfinished Transfer Subscription requests from cache, if any...
103-
if let transferSubscriptionRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestTransferSubscription] {
104-
// We only care about the last transfer subscription request
105-
if let request = transferSubscriptionRequestQueue.last {
106-
// Hook the uncached Request to the model in the store
107-
if request.subscriptionModel.modelId == OneSignalUserManagerImpl.sharedInstance.user.pushSubscriptionModel.modelId {
108-
// The model exist, set it to be the Request's model
109-
request.subscriptionModel = OneSignalUserManagerImpl.sharedInstance.user.pushSubscriptionModel
110-
self.transferSubscriptionRequestQueue = [request]
111-
} else if !request.prepareForExecution() {
112-
// The model do not exist AND this request cannot be sent, drop this Request
113-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor.start() dropped: \(request)")
114-
self.transferSubscriptionRequestQueue = []
115-
}
116-
}
117-
} else {
118-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor error encountered reading from cache for \(OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY)")
119-
}
120-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY, withValue: self.transferSubscriptionRequestQueue)
121101

102+
migrateTransferSubscriptionRequests()
122103
executePendingRequests()
123104
}
124105
}
125106

107+
/**
108+
Read Transfer Subscription requests from cache, if any.
109+
As of `5.2.3`, the SDK will no longer send Transfer Subscription requests, so migrate the request into an equivalent Create User request.
110+
*/
111+
static private func migrateTransferSubscriptionRequests() {
112+
if let transferSubscriptionRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY, defaultValue: nil) as? [OSRequestTransferSubscription] {
113+
OneSignalUserDefaults.initShared().removeValue(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY)
114+
115+
// Translate the last request into a Create User request, if the current user is the same
116+
if let request = transferSubscriptionRequestQueue.last,
117+
OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.aliasId) {
118+
createUser(OneSignalUserManagerImpl.sharedInstance.user)
119+
}
120+
}
121+
}
122+
126123
static private func getIdentityModel(_ modelId: String) -> OSIdentityModel? {
127124
return OneSignalUserManagerImpl.sharedInstance.getIdentityModel(modelId)
128125
}
@@ -133,41 +130,27 @@ class OSUserExecutor {
133130

134131
static func appendToQueue(_ request: OSUserRequest) {
135132
self.dispatchQueue.async {
136-
if request.isKind(of: OSRequestTransferSubscription.self), let req = request as? OSRequestTransferSubscription {
137-
self.transferSubscriptionRequestQueue.append(req)
138-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY, withValue: self.transferSubscriptionRequestQueue)
139-
} else {
140-
self.userRequestQueue.append(request)
141-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self.userRequestQueue)
142-
}
133+
self.userRequestQueue.append(request)
134+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self.userRequestQueue)
143135
}
144136
}
145137

146138
static func removeFromQueue(_ request: OSUserRequest) {
147139
self.dispatchQueue.async {
148-
if request.isKind(of: OSRequestTransferSubscription.self), let req = request as? OSRequestTransferSubscription {
149-
transferSubscriptionRequestQueue.removeAll(where: { $0 == req})
150-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_TRANSFER_SUBSCRIPTION_REQUEST_QUEUE_KEY, withValue: self.transferSubscriptionRequestQueue)
151-
} else {
152-
userRequestQueue.removeAll(where: { $0 == request})
153-
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self.userRequestQueue)
154-
}
140+
userRequestQueue.removeAll(where: { $0 == request})
141+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_USER_EXECUTOR_USER_REQUEST_QUEUE_KEY, withValue: self.userRequestQueue)
155142
}
156143
}
157144

158145
static func executePendingRequests() {
159146
self.dispatchQueue.async {
160-
let requestQueue: [OSUserRequest] = userRequestQueue + transferSubscriptionRequestQueue
161-
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSUserExecutor.executePendingRequests called with queue \(requestQueue)")
147+
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSUserExecutor.executePendingRequests called with queue \(userRequestQueue)")
162148

163-
if requestQueue.isEmpty {
149+
if userRequestQueue.isEmpty {
164150
return
165151
}
166152

167-
// Sort the requestQueue by timestamp
168-
for request in requestQueue.sorted(by: { first, second in
169-
return first.timestamp < second.timestamp
170-
}) {
153+
for request in userRequestQueue {
171154
// Return as soon as we reach an un-executable request
172155
if !request.prepareForExecution() {
173156
OneSignalLog.onesignalLog(.LL_WARN, message: "OSUserExecutor.executePendingRequests() is blocked by unexecutable request \(request)")
@@ -183,9 +166,6 @@ class OSUserExecutor {
183166
} else if request.isKind(of: OSRequestIdentifyUser.self), let identifyUserRequest = request as? OSRequestIdentifyUser {
184167
executeIdentifyUserRequest(identifyUserRequest)
185168
return
186-
} else if request.isKind(of: OSRequestTransferSubscription.self), let transferSubscriptionRequest = request as? OSRequestTransferSubscription {
187-
executeTransferPushSubscriptionRequest(transferSubscriptionRequest)
188-
return
189169
} else if request.isKind(of: OSRequestFetchUser.self), let fetchUserRequest = request as? OSRequestFetchUser {
190170
executeFetchUserRequest(fetchUserRequest)
191171
return
@@ -390,45 +370,6 @@ extension OSUserExecutor {
390370
}
391371
}
392372

393-
static func transferPushSubscriptionTo(aliasLabel: String, aliasId: String) {
394-
// TODO: Where to get pushSubscriptionModel for this request
395-
let request = OSRequestTransferSubscription(
396-
subscriptionModel: OneSignalUserManagerImpl.sharedInstance.user.pushSubscriptionModel,
397-
aliasLabel: aliasLabel,
398-
aliasId: aliasId
399-
)
400-
401-
appendToQueue(request)
402-
403-
executePendingRequests()
404-
}
405-
406-
static func executeTransferPushSubscriptionRequest(_ request: OSRequestTransferSubscription) {
407-
guard !request.sentToClient else {
408-
return
409-
}
410-
guard request.prepareForExecution() else {
411-
// Missing subscriptionId
412-
OneSignalLog.onesignalLog(.LL_DEBUG, message: "OSUserExecutor.executeTransferPushSubscriptionRequest with request \(request) cannot be executed due to failing prepareForExecution()")
413-
return
414-
}
415-
request.sentToClient = true
416-
OneSignalCoreImpl.sharedClient().execute(request) { _ in
417-
removeFromQueue(request)
418-
executePendingRequests()
419-
} onFailure: { error in
420-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor executeTransferPushSubscriptionRequest failed with error: \(error.debugDescription)")
421-
if let nsError = error as? NSError {
422-
let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code)
423-
if responseType != .retryable {
424-
// Fail, no retry, remove from cache and queue
425-
removeFromQueue(request)
426-
}
427-
}
428-
executePendingRequests()
429-
}
430-
}
431-
432373
static func fetchUser(aliasLabel: String, aliasId: String, identityModel: OSIdentityModel, onNewSession: Bool = false) {
433374
let request = OSRequestFetchUser(identityModel: identityModel, aliasLabel: aliasLabel, aliasId: aliasId, onNewSession: onNewSession)
434375

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OneSignalUserManagerImpl.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,14 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
354354
return self.identityModelStore.getModel(modelId: identityModel.modelId) != nil
355355
}
356356

357+
func isCurrentUser(_ externalId: String) -> Bool {
358+
guard !externalId.isEmpty else {
359+
OneSignalLog.onesignalLog(.LL_ERROR, message: "isCurrentUser called with empty externalId")
360+
return false
361+
}
362+
363+
return user.identityModel.externalId == externalId
364+
}
357365
/**
358366
Clears the existing user's data in preparation for hydration via a fetch user call.
359367
*/

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestTransferSubscription.swift

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,80 +28,36 @@
2828
import OneSignalCore
2929

3030
/**
31+
Deprecated as of `5.2.3`. Use CreateUser instead. This class skeleton remains due to potentially cached requests.
32+
When this request is uncached, it will be translated to a CreateUser request, if appropriate.
33+
-------
3134
Transfers the Subscription specified by the subscriptionId to the User identified by the identity in the payload.
3235
Only one entry is allowed, `onesignal_id` or an Alias. We will use the alias specified.
3336
The anticipated usage of this request is only for push subscriptions.
3437
*/
38+
@available(*, deprecated, message: "Replaced by Create User")
3539
class OSRequestTransferSubscription: OneSignalRequest, OSUserRequest {
3640
var sentToClient = false
37-
let stringDescription: String
38-
override var description: String {
39-
return stringDescription
40-
}
4141

42-
var subscriptionModel: OSSubscriptionModel
4342
let aliasLabel: String
4443
let aliasId: String
4544

46-
// Need an alias and subscription_id
4745
func prepareForExecution() -> Bool {
48-
if let subscriptionId = subscriptionModel.subscriptionId, let appId = OneSignalConfigManager.getAppId() {
49-
self.path = "apps/\(appId)/subscriptions/\(subscriptionId)/owner"
50-
// TODO: self.addJWTHeader(identityModel: identityModel) ??
51-
return true
52-
} else {
53-
self.path = "" // self.path is non-nil, so set to empty string
54-
return false
55-
}
46+
return false
5647
}
5748

58-
/**
59-
Must pass an Alias pair to identify the User.
60-
*/
61-
init(
62-
subscriptionModel: OSSubscriptionModel,
63-
aliasLabel: String,
64-
aliasId: String
65-
) {
66-
self.subscriptionModel = subscriptionModel
67-
self.aliasLabel = aliasLabel
68-
self.aliasId = aliasId
69-
self.stringDescription = "<OSRequestTransferSubscription to \(aliasLabel): \(aliasId)>"
70-
super.init()
71-
self.parameters = ["identity": [aliasLabel: aliasId]]
72-
self.method = PATCH
73-
_ = prepareForExecution() // sets the path property
74-
}
75-
76-
func encode(with coder: NSCoder) {
77-
coder.encode(subscriptionModel, forKey: "subscriptionModel")
78-
coder.encode(aliasLabel, forKey: "aliasLabel")
79-
coder.encode(aliasId, forKey: "aliasId")
80-
coder.encode(parameters, forKey: "parameters")
81-
coder.encode(method.rawValue, forKey: "method") // Encodes as String
82-
coder.encode(timestamp, forKey: "timestamp")
83-
}
49+
func encode(with coder: NSCoder) { }
8450

51+
/// All cached instances should have External ID as the alias
8552
required init?(coder: NSCoder) {
8653
guard
87-
let subscriptionModel = coder.decodeObject(forKey: "subscriptionModel") as? OSSubscriptionModel,
8854
let aliasLabel = coder.decodeObject(forKey: "aliasLabel") as? String,
89-
let aliasId = coder.decodeObject(forKey: "aliasId") as? String,
90-
let rawMethod = coder.decodeObject(forKey: "method") as? UInt32,
91-
let parameters = coder.decodeObject(forKey: "parameters") as? [String: Any],
92-
let timestamp = coder.decodeObject(forKey: "timestamp") as? Date
55+
let aliasId = coder.decodeObject(forKey: "aliasId") as? String
9356
else {
9457
// Log error
9558
return nil
9659
}
97-
self.subscriptionModel = subscriptionModel
9860
self.aliasLabel = aliasLabel
9961
self.aliasId = aliasId
100-
self.stringDescription = "<OSRequestTransferSubscription to \(aliasLabel): \(aliasId)>"
101-
super.init()
102-
self.parameters = parameters
103-
self.method = HTTPMethod(rawValue: rawMethod)
104-
self.timestamp = timestamp
105-
_ = prepareForExecution()
10662
}
10763
}

0 commit comments

Comments
 (0)