Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: device attributes using data pipeline #434

Merged
merged 27 commits into from
Dec 15, 2023

Conversation

mrehan27
Copy link
Contributor

helps: https://github.com/customerio/issues/issues/11609

Changes

  • Removed unused initialize from DataPipeline
  • Updated DataPipelineImplementation to set device attributes using analytics
  • Removed device attributes and token implementation from CustomerIOImplementation

@mrehan27 mrehan27 self-assigned this Dec 13, 2023
Copy link

github-actions bot commented Dec 13, 2023

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


  • CocoaPods-FCM: Build failed. See CI job logs to determine the issue and try re-building.
  • APN-UIKit: rehan/cdp-register-token (1702660730)

public static func initialize(
writeKey: String,
configure configureHandler: ((inout DataPipelineConfigOptions) -> Void)? = nil
) -> CustomerIOInstance {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this as we are now using DataPipeline.initialize(moduleConfig: DataPipelineConfigOptions)

private func initialize() {
if let token = globalDataStore.pushDeviceToken {
// if the device token exists, pass it to the plugin to ensure device attributes are updated with each request
setDeviceToken(token)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't able to test complete flow because Journey implementation is not yet complete. But testing with assumptions and looking at code, it looks like segment is storing token only in memory, so we apparently need to pass it on every app launch.

Adds device default and custom attributes and registers device token.
*/
// TODO: Segment doesn't provide this method by default needs to get added
private func addDeviceAttributes(deviceToken: String, customAttributes: [String: Any] = [:]) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With DataPipelineImplementation handling all this stuff, we may completely remove CustomerIOImplementation, but doing it in phases so it is easier for us to make sure we aren't ignoring anything unknowingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: We will be keeping CustomerIOImplementation as it will help us keep the same experience for existing users without impacting customer coming from Segment.

@mrehan27 mrehan27 requested a review from a team December 13, 2023 08:20
@mrehan27 mrehan27 marked this pull request as ready for review December 13, 2023 08:20
}

private func initialize() {
if let token = globalDataStore.pushDeviceToken {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might not need do it anymore with journeys inclusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed this on call, will decide after discussing more with team. Looks good for now.

@@ -6,24 +6,31 @@ class DeviceAttributes: Plugin {
public let type = PluginType.before
public weak var analytics: Analytics?

public var token: String?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are now not using segment plugin for token and relying on our plugin instead

@@ -6,6 +6,7 @@ SHELL = /bin/sh
# imports - Import statements to be at the top of the generated files in case the file needs classes from other modules. Split by `-` (example: `imports=Cio-Foo-Bar`)
generate:
./binny sourcery --sources Sources/Common --templates Sources/Templates --output Sources/Common/autogenerated
./binny sourcery --sources Sources/DataPipeline --templates Sources/Templates --output Sources/DataPipeline/autogenerated --args imports=CioInternalCommon
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this for DeviceAttributesProvider

@@ -57,4 +57,7 @@ public struct DataPipelineConfigOptions {
public var flushQueue: DispatchQueue = .init(label: "com.segment.operatingModeQueue", qos: .utility)
public var operatingMode: OperatingMode = .asynchronous
public var trackApplicationLifecycleEvents: Bool = true

/// Configuration options for users to easily add available plugins
public var autoTrackDeviceAttributes: Bool = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION

This option might be new for analytics users, but same for Customer.io users. And analytics would still be adding some attributes, should we stop them too or remove this config completely?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you ask this in the slack channel? I want to make sure it doesn't go unanswered.

onComplete([:])
return
}

var deviceAttributes = [
"cio_sdk_version": getSdkVersionAttribute(),
"cio_sdk_version": deviceInfo.sdkVersion,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because wrappers will have their own analytics implementation, I think we can simply refer sdkVersion now

Comment on lines -228 to -244
guard let identifier = profileStore.identifier else {
logger.info("no profile identified, so not registering device token to a profile")
return
}
if identifier.isBlankOrEmpty() {
logger.error("profile cannot be identified: Identifier is empty, so not registering device token to a profile")
return
}

// OS name might not be available if running on non-apple product. We currently only support iOS for the SDK
// and iOS should always be non-nil. Though, we are consolidating all Apple platforms under iOS but this check
// is
// required to prevent SDK execution for unsupported OS.
if deviceInfo.osName == nil {
logger.info("SDK being executed from unsupported OS. Ignoring request to register push token.")
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are no longer blocking token calls on these checks because

  • Device token can now be attached before profile is identified
  • analytics doesn't prevent unknown OS names from registering token, so to keep analytics user unaffected, we are no longer blocking this. However, if needed for we can keep this check in CustomerIOImplementation.swift with slight changes

Comment on lines -284 to -294
guard let existingDeviceToken = globalDataStore.pushDeviceToken else {
logger.info("no device token exists so ignoring request to delete")
return // no device token to delete, ignore request
}
// Do not delete push token from device storage. The token is valid
// once given to SDK. We need it for future profile identifications.

guard let identifiedProfileId = profileStore.identifier else {
logger.info("no profile identified so not removing device token from profile")
return // no profile to delete token from, ignore request
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, no checks because analytics doesn't do that either. And customers may still want to reset data for anonymous users.

@mrehan27 mrehan27 requested a review from Shahroz16 December 14, 2023 14:50
deviceAttributesProvider.getDefaultDeviceAttributes { defaultDeviceAttributes in
let deviceAttributes: [String: Any] = defaultDeviceAttributes
.mergeWith([
"last_used": self.dateUtil.now
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed platform as it causes issues on server side, we no longer need it

@mrehan27
Copy link
Contributor Author

Device and metric events json have been verified. Merging this as the changes are required on other branches for testing and code changes.

@mrehan27 mrehan27 merged commit 4ff70b0 into main-replica-for-cdp Dec 15, 2023
@mrehan27 mrehan27 deleted the rehan/cdp-register-token branch December 15, 2023 17:27
Comment on lines +35 to +38
if let existingDeviceToken = globalDataStore.pushDeviceToken {
// if the device token exists, pass it to the plugin and ensure device attributes are updated
addDeviceAttributes(token: existingDeviceToken)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this logic can be removed once we have the eventbus implemented and the CDP module begins listening to register device token events from the eventbus.

Correct, @Shahroz16?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is true, could we make a TODO or something to document this change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will need to see the use-case as its using a plugin, i probably transforming data on basis of event.

Comment on lines +15 to +17
guard var workingEvent = event,
var context = workingEvent.context?.dictionaryValue
else { return event }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this doing? From reading it, I don't understand what this code is for?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transforming the data, if you look into the payload expected by CDP and generated by SDK that might help in understand it more.

Raw Event already has a json, which has context and other json object in it. This plugin updates the values of context json object.

}
} catch {
analytics?.reportInternalError(error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this file is code that we wrote, I was expecting to use the CIO logger, logger.error(). Could that work better?

Ahmed-PublicCIO pushed a commit to Ahmed-PublicCIO/customerio-ios that referenced this pull request Dec 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants