Пример #1
0
        private List <Variation> GetWhiteListedVariationsList(string apiName, string userId, BucketedCampaign campaign, string campaignKey, Dictionary <string, dynamic> customVariables, Dictionary <string, dynamic> variationTargetingVariables)
        {
            List <Variation> result = new List <Variation> {
            };

            foreach (var variation in campaign.Variations.All())
            {
                string status           = Constants.SegmentationStatus.FAILED;
                string segmentationType = Constants.SegmentationType.WHITELISTING;
                if (variation.Segments.Count == 0)
                {
                    LogDebugMessage.SkippingSegmentation(typeof(IVWOClient).FullName, userId, campaignKey, apiName, variation.Name);
                }
                else
                {
                    if (this._segmentEvaluator.evaluate(userId, campaignKey, segmentationType, variation.Segments, variationTargetingVariables))
                    {
                        status = Constants.SegmentationStatus.PASSED;
                        result.Add(variation);
                    }
                    LogDebugMessage.SegmentationStatus(typeof(IVWOClient).FullName, userId, campaignKey, apiName, variation.Name, status);
                }
            }
            return(result);
        }
        public double ComputeBucketValue(string userId, double maxVal, double multiplier, out double hashValue)
        {
            byte[] hash = this._murmur32.ComputeHash(Encoding.UTF8.GetBytes(userId));
            hashValue = BitConverter.ToUInt32(hash, 0);
            var bucketValue = Compute(hashValue, maxVal, multiplier);

            LogDebugMessage.UserHashBucketValue(file, userId, hashValue, bucketValue);
            return(bucketValue);
        }
Пример #3
0
        /// <summary>
        /// Allocate variation by checking UserStorageService, Campaign Traffic Allocation and compute UserHash to check variation allocation by bucketing.
        /// </summary>
        /// <param name="campaignKey"></param>
        /// <param name="userId"></param>
        /// <param name="apiName"></param>
        /// <param name="campaign"></param>
        /// <param name="customVariables"></param>
        /// <param name="variationTargetingVariables"></param>
        /// <returns>
        /// If Variation is allocated, returns UserAssignedInfo with valid details, else return Empty UserAssignedInfo.
        /// </returns>
        private UserAllocationInfo AllocateVariation(string campaignKey, string userId, BucketedCampaign campaign, Dictionary <string, dynamic> customVariables, Dictionary <string, dynamic> variationTargetingVariables, string apiName = null)
        {
            Variation TargettedVariation = this.FindTargetedVariation(apiName, campaign, campaignKey, userId, customVariables, variationTargetingVariables);

            if (TargettedVariation != null)
            {
                return(new UserAllocationInfo(TargettedVariation, campaign));
            }

            UserStorageMap   userStorageMap   = this._userStorageService.GetUserMap(campaignKey, userId);
            BucketedCampaign selectedCampaign = this._campaignAllocator.Allocate(this._settings, userStorageMap, campaignKey, userId, apiName);

            if (userStorageMap != null && userStorageMap.VariationName != null)
            {
                Variation variation = this._variationAllocator.GetSavedVariation(campaign, userStorageMap.VariationName.ToString());
                return(new UserAllocationInfo(variation, selectedCampaign));
            }
            if (selectedCampaign != null)
            {
                Variation variation = this._variationAllocator.Allocate(userStorageMap, selectedCampaign, userId);
                if (variation != null)
                {
                    if (campaign.Segments.Count > 0)
                    {
                        string segmentationType = Constants.SegmentationType.PRE_SEGMENTATION;
                        if (customVariables == null)
                        {
                            LogInfoMessage.NoCustomVariables(typeof(IVWOClient).FullName, userId, campaignKey, apiName);
                            customVariables = new Dictionary <string, dynamic>();
                        }
                        if (variationTargetingVariables == null)
                        {
                            variationTargetingVariables = new Dictionary <string, dynamic>();
                        }
                        if (!this._segmentEvaluator.evaluate(userId, campaignKey, segmentationType, campaign.Segments, customVariables))
                        {
                            return(new UserAllocationInfo());
                        }
                    }
                    else
                    {
                        LogInfoMessage.SkippingPreSegmentation(typeof(IVWOClient).FullName, userId, campaignKey, apiName);
                    }
                    LogInfoMessage.VariationAllocated(file, userId, campaignKey, variation.Name);
                    LogDebugMessage.GotVariationForUser(file, userId, campaignKey, variation.Name, nameof(AllocateVariation));

                    this._userStorageService.SetUserMap(userId, selectedCampaign.Key, variation.Name);
                    return(new UserAllocationInfo(variation, selectedCampaign));
                }
            }

            LogInfoMessage.NoVariationAllocated(file, userId, campaignKey);
            return(new UserAllocationInfo());
        }
Пример #4
0
        public static string Compute(long accountId, string userId)
        {
            var accountIdAsString = accountId.ToString();
            var vwoNamespaceGuid  = Identifiable.NamedGuid.Compute(NamedGuidAlgorithm.SHA1, UrlNamespace, VWO_NAMESPACE_URL);
            var accountIdGuid     = NamedGuid.Compute(NamedGuidAlgorithm.SHA1, vwoNamespaceGuid, accountIdAsString);
            var userIdGuid        = NamedGuid.Compute(NamedGuidAlgorithm.SHA1, accountIdGuid, userId);
            var uuid = userIdGuid.ToString(GUID_FORMAT).ToUpper();

            LogDebugMessage.UuidForUser(file, userId, accountId, uuid);
            return(uuid);
        }
Пример #5
0
        //Event Batching
        internal static ApiRequest EventBatching(long accountId, bool isDevelopmentMode, string sdkKey)
        {
            string queryParams      = GetQueryParamertersForEventBatching(accountId);
            var    trackUserRequest = new ApiRequest(Method.POST, isDevelopmentMode)
            {
                Uri    = new Uri($"{Host}/{Verb}/{BatchEventVerb}?{queryParams}&{GetSdkKeyQuery(sdkKey)}"),
                logUri = new Uri($"{Host}/{Verb}/{BatchEventVerb}?{queryParams}"),
            };

            LogDebugMessage.ImpressionForBatchEvent(file, queryParams);
            return(trackUserRequest);
        }
Пример #6
0
        internal static ApiRequest TrackGoal(int accountId, int campaignId, int variationId, string userId, int goalId, string revenueValue, bool isDevelopmentMode)
        {
            string queryParams      = GetQueryParamertersForTrackGoal(accountId, campaignId, variationId, userId, goalId, revenueValue);
            var    trackUserRequest = new ApiRequest(Method.GET, isDevelopmentMode)
            {
                Uri = new Uri($"{Host}/{Verb}/{TrackGoalVerb}?{queryParams}"),
            };

            trackUserRequest.WithCaller(AppContext.ApiCaller);
            LogDebugMessage.ImpressionForTrackGoal(file, queryParams);
            return(trackUserRequest);
        }
Пример #7
0
        internal static ApiRequest PushTags(AccountSettings settings, string tagKey, string tagValue, string userId, bool isDevelopmentMode)
        {
            string queryParams      = GetQueryParamertersForPushTag(settings, tagKey, tagValue, userId);
            var    trackPushRequest = new ApiRequest(Method.GET, isDevelopmentMode)
            {
                Uri = new Uri($"{Host}/{Verb}/{PushTagsVerb}?{queryParams}"),
            };

            trackPushRequest.WithCaller(AppContext.ApiCaller);
            LogDebugMessage.ImpressionForPushTag(file, queryParams);
            return(trackPushRequest);
        }
Пример #8
0
        internal static ApiRequest TrackUser(long accountId, int campaignId, int variationId, string userId, bool isDevelopmentMode, string sdkKey)
        {
            string queryParams      = GetQueryParamertersForTrackUser(accountId, campaignId, variationId, userId);
            var    trackUserRequest = new ApiRequest(Method.GET, isDevelopmentMode)
            {
                Uri    = new Uri($"{Host}/{Verb}/{TrackUserVerb}?{queryParams}&{GetSdkKeyQuery(sdkKey)}"),
                logUri = new Uri($"{Host}/{Verb}/{TrackUserVerb}?{queryParams}"),
            };

            trackUserRequest.WithCaller(AppContext.ApiCaller);
            LogDebugMessage.ImpressionForTrackUser(file, queryParams);
            return(trackUserRequest);
        }
Пример #9
0
        /// <summary>
        /// Allocate Variation by checking previously assigned variation if userStorageMap is provided, else by computing User Hash and matching it in bucket for eligible variation.
        /// </summary>
        /// <param name="userStorageMap"></param>
        /// <param name="campaign"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public Variation Allocate(UserStorageMap userStorageMap, BucketedCampaign campaign, string userId)
        {
            if (campaign == null)
            {
                return(null);
            }

            if (userStorageMap == null)
            {
                double maxVal            = Constants.Variation.MAX_TRAFFIC_VALUE;
                double multiplier        = maxVal / campaign.PercentTraffic / 100; ///This is to evenly spread all user among variations.
                var    bucketValue       = this._userHasher.ComputeBucketValue(userId, maxVal, multiplier, out double hashValue);
                var    selectedVariation = campaign.Variations.Find(bucketValue);
                LogDebugMessage.VariationHashBucketValue(file, userId, campaign.Key, campaign.PercentTraffic, hashValue, bucketValue);
                return(selectedVariation);
            }

            return(campaign.Variations.Find(userStorageMap.VariationName, GetVariationName));
        }
Пример #10
0
        internal void SetUserMap(string userId, string campaignKey, string variationName, string goalIdentifier = null)
        {
            if (this._userStorageService == null)
            {
                LogDebugMessage.NoUserStorageServiceSet(file);
                return;
            }

            try
            {
                this._userStorageService.Set(new UserStorageMap(userId, campaignKey, variationName, goalIdentifier));
                LogInfoMessage.SavingDataUserStorageService(file, userId);
                return;
            }
            catch (Exception ex)
            {
                LogErrorMessage.SetUserStorageServiceFailed(file, userId);
            }
        }
Пример #11
0
 /// <summary>
 /// Init variables in BatchEventQueue.
 /// </summary>
 /// <param name="batchEvents">BatchEventsData instance</param>
 /// <param name="apikey">VWO application apikey</param>
 /// <param name="accountId">VWO application accountId</param>
 /// <param name="isDevelopmentMode">isDevelopmentMode Boolean value specifying development mode is on ir off</param>
 internal BatchEventQueue(BatchEventData batchEvents, string apikey, int accountId, bool isDevelopmentMode)
 {
     if (batchEvents != null)
     {
         if (batchEvents.RequestTimeInterval != null)
         {
             if (batchEvents.RequestTimeInterval > 1)
             {
                 this.requestTimeInterval = (int)batchEvents.RequestTimeInterval;
             }
             else
             {
                 LogDebugMessage.RequestTimeIntervalOutOfBound(file, 1, requestTimeInterval);
             }
         }
         else
         {
             LogDebugMessage.RequestTimeIntervalOutOfBound(file, 1, requestTimeInterval);
         }
         if (batchEvents.EventsPerRequest != null)
         {
             if (batchEvents.EventsPerRequest > 0 && batchEvents.EventsPerRequest <= MAX_EVENTS_PER_REQUEST)
             {
                 this.eventsPerRequest = Math.Min((int)batchEvents.EventsPerRequest, MAX_EVENTS_PER_REQUEST);
             }
             else
             {
                 LogDebugMessage.EventsPerRequestOutOfBound(file, 1, MAX_EVENTS_PER_REQUEST, eventsPerRequest);
             }
         }
         else
         {
             LogDebugMessage.EventsPerRequestOutOfBound(file, 1, MAX_EVENTS_PER_REQUEST, eventsPerRequest);
         }
         if (batchEvents.FlushCallback != null)
         {
             this.flushCallback = batchEvents.FlushCallback;
         }
     }
     this.accountId         = accountId;
     this.isDevelopmentMode = isDevelopmentMode;
     this.apikey            = apikey;
 }
        internal void SaveUserMap(string userId, string campaignTestKey, string variationName)
        {
            if (this._userProfileService == null)
            {
                LogDebugMessage.NoUserProfileServiceSave(file);
                return;
            }

            try
            {
                LogInfoMessage.SavingDataUserProfileService(file, userId);
                this._userProfileService.Save(new UserProfileMap(userId, campaignTestKey, variationName));
                return;
            }
            catch (Exception ex)
            {
                LogErrorMessage.SaveUserProfileServiceFailed(file, userId);
            }
        }
Пример #13
0
        /// <summary>
        /// If UserStorageService is provided, Calls Get for given UserId and validate the result.
        /// </summary>
        /// <param name="campaignKey"></param>
        /// <param name="userId"></param>
        /// <param name="userStorageData"></param>
        /// <returns>
        /// Returns userStorageMap if validation is success, else null.
        /// </returns>
        internal UserStorageMap GetUserMap(string campaignKey, string userId, Dictionary <string, dynamic> userStorageData = null)
        {
            if (this._userStorageService == null)
            {
                LogDebugMessage.NoUserStorageServiceGet(file);
                return(null);
            }

            UserStorageMap userMap = TryGetUserMap(userId, campaignKey, userStorageData);

            if (userMap == null || string.IsNullOrEmpty(userMap.CampaignKey) ||
                string.IsNullOrEmpty(userMap.VariationName) || string.IsNullOrEmpty(userMap.UserId) ||
                string.Equals(userMap.UserId, userId) == false || string.Equals(userMap.CampaignKey, campaignKey) == false)
            {
                LogDebugMessage.NoStoredVariation(file, userId, campaignKey);
                return(null);
            }
            LogInfoMessage.GotStoredVariation(file, userMap.VariationName, campaignKey, userId);
            return(userMap);
        }
        /// <summary>
        /// If UserProfileService is provided, Calls Lookup for given UserId and validate the result.
        /// </summary>
        /// <param name="campaignTestKey"></param>
        /// <param name="userId"></param>
        /// <returns>
        /// Returns userProfileMap if validation is success, else null.
        /// </returns>
        internal UserProfileMap GetUserMap(string campaignTestKey, string userId)
        {
            if (this._userProfileService == null)
            {
                LogDebugMessage.NoUserProfileServiceLookup(file);
                return(null);
            }

            UserProfileMap userMap = TryGetUserMap(userId, campaignTestKey);

            if (userMap == null || string.IsNullOrEmpty(userMap.CampaignTestKey) ||
                string.IsNullOrEmpty(userMap.VariationName) || string.IsNullOrEmpty(userMap.UserId) ||
                string.Equals(userMap.UserId, userId) == false || string.Equals(userMap.CampaignTestKey, campaignTestKey) == false)
            {
                LogDebugMessage.NoStoredVariation(file, userId, campaignTestKey);
                return(null);
            }

            LogInfoMessage.GotStoredVariation(file, userMap.VariationName, campaignTestKey, userId);
            LogDebugMessage.GettingStoredVariation(file, userId, campaignTestKey, userMap.VariationName);
            return(userMap);
        }
Пример #15
0
        /// <summary>
        /// Flush the queue, clear timer and send POST network call to VWO servers.
        /// </summary>
        /// <param name="manual">manual Boolean specifying flush is triggered manual or not.</param>
        /// <returns>Boolean value specifying flush was successful or not.</returns>
        public bool flush(bool manual)
        {
            var batchMetadata = HttpRequestBuilder.GetJsonString(this.batchQueue);

            if (batchQueue.Count == 0)
            {
                LogDebugMessage.EventQueueEmpty(file);
            }
            if (manual)
            {
                if (batchQueue.Count > 0)
                {
                    LogDebugMessage.BeforeFlushing(file, "manually", batchQueue.Count.ToString(), accountId.ToString(), "Timer will be cleared and registered again", batchMetadata);
                    Task <bool> response = sendPostCall();
                    LogDebugMessage.AfterFlushing(file, "manually", batchQueue.Count.ToString(), batchMetadata);
                    disposeData();
                    return(true);
                }
                clearRequestTimer();
                return(true);
            }
            else
            {
                if (batchQueue.Count > 0 && !isBatchProcessing)
                {
                    isBatchProcessing = true;

                    LogDebugMessage.BeforeFlushing(file, "", batchQueue.Count.ToString(), accountId.ToString(), "", batchMetadata);
                    Task <bool> response = sendPostCall();
                    LogDebugMessage.AfterFlushing(file, "", batchQueue.Count.ToString(), batchMetadata);
                    disposeData();
                    return(true);
                }
                clearRequestTimer();
                return(true);
            }
        }
Пример #16
0
        /// <summary>
        /// Send Post network call to VWO servers.
        /// </summary>
        /// <returns>Boolean value specifying flush was successful or not.</returns>
        private async Task <bool> sendPostCall()
        {
            string     PayLoad    = HttpRequestBuilder.GetJsonString(this.batchQueue);
            var        ApiRequest = ServerSideVerb.EventBatching(this.accountId, this.isDevelopmentMode, this.apikey);
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Accept.Clear();
            httpClient.DefaultRequestHeaders.Add("Authorization", this.apikey);
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var data = new StringContent(PayLoad, Encoding.UTF8, "application/json");

            try
            {
                HttpResponseMessage response = await httpClient.PostAsync(ApiRequest.Uri, data);

                response.EnsureSuccessStatusCode();
                if (response.StatusCode == System.Net.HttpStatusCode.OK && response.StatusCode < System.Net.HttpStatusCode.Ambiguous)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush(null, PayLoad);
                    }
                    LogInfoMessage.ImpressionSuccess(file, ApiRequest.logUri?.ToString());
                    return(true);
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.RequestEntityTooLarge)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Payload size too large", PayLoad);
                    }
                    LogDebugMessage.BatchEventLimitExceeded(file, ApiRequest.logUri?.ToString(), this.accountId.ToString(), eventsPerRequest.ToString());
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());

                    return(false);
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Account id not found, no request app id found, or invalid API key", PayLoad);
                    }
                    LogErrorMessage.BulkNotProcessed(file);
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());
                    return(false);
                }
                else
                {
                    LogErrorMessage.BulkNotProcessed(file);
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Invalid call", PayLoad);
                    }

                    return(false);
                }
            }
            catch (HttpRequestException ex)
            {
                LogErrorMessage.BulkNotProcessed(file);
                LogErrorMessage.UnableToDisplayHttpRequest(file, ex.StackTrace);
                if (flushCallback != null)
                {
                    flushCallback.onFlush("HttpRequest Exception", PayLoad);
                }
                return(false);
            }
        }