/// <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); } }
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); }
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); }
/// <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); }
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); }
/// <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()); }
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); }
/// <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); } }
/// <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); }
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); }
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); } }
/// <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); }
/// <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); }
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); }
/// <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); } }