diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Constants/UnityNativeConstants.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Constants/UnityNativeConstants.cs index 7d606d2..7a53551 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Constants/UnityNativeConstants.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Constants/UnityNativeConstants.cs @@ -1,4 +1,5 @@ #if (!UNITY_IOS && !UNITY_ANDROID) || UNITY_EDITOR +using System; using System.Collections.Generic; using System.Linq; @@ -166,13 +167,13 @@ internal static class EventMeta { internal const string CAMPAIGN = "campaign"; internal const string REF = "ref"; internal const string WZRK_REF = "wzrk_ref"; + internal const string DISCARDED_EVENT_JSON_KEY = "d_e"; } internal static class Validator { internal const int MAX_KEY_CHARS = 120; internal const int MAX_VALUE_CHARS = 1024; internal const int MAX_VALUE_PROPERTY_ARRAY_COUNT = 100; - internal static readonly IReadOnlyList KEY_NOT_ALLOWED_CHARS = new List { ".", ":", "$", "'", "\"", "\\" }; internal static readonly IReadOnlyList VALUE_NOT_ALLOWED_CHARS = new List { "'", "\"", "\\" }; @@ -216,6 +217,9 @@ internal static class Network { #endif internal const string REQUEST_PATH_USER_VARIABLES = "defineVars"; internal const string REQUEST_PATH_HAND_SHAKE = "hello"; + + internal const string ARP_NAMESPACE_KEY = "ARP:{0}:{1}"; + internal const string ARP_KEY = "arp"; } internal static class Commands { diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeBaseEventBuilder.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeBaseEventBuilder.cs index 42201ad..cc92732 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeBaseEventBuilder.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeBaseEventBuilder.cs @@ -9,11 +9,13 @@ internal class UnityNativeEventBuilder { private UnityNativeDeviceInfo _deviceInfo; private UnityNativeSessionManager _sessionManager; private UnityNativeNetworkEngine _networkEngine; - - internal UnityNativeEventBuilder(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine) { + private UnityNativeEventValidator _eventValidator; + + internal UnityNativeEventBuilder(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, UnityNativeEventValidator eventValidator) { _deviceInfo = coreState.DeviceInfo; _sessionManager = coreState.SessionManager; _networkEngine = networkEngine; + _eventValidator = eventValidator; } internal Dictionary BuildEvent(UnityNativeEventType eventType, Dictionary eventDetails) { diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeRaisedEventBuilder.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeRaisedEventBuilder.cs index f947e98..87101c8 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeRaisedEventBuilder.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/EventBuilders/UnityNativeRaisedEventBuilder.cs @@ -5,8 +5,11 @@ namespace CleverTapSDK.Native { internal class UnityNativeRaisedEventBuilder { - internal UnityNativeRaisedEventBuilder() { } - + private UnityNativeEventValidator _eventValidator; + internal UnityNativeRaisedEventBuilder(UnityNativeEventValidator eventValidator) + { + this._eventValidator = eventValidator; + } internal UnityNativeEventBuilderResult> Build(string eventName, Dictionary properties = null) { var eventValidator = new UnityNativeEventValidator(); var eventValidationResultsWithErrors = new List(); @@ -19,6 +22,12 @@ internal UnityNativeEventBuilderResult> Build(string eventValidationResultsWithErrors.Add(isRestrictedNameValidationResult); return new UnityNativeEventBuilderResult>(eventValidationResultsWithErrors, null); } + + var isDiscardedValidationResult = eventValidator.IsEventDiscarded(eventName); + if (!isDiscardedValidationResult.IsSuccess) { + eventValidationResultsWithErrors.Add(isDiscardedValidationResult); + return new UnityNativeEventBuilderResult>(eventValidationResultsWithErrors, null); + } var cleanEventNameValidationResult = eventValidator.CleanEventName(eventName, out var cleanEventName); if (!cleanEventNameValidationResult.IsSuccess) { @@ -33,12 +42,12 @@ internal UnityNativeEventBuilderResult> Build(string return new UnityNativeEventBuilderResult>(eventValidationResultsWithErrors, eventDetails); } - var cleanObjectDictonaryValidationResult = CleanObjectDictonary(properties); - if (cleanObjectDictonaryValidationResult.ValidationResults.Any(vr => !vr.IsSuccess)) { - eventValidationResultsWithErrors.AddRange(cleanObjectDictonaryValidationResult.ValidationResults.Where(vr => !vr.IsSuccess)); + var cleanObjectDictionaryValidationResult = CleanObjectDictonary(properties); + if (cleanObjectDictionaryValidationResult.ValidationResults.Any(vr => !vr.IsSuccess)) { + eventValidationResultsWithErrors.AddRange(cleanObjectDictionaryValidationResult.ValidationResults.Where(vr => !vr.IsSuccess)); } - eventDetails.Add(UnityNativeConstants.Event.EVENT_DATA, cleanObjectDictonaryValidationResult.EventResult); + eventDetails.Add(UnityNativeConstants.Event.EVENT_DATA, cleanObjectDictionaryValidationResult.EventResult); return new UnityNativeEventBuilderResult>(eventValidationResultsWithErrors, eventDetails); } diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs new file mode 100644 index 0000000..268787f --- /dev/null +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using CleverTapSDK.Native; +using CleverTapSDK.Utilities; + +#if (!UNITY_IOS && !UNITY_ANDROID) || UNITY_EDITOR +namespace CleverTapSDK.Native +{ + internal class UnityNativeARPResponseInterceptor : IUnityNativeResponseInterceptor + { + private readonly UnityNativeEventValidator _eventValidator; + private readonly string _accountId; + private readonly string _namespaceARPKey; + public UnityNativeARPResponseInterceptor(string accountId,string deviceId, UnityNativeEventValidator eventValidator) + { + this._accountId = accountId; + this._namespaceARPKey = string.Format(UnityNativeConstants.Network.ARP_NAMESPACE_KEY,accountId,deviceId); + _eventValidator = eventValidator; + } + + UnityNativeResponse IUnityNativeResponseInterceptor.Intercept(UnityNativeResponse response) + { + var result = Json.Deserialize(response.Content) as Dictionary; + try + { + if (result.ContainsKey("arp")) + if (Json.Deserialize(result["arp"].ToString()) is Dictionary { Count: > 0 } arp) + { + //Handle Discarded events in ARP + try + { + ProcessDiscardedEventsList(arp); + } + catch (Exception t) + { + CleverTapLogger.Log("Failed to process ARP discarded events"); + } + + HandleARPUpdate(arp); + } + } + catch (Exception exception) + { + CleverTapLogger.Log("Failed to process ARP"); + } + + return response; + } + + + private void HandleARPUpdate(Dictionary arp) + { + if (arp == null || arp.Count == 0 || string.IsNullOrEmpty(_namespaceARPKey)) + return; + + UnityNativePreferenceManager preferenceManager = UnityNativePreferenceManager.GetPreferenceManager(_accountId); + Dictionary currentARP = Json.Deserialize(preferenceManager.GetString(_namespaceARPKey, "{}")) as Dictionary; + + if (currentARP == null || currentARP.Count == 0) + { + preferenceManager.SetString(_namespaceARPKey, Json.Serialize(arp)); + return; + } + + foreach (var keyValuePair in arp) + { + string key = keyValuePair.Key; + object value = keyValuePair.Value; + + switch (value) + { + case int i: + currentARP[key] = i; + break; + case long l: + currentARP[key] = l; + break; + case float f: + currentARP[key] = f; + break; + case double d: + currentARP[key] = d; + break; + case string s: + currentARP[key] = s; + break; + case bool b: + currentARP[key] = b; + break; + default: + CleverTapLogger.Log($"ARP update for key {key} rejected (invalid data type)"); + break; + } + } + + preferenceManager.SetString(_namespaceARPKey, Json.Serialize(currentARP)); + } + + + private void ProcessDiscardedEventsList(Dictionary response) + { + if (!response.ContainsKey(UnityNativeConstants.EventMeta.DISCARDED_EVENT_JSON_KEY)) + { + CleverTapLogger.Log("ARP doesn't contain the Discarded Events key"); + return; + } + + try + { + var discardedEventsList = new List(); + // Get the discarded event JSON from the response + string discardedEventsJson = response[UnityNativeConstants.EventMeta.DISCARDED_EVENT_JSON_KEY].ToString(); + var discardedEventsArray = Json.Deserialize(discardedEventsJson) as List; + if (discardedEventsArray != null) + { + discardedEventsList.AddRange(discardedEventsArray); + } + if (_eventValidator != null) + _eventValidator.SetDiscardedEvents(discardedEventsList); + else + CleverTapLogger.Log("Validator object is NULL"); + } + catch (Exception e) + { + CleverTapLogger.Log("Error parsing discarded events list" + e.StackTrace); + } + } + } +} +#endif \ No newline at end of file diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs.meta b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs.meta new file mode 100644 index 0000000..0144595 --- /dev/null +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeARPResponseInterceptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7fe26e2d875de4bf7946f93a7f36b770 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeBaseEventQueue.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeBaseEventQueue.cs index cfc1ce6..e1828f7 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeBaseEventQueue.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeBaseEventQueue.cs @@ -26,13 +26,14 @@ internal abstract class UnityNativeBaseEventQueue protected UnityNativeCoreState coreState; protected UnityNativeNetworkEngine networkEngine; - + protected UnityNativeEventValidator eventValidator; private Coroutine timerCoroutine; - internal UnityNativeBaseEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, int queueLimit = 49, int defaultTimerInterval = 1) + internal UnityNativeBaseEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine,UnityNativeEventValidator eventValidator, int queueLimit = 49, int defaultTimerInterval = 1) { this.coreState = coreState; this.networkEngine = networkEngine; + this.eventValidator = eventValidator; this.queueLimit = queueLimit; this.defaultTimerInterval = defaultTimerInterval; eventsQueue = new Queue>(); @@ -163,7 +164,7 @@ internal Dictionary BuildMeta() { { UnityNativeConstants.EventMeta.GUID, deviceInfo.DeviceId }, { UnityNativeConstants.EventMeta.TYPE, UnityNativeConstants.EventMeta.TYPE_NAME }, - { UnityNativeConstants.EventMeta.APPLICATION_FIELDS, new UnityNativeEventBuilder(coreState, networkEngine).BuildAppFields() }, + { UnityNativeConstants.EventMeta.APPLICATION_FIELDS, new UnityNativeEventBuilder(coreState, networkEngine,eventValidator).BuildAppFields() }, { UnityNativeConstants.EventMeta.ACCOUNT_ID, accountInfo.AccountId }, { UnityNativeConstants.EventMeta.ACCOUNT_TOKEN, accountInfo.AccountToken }, { UnityNativeConstants.EventMeta.FIRST_REQUEST_IN_SESSION, coreState.SessionManager.IsFirstSession() } diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeRaisedEventQueue.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeRaisedEventQueue.cs index a0b5da8..f4f6ef5 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeRaisedEventQueue.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeRaisedEventQueue.cs @@ -8,7 +8,8 @@ internal class UnityNativeRaisedEventQueue : UnityNativeBaseEventQueue { protected override string QueueName => "RAISED_EVENTS"; - internal UnityNativeRaisedEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, int queueLimit = 49, int defaultTimerInterval = 1) : base(coreState, networkEngine, queueLimit, defaultTimerInterval) { } + internal UnityNativeRaisedEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, UnityNativeEventValidator eventValidator, int queueLimit = 49, int defaultTimerInterval = 1) : + base(coreState, networkEngine,eventValidator, queueLimit, defaultTimerInterval) { } protected override string RequestPath => UnityNativeConstants.Network.REQUEST_PATH_RECORD; diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeSession.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeSession.cs index 9c5dd70..a49f59d 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeSession.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeSession.cs @@ -31,7 +31,7 @@ internal UnityNativeSession(string accountId) { _lastSessionLength = lastSessionTime - lastSessionId; } - _preferenceManager.SetLong(UnityNativeConstants.Session.SESSION_ID_KEY, _sessionId); + _preferenceManager.SetLong(UnityNativeConstants.Session.SESSION_ID_KEY, _sessionId.ToString()); } internal long SessionId => _sessionId; @@ -46,7 +46,7 @@ internal void SetIsAppLaunched(bool isAppLaunched) { internal long UpdateTimestamp() { long now = GetNow(); - _preferenceManager.SetLong(UnityNativeConstants.Session.LAST_SESSION_TIME_KEY, now); + _preferenceManager.SetLong(UnityNativeConstants.Session.LAST_SESSION_TIME_KEY, now.ToString()); _lastUpdateTimestamp = now; return _lastUpdateTimestamp; } diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeUserEventQueue.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeUserEventQueue.cs index df3224e..b39d4df 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeUserEventQueue.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeUserEventQueue.cs @@ -7,7 +7,7 @@ internal class UnityNativeUserEventQueue : UnityNativeBaseEventQueue { protected override string QueueName => "USER_EVENTS"; - internal UnityNativeUserEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, int queueLimit = 49, int defaultTimerInterval = 1) : base(coreState, networkEngine, queueLimit, defaultTimerInterval) { } + internal UnityNativeUserEventQueue(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, UnityNativeEventValidator eventValidator, int queueLimit = 49, int defaultTimerInterval = 1) : base(coreState, networkEngine, eventValidator, queueLimit, defaultTimerInterval) { } protected override string RequestPath => UnityNativeConstants.Network.REQUEST_PATH_RECORD; diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeValidationResult.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeValidationResult.cs index 6000b56..d4f2f20 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeValidationResult.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Models/UnityNativeValidationResult.cs @@ -1,6 +1,6 @@ #if (!UNITY_IOS && !UNITY_ANDROID) || UNITY_EDITOR namespace CleverTapSDK.Native { - internal class UnityNativeValidationResult { + public class UnityNativeValidationResult { // TODO : Consider converting errorCode into appropriate enumration(Enum) private readonly int? _errorCode; diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventManager.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventManager.cs index 978434f..9daf3f4 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventManager.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventManager.cs @@ -1,5 +1,5 @@ #if (!UNITY_IOS && !UNITY_ANDROID) || UNITY_EDITOR -using CleverTapSDK.Common; +using CleverTapSDK.Common; using CleverTapSDK.Utilities; using System; using System.Collections; @@ -18,6 +18,7 @@ internal class UnityNativeEventManager { private UnityNativeCallbackHandler _callbackHandler; private UnityNativeCoreState _coreState; private UnityNativeNetworkEngine _networkEngine; + private UnityNativeEventValidator _eventValidator; private string _accountId; private int _enableNetworkInfoReporting = -1; @@ -33,10 +34,19 @@ private void Initialize(string accountId, string token, string region = null) _preferenceManager = UnityNativePreferenceManager.GetPreferenceManager(_accountId); _databaseStore = new UnityNativeDatabaseStore($"{_accountId}_{NATIVE_EVENTS_DB_CACHE}"); - _networkEngine = UnityNativeNetworkEngine.Create(_accountId); - _eventQueueManager = new UnityNativeEventQueueManager(_coreState, _networkEngine, _databaseStore); + _eventValidator = new UnityNativeEventValidator(); + _networkEngine = UnityNativeNetworkEngine.Create(_coreState); + SetResponseInterceptors(); + _eventQueueManager = new UnityNativeEventQueueManager(_coreState, _networkEngine, _databaseStore,_eventValidator); } + private void SetResponseInterceptors() + { + List responseInterceptors = new List(); + responseInterceptors.Add(new UnityNativeARPResponseInterceptor(_accountId,_coreState.DeviceInfo.DeviceId,_eventValidator)); + _networkEngine.SetResponseInterceptors(responseInterceptors); + } + #region Launch internal void LaunchWithCredentials(string accountId, string token, string region = null) { @@ -170,6 +180,7 @@ private void SwitchOrCreateProfile(Dictionary profile, string ca _coreState.DeviceInfo.ForceNewDeviceID(); } + SetResponseInterceptors(); NotifyUserProfileInitialized(); RecordAppLaunch(); @@ -290,7 +301,7 @@ internal UnityNativeEvent RecordEvent(string eventName, Dictionary eventDetails, bool storeEvent = true) { - var eventData = new UnityNativeEventBuilder(_coreState, _networkEngine).BuildEvent(eventType, eventDetails); + var eventData = new UnityNativeEventBuilder(_coreState, _networkEngine,_eventValidator).BuildEvent(eventType, eventDetails); var eventDataJSONContent = Json.Serialize(eventData); var @event = new UnityNativeEvent(eventType, eventDataJSONContent); if (storeEvent) @@ -342,7 +353,7 @@ private UnityNativeEvent BuildEvent(UnityNativeEventType eventType, Dictionary eventDetails, bool storeEvent = true) { - var eventData = new UnityNativeEventBuilder(_coreState, _networkEngine).BuildEventWithAppFields(eventType, eventDetails); + var eventData = new UnityNativeEventBuilder(_coreState, _networkEngine,_eventValidator).BuildEventWithAppFields(eventType, eventDetails); var eventDataJSONContent = Json.Serialize(eventData); var @event = new UnityNativeEvent(eventType, eventDataJSONContent); if (storeEvent) diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventQueueManager.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventQueueManager.cs index b408219..3ff9486 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventQueueManager.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeEventQueueManager.cs @@ -9,12 +9,12 @@ internal class UnityNativeEventQueueManager { private readonly UnityNativeBaseEventQueue _userEventsQueue; private readonly UnityNativeBaseEventQueue _raisedEventsQueue; - internal UnityNativeEventQueueManager(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, UnityNativeDatabaseStore databaseStore) { + internal UnityNativeEventQueueManager(UnityNativeCoreState coreState, UnityNativeNetworkEngine networkEngine, UnityNativeDatabaseStore databaseStore, UnityNativeEventValidator eventValidator) { _databaseStore = databaseStore; _databaseStore.OnEventStored += OnDatabaseEventStored; - _userEventsQueue = new UnityNativeUserEventQueue(coreState, networkEngine); + _userEventsQueue = new UnityNativeUserEventQueue(coreState, networkEngine,eventValidator); _userEventsQueue.OnEventTimerTick += OnUserEventTimerTick; - _raisedEventsQueue = new UnityNativeRaisedEventQueue(coreState, networkEngine); + _raisedEventsQueue = new UnityNativeRaisedEventQueue(coreState, networkEngine,eventValidator); _raisedEventsQueue.OnEventTimerTick += OnRaisedEventTimerTick; // Add the events stored in the DB _databaseStore.AddEventsFromDB(); diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeNetworkEngine.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeNetworkEngine.cs index 3c8dee3..fe46ff7 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeNetworkEngine.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativeNetworkEngine.cs @@ -12,6 +12,7 @@ namespace CleverTapSDK.Native { internal class UnityNativeNetworkEngine : MonoBehaviour { private SynchronizationContext _context; + private UnityNativeCoreState _coreState; private void Awake() { _context = SynchronizationContext.Current; @@ -86,14 +87,16 @@ public Task RunOnMainThread(Func> function) private UnityNativeNetworkEngine() { } - internal static UnityNativeNetworkEngine Create(string accountId) + internal static UnityNativeNetworkEngine Create(UnityNativeCoreState coreState) { - var gameObject = new GameObject($"{accountId}_UnityNativeNetworkEngine"); + var gameObject = new GameObject($"{coreState.AccountInfo.AccountId}_UnityNativeNetworkEngine"); gameObject.AddComponent(); DontDestroyOnLoad(gameObject); UnityNativeNetworkEngine component = gameObject.GetComponent(); - component._preferenceManager = UnityNativePreferenceManager.GetPreferenceManager(accountId); + component._preferenceManager = UnityNativePreferenceManager.GetPreferenceManager(coreState.AccountInfo.AccountId); + + component._coreState = coreState; return gameObject.GetComponent(); } @@ -287,18 +290,21 @@ private async Task ExecuteRequestAfterHandshake(UnityNative private void ApplyNetworkEngineRequestConfiguration(UnityNativeRequest request) { // Set Headers if (_headers?.Count > 0) { + var allHeaders = new Dictionary(_headers); if (request.Headers == null) { - request.SetHeaders(_headers.ToDictionary(x => x.Key, x => x.Value)); + allHeaders = _headers.ToDictionary(x => x.Key, x => x.Value); } else { - var allHeaders = request.Headers.ToDictionary(x => x.Key, x => x.Value); + allHeaders = request.Headers.ToDictionary(x => x.Key, x => x.Value); foreach (var header in _headers) { // Do not overwrite existing headers if (!allHeaders.ContainsKey(header.Key)) { allHeaders.Add(header.Key, header.Value); } } - request.SetHeaders(allHeaders); } + //Add ARP + allHeaders = AddARP(allHeaders); + request.SetHeaders(allHeaders); } // Set Timeout @@ -334,6 +340,42 @@ private void ApplyNetworkEngineRequestConfiguration(UnityNativeRequest request) } } + private Dictionary AddARP(Dictionary headers) + { + string arpNamespaceKey = string.Format(UnityNativeConstants.Network.ARP_NAMESPACE_KEY, + _coreState.AccountInfo.AccountId, _coreState.DeviceInfo.DeviceId); + var arpJson = _preferenceManager.GetString(arpNamespaceKey, string.Empty); + if (string.IsNullOrEmpty(arpJson)) + return headers; + + Dictionary arpDictionary = Json.Deserialize(arpJson) as Dictionary; + if (arpDictionary == null || arpDictionary.Count == 0) + return headers; + + var keysToRemove = new List(); + + foreach (var param in arpDictionary) + { + if (param.Value is string strValue && strValue.Length > 100) + { + keysToRemove.Add(param.Key); + } + else if (param.Value is int intValue && intValue == -1) + { + keysToRemove.Add(param.Key); + } + } + + foreach (var key in keysToRemove) + { + arpDictionary.Remove(key); + } + + headers[UnityNativeConstants.Network.ARP_KEY] = Json.Serialize(arpDictionary); + + return headers; + } + private async Task SendRequest(UnityNativeRequest request) { if (Application.internetReachability == NetworkReachability.NotReachable) { diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativePreferenceManager.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativePreferenceManager.cs index 1a851af..671daf3 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativePreferenceManager.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/UnityNativePreferenceManager.cs @@ -1,5 +1,6 @@ #if (!UNITY_IOS && !UNITY_ANDROID) || UNITY_EDITOR using System.Collections.Generic; +using System.Globalization; using CleverTapSDK.Utilities; using UnityEngine; @@ -58,12 +59,30 @@ internal long GetLong(string key, long defaultValue) return long.Parse(PlayerPrefs.GetString(GetStorageKey(key), defaultValue.ToString())); } - internal void SetLong(string key, long value) + internal void SetLong(string key, string longValue) { - // Use string to set long values in PlayerPrefs - PlayerPrefs.SetString(GetStorageKey(key), value.ToString()); + PlayerPrefs.SetString(GetStorageKey(key), longValue); } + public void SetDouble(string key, string doubleValue) + { + PlayerPrefs.SetString(GetStorageKey(key), doubleValue.ToString()); + } + + public double GetDouble(string key, double defaultValue) + { + return double.Parse(PlayerPrefs.GetString(GetStorageKey(key), defaultValue.ToString(CultureInfo.InvariantCulture))); + } + public void SetBool(string key, int value) + { + PlayerPrefs.SetInt(GetStorageKey(key), value); + } + + public bool GetBool(string key, bool defaultValue) + { + return PlayerPrefs.GetInt(GetStorageKey(key), defaultValue? 1 : 0) == 1; + } + internal void DeleteKey(string key) { PlayerPrefs.DeleteKey(GetStorageKey(key)); @@ -114,12 +133,13 @@ internal void SetGUIDForIdentifier(string guid, string key, string identifier) { } internal string GetKeyIdentifier(string key, string identifier) { - return string.Format("{0}_{1}", key, identifier); + return $"{key}_{identifier}"; } internal string GetStorageKey(string suffix) { return $"{_accountId}:{suffix}"; } + } } #endif \ No newline at end of file diff --git a/CleverTap/Runtime/Native/UnityNativeWrapper/Validators/UnityNativeEventValidator.cs b/CleverTap/Runtime/Native/UnityNativeWrapper/Validators/UnityNativeEventValidator.cs index 8b05529..ec9bd32 100644 --- a/CleverTap/Runtime/Native/UnityNativeWrapper/Validators/UnityNativeEventValidator.cs +++ b/CleverTap/Runtime/Native/UnityNativeWrapper/Validators/UnityNativeEventValidator.cs @@ -4,11 +4,13 @@ using System.Linq; namespace CleverTapSDK.Native { - internal class UnityNativeEventValidator { + public class UnityNativeEventValidator { + private List discardedEvents; + internal UnityNativeValidationResult CleanEventName(string eventName, out string cleanEventName) { cleanEventName = eventName; if (string.IsNullOrWhiteSpace(cleanEventName)) { - return new UnityNativeValidationResult(); + return new UnityNativeValidationResult(510, "Event name is null or empty."); } cleanEventName = ReplaceNotAllowedCharacters(cleanEventName, UnityNativeConstants.Validator.KEY_NOT_ALLOWED_CHARS); @@ -57,7 +59,7 @@ internal UnityNativeValidationResult CleanMultiValuePropertyKey(string multiValu } internal UnityNativeValidationResult CleanMultiValuePropertyValue(string multiValuePropertyValue, out string cleanMultiValuePropertyValue) { - return CleanProperyValue(multiValuePropertyValue, out cleanMultiValuePropertyValue); + return CleanPropertyValue(multiValuePropertyValue, out cleanMultiValuePropertyValue); } internal UnityNativeValidationResult CleanMultiValuePropertyArray(List multiValuePropertyArray, out List cleanMultiValuePropertyArray, string key) { @@ -82,7 +84,7 @@ internal UnityNativeValidationResult CleanObjectValue(object objectValue, out ob } if (cleanObjectValue is string) { - var validationResult = CleanProperyValue((string)cleanObjectValue, out var cleanObjectValueString); + var validationResult = CleanPropertyValue((string)cleanObjectValue, out var cleanObjectValueString); cleanObjectValue = cleanObjectValueString; return validationResult; } @@ -127,16 +129,16 @@ internal UnityNativeValidationResult IsRestrictedName(string eventName) { return new UnityNativeValidationResult(); } - private UnityNativeValidationResult CleanProperyValue(string propertyValue, out string cleanProperyValue) { - cleanProperyValue = propertyValue; - if (string.IsNullOrWhiteSpace(cleanProperyValue)) { + private UnityNativeValidationResult CleanPropertyValue(string propertyValue, out string cleanPropertyValue) { + cleanPropertyValue = propertyValue; + if (string.IsNullOrWhiteSpace(cleanPropertyValue)) { return new UnityNativeValidationResult(); } - cleanProperyValue = ReplaceNotAllowedCharacters(cleanProperyValue, UnityNativeConstants.Validator.VALUE_NOT_ALLOWED_CHARS, toLower: true); - if (cleanProperyValue.Length > UnityNativeConstants.Validator.MAX_VALUE_CHARS) { - cleanProperyValue = cleanProperyValue.Substring(0, UnityNativeConstants.Validator.MAX_VALUE_CHARS); - return new UnityNativeValidationResult(521, $"{cleanProperyValue}... exceeds the limit of {UnityNativeConstants.Validator.MAX_VALUE_CHARS} characters. Trimmed"); + cleanPropertyValue = ReplaceNotAllowedCharacters(cleanPropertyValue, UnityNativeConstants.Validator.VALUE_NOT_ALLOWED_CHARS, toLower: true); + if (cleanPropertyValue.Length > UnityNativeConstants.Validator.MAX_VALUE_CHARS) { + cleanPropertyValue = cleanPropertyValue.Substring(0, UnityNativeConstants.Validator.MAX_VALUE_CHARS); + return new UnityNativeValidationResult(521, $"{cleanPropertyValue}... exceeds the limit of {UnityNativeConstants.Validator.MAX_VALUE_CHARS} characters. Trimmed"); } return new UnityNativeValidationResult(); @@ -166,6 +168,46 @@ private bool IsAnyNumericType(object o) { return o is short || o is int || o is long || o is float || o is double || o is decimal; } + + /** + * Checks whether the specified event name has been discarded from Dashboard. If it is, + * then create a pending error, and abort. + * + * @param name The event name + * @return Boolean indication whether the event name has been discarded from Dashboard + */ + public UnityNativeValidationResult IsEventDiscarded(string eventName) + { + if (string.IsNullOrEmpty(eventName)) + { + return new UnityNativeValidationResult(510, $"event name is null or empty."); + } + + UnityNativeValidationResult error = new UnityNativeValidationResult(); + + var discardedEvents = GetDiscardedEvents(); + if (discardedEvents != null) + { + foreach (string x in discardedEvents) + { + if (string.Equals(eventName, x, StringComparison.OrdinalIgnoreCase)) + { + return new UnityNativeValidationResult(513, + $"{eventName} is restricted event name. Last event aborted."); + } + } + } + + return error; + } + + private List GetDiscardedEvents() + { + return discardedEvents; + } + + public void SetDiscardedEvents(List events) => this.discardedEvents = events; } + } #endif \ No newline at end of file