예제 #1
0
        /// <summary>
        /// Insert the event in the queue and flush if the queue is full.
        /// </summary>
        /// <param name="eventData"> event Map containing configs of the event</param>
        ///
        public void addInQueue(IDictionary <string, dynamic> eventData)
        {
            if (isDevelopmentMode)
            {
                return;
            }

            batchQueue.Enqueue(eventData);

            if (eventData.ContainsKey("eT"))
            {
                int eT = (int)eventData["eT"];
                addEventCount(eT);
                LogInfoMessage.ImpressionSuccessQueue(file);
            }


            if (timer == null)
            {
                createNewBatchTimer();
            }
            if (eventsPerRequest == batchQueue.Count)
            {
                flush(false);
            }
        }
예제 #2
0
        public async Task <byte[]> ExecuteAsync(ApiRequest apiRequest)
        {
            if (apiRequest == null)
            {
                return(null);
            }
            HttpRequestMessage  httpRequestMessage  = new HttpRequestMessage(apiRequest.Method.GetHttpMethod(), apiRequest.Uri.ToString());
            HttpResponseMessage httpResponseMessage = null;

            try
            {
                httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage);

                if (httpResponseMessage.IsSuccessStatusCode)
                {
                    var response = await httpResponseMessage.Content.ReadAsByteArrayAsync();

                    LogInfoMessage.ImpressionSuccess(file, apiRequest.Uri.ToString());
                    return(response);
                }
                LogErrorMessage.ImpressionFailed(file, apiRequest.Uri?.ToString());
            }
            catch (Exception exception)
            {
                LogErrorMessage.ImpressionFailed(file, apiRequest.Uri?.ToString());
            }
            finally
            {
            }
            return(null);
        }
예제 #3
0
        private bool isGoalTriggerRequired(string campaignKey, string userId, string goalIdentifier, string variationName, bool shouldTrackReturningUser)
        {
            UserStorageMap userMap = this._userStorageService.GetUserMap(campaignKey, userId);

            if (userMap == null)
            {
                return(true);
            }
            string storedGoalIdentifier = null;

            if (userMap.GoalIdentifier != null)
            {
                storedGoalIdentifier = userMap.GoalIdentifier;
                string[] identifiers = storedGoalIdentifier.Split(new string[] { Constants.GOAL_IDENTIFIER_SEPERATOR }, StringSplitOptions.None);
                if (!((IList <string>)identifiers).Contains(goalIdentifier))
                {
                    storedGoalIdentifier = storedGoalIdentifier + Constants.GOAL_IDENTIFIER_SEPERATOR + goalIdentifier;
                }
                else if (!shouldTrackReturningUser)
                {
                    LogInfoMessage.GoalAlreadyTracked(file, userId, campaignKey, goalIdentifier);
                    return(false);
                }
            }
            else
            {
                storedGoalIdentifier = goalIdentifier;
            }
            this._userStorageService.SetUserMap(userId, campaignKey, variationName, storedGoalIdentifier);
            return(true);
        }
예제 #4
0
        /// <summary>
        /// Returns the feature variable corresponding to the variableKey passed. It typecasts the value to the corresponding value type found in settings_file
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="variableKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// The name of the variation in which the user is bucketed, or null if the user doesn't qualify to become a part of the campaign.
        /// </returns>
        public dynamic GetFeatureVariableValue(string campaignKey, string variableKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;
            var variables = new List <Dictionary <string, dynamic> >();
            var variable  = new Dictionary <string, dynamic>();

            if (this._validator.GetFeatureVariableValue(campaignKey, variableKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(GetFeatureVariableValue));
                    return(null);
                }

                if (campaign.Type == Constants.CampaignTypes.VISUAL_AB)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(GetFeatureVariableValue));
                    return(null);
                }

                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(GetFeatureVariableValue));
                if (campaign.Type == Constants.CampaignTypes.FEATURE_ROLLOUT)
                {
                    variables = campaign.Variables;
                }
                else if (campaign.Type == Constants.CampaignTypes.FEATURE_TEST)
                {
                    if (!assignedVariation.Variation.IsFeatureEnabled)
                    {
                        LogInfoMessage.FeatureNotEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(GetFeatureVariableValue));
                        assignedVariation = this.GetControlVariation(campaign, campaign.Variations.Find(1, (new VariationAllocator()).GetVariationId));
                    }
                    else
                    {
                        LogInfoMessage.FeatureEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(GetFeatureVariableValue));
                    }
                    variables = assignedVariation.Variation.Variables;
                }

                variable = this.GetVariable(variables, variableKey);
                if (variable == null || variable.Count == 0)
                {
                    LogErrorMessage.VariableNotFound(typeof(IVWOClient).FullName, variableKey, campaignKey, campaign.Type, userId, nameof(GetFeatureVariableValue));
                    return(null);
                }
                else
                {
                    LogInfoMessage.VariableFound(typeof(IVWOClient).FullName, variableKey, campaignKey, campaign.Type, variable["value"].ToString(), userId, nameof(GetFeatureVariableValue));
                }
                return(this._segmentEvaluator.getTypeCastedFeatureValue(variable["value"], variable["type"]));
            }
            return(null);
        }
예제 #5
0
        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);

            LogInfoMessage.UserHashBucketValue(file, userId, hashValue, bucketValue);
            return(bucketValue);
        }
예제 #6
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());
        }
예제 #7
0
        private RangeBucket <Variation> Bucket(IReadOnlyList <Variation> variations, string campaignKey)
        {
            RangeBucket <Variation> bucket = new RangeBucket <Variation>(Constants.Variation.MAX_TRAFFIC_VALUE);

            foreach (var variation in variations)
            {
                bucket.Add(variation.Weight, variation, out double start, out double end);
                LogInfoMessage.VariationRangeAllocation(file, campaignKey, variation.Name, variation.Weight, start, end);
            }
            return(bucket);
        }
예제 #8
0
        /// <summary>
        /// Identifies whether the user becomes a part of feature rollout/test or not.
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// /// A boolean value based on whether the impression was made to the VWO server.
        /// True, if an impression event is successfully being made to the VWO server for report generation.
        /// False, If userId provided is not part of campaign or when unexpected error comes and no impression call is made to the VWO server.
        /// </returns>
        public bool IsFeatureEnabled(string campaignKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;

            if (this._validator.IsFeatureEnabled(campaignKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(IsFeatureEnabled));
                    return(false);
                }
                if (campaign.Type == Constants.CampaignTypes.VISUAL_AB)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(IsFeatureEnabled));
                    return(false);
                }

                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(IsFeatureEnabled));
                if (campaign.Type == Constants.CampaignTypes.FEATURE_TEST)
                {
                    if (assignedVariation.Variation != null)
                    {
                        var trackUserRequest = ServerSideVerb.TrackUser(this._settings.AccountId, assignedVariation.Campaign.Id, assignedVariation.Variation.Id, userId, this._isDevelopmentMode);
                        trackUserRequest.ExecuteAsync();
                        var result = assignedVariation.Variation.IsFeatureEnabled;

                        if (result)
                        {
                            LogInfoMessage.FeatureEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(IsFeatureEnabled));
                        }
                        else
                        {
                            LogInfoMessage.FeatureNotEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(IsFeatureEnabled));
                        }
                        return(result);
                    }
                    return(false);
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #9
0
        /// <summary>
        /// Calls Get within try to suppress any Exception from outside of SDK application.
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private UserStorageMap TryGetUserMap(string userId, string campaignKey)
        {
            try
            {
                LogInfoMessage.LookingUpUserStorageService(file, userId, campaignKey);
                return(this._userStorageService.Get(userId, campaignKey));
            }
            catch (Exception ex)
            {
                LogErrorMessage.GetUserStorageServiceFailed(file, userId, campaignKey);
            }

            return(null);
        }
예제 #10
0
        public bool evaluate(string userId, string campaignKey, string segmentationType, Dictionary <string, dynamic> segments, Dictionary <string, dynamic> customVariables)
        {
            var result = this.evaluateSegment(segments, customVariables);

            if (segmentationType == Constants.SegmentationType.PRE_SEGMENTATION)
            {
                if (result)
                {
                    LogInfoMessage.UserPassedPreSegmentation(typeof(SegmentEvaluator).FullName, userId, campaignKey, customVariables);
                }
                else
                {
                    LogInfoMessage.UserFailedPreSegmentation(typeof(SegmentEvaluator).FullName, userId, campaignKey, customVariables);
                }
            }
            return(result);
        }
예제 #11
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);
            }
        }
        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>
        /// Calls Get within try to suppress any Exception from outside of SDK application.
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="campaignKey"></param>
        /// <param name="userStorageData"></param>
        /// <returns></returns>
        private UserStorageMap TryGetUserMap(string userId, string campaignKey, Dictionary <string, dynamic> userStorageData = null)
        {
            try
            {
                LogInfoMessage.LookingUpUserStorageService(file, userId, campaignKey);
                if (userStorageData != null)
                {
                    if (userStorageData.ContainsKey("userId") && userStorageData.ContainsKey("campaignKey") && userStorageData.ContainsKey("variationName"))
                    {
                        if (string.IsNullOrEmpty(userStorageData["userId"]) == false && string.IsNullOrEmpty(userStorageData["campaignKey"]) == false &&
                            string.IsNullOrEmpty(userStorageData["variationName"]) == false)
                        {
                            string jsonString = JsonConvert.SerializeObject(userStorageData);
                            var    allValue   = JsonConvert.DeserializeObject <UserStorageMap>(jsonString);
                            LogInfoMessage.ReturnUserStorageData(file, userStorageData["userId"], userStorageData["campaignKey"]);
                            return(allValue);
                        }
                        else
                        {
                            return(this._userStorageService.Get(userId, campaignKey));
                        }
                    }
                    else
                    {
                        return(this._userStorageService.Get(userId, campaignKey));
                    }
                }
                else
                {
                    return(this._userStorageService.Get(userId, campaignKey));
                }
            }
            catch (Exception ex)
            {
                LogErrorMessage.GetUserStorageServiceFailed(file, userId, campaignKey);
            }

            return(null);
        }
예제 #16
0
        private Variation FindTargetedVariation(string apiName, BucketedCampaign campaign, string campaignKey, string userId, Dictionary <string, dynamic> customVariables, Dictionary <string, dynamic> variationTargetingVariables)
        {
            if (campaign.IsForcedVariationEnabled)
            {
                if (variationTargetingVariables == null)
                {
                    variationTargetingVariables = new Dictionary <string, dynamic>();
                    variationTargetingVariables.Add("_vwoUserId", userId);
                }
                else
                {
                    if (variationTargetingVariables.ContainsKey("_vwoUserId"))
                    {
                        variationTargetingVariables["_vwoUserId"] = userId;
                    }
                    else
                    {
                        variationTargetingVariables.Add("_vwoUserId", userId);
                    }
                }
                List <Variation> whiteListedVariations = this.GetWhiteListedVariationsList(apiName, userId, campaign, campaignKey, customVariables, variationTargetingVariables);

                string    status          = Constants.WhitelistingStatus.FAILED;
                string    variationString = " ";
                Variation variation       = this._variationAllocator.TargettedVariation(userId, whiteListedVariations);
                if (variation != null)
                {
                    status          = Constants.WhitelistingStatus.PASSED;
                    variationString = $"and variation: {variation.Name} is assigned";
                }
                LogInfoMessage.WhitelistingStatus(typeof(IVWOClient).FullName, userId, campaignKey, apiName, variationString, status);
                return(variation);
            }
            LogInfoMessage.SkippingWhitelisting(typeof(IVWOClient).FullName, userId, campaignKey, apiName);
            return(null);
        }
예제 #17
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);
            }
        }