vwo-sdk 1.3.0 → 1.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/vwo.rb +1020 -84
- data/lib/vwo/constants.rb +64 -13
- data/lib/vwo/core/bucketer.rb +10 -14
- data/lib/vwo/core/variation_decider.rb +391 -80
- data/lib/vwo/enums.rb +113 -10
- data/lib/vwo/logger.rb +9 -3
- data/lib/vwo/schemas/settings_file.rb +1 -3
- data/lib/vwo/services/batch_events_dispatcher.rb +110 -0
- data/lib/vwo/services/batch_events_queue.rb +175 -0
- data/lib/vwo/services/event_dispatcher.rb +3 -17
- data/lib/vwo/services/hooks_manager.rb +36 -0
- data/lib/vwo/services/operand_evaluator.rb +122 -0
- data/lib/vwo/services/segment_evaluator.rb +88 -0
- data/lib/vwo/services/settings_file_manager.rb +11 -9
- data/lib/vwo/services/settings_file_processor.rb +6 -3
- data/lib/vwo/services/usage_stats.rb +29 -0
- data/lib/vwo/user_storage.rb +1 -3
- data/lib/vwo/utils/campaign.rb +151 -22
- data/lib/vwo/utils/custom_dimensions.rb +72 -0
- data/lib/vwo/utils/feature.rb +56 -0
- data/lib/vwo/utils/function.rb +6 -3
- data/lib/vwo/utils/impression.rb +76 -7
- data/lib/vwo/utils/request.rb +15 -3
- data/lib/vwo/utils/segment.rb +116 -0
- data/lib/vwo/utils/uuid.rb +3 -5
- data/lib/vwo/utils/validations.rb +96 -4
- metadata +30 -8
data/lib/vwo/enums.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2019 Wingify Software Pvt. Ltd.
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,14 +12,54 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# frozen_string_literal: true
|
16
|
-
|
17
15
|
# rubocop:disable Metrics/LineLength
|
18
16
|
|
19
17
|
require 'logger'
|
20
18
|
|
21
19
|
class VWO
|
22
20
|
module Enums
|
21
|
+
module OperandValueTypesName
|
22
|
+
REGEX = 'regex'
|
23
|
+
WILDCARD = 'wildcard'
|
24
|
+
LOWER = 'lower'
|
25
|
+
EQUALS = 'equals'
|
26
|
+
end
|
27
|
+
|
28
|
+
module OperandValueTypes
|
29
|
+
LOWER = 'lower'
|
30
|
+
CONTAINS = 'contains'
|
31
|
+
STARTS_WITH = 'starts_with'
|
32
|
+
ENDS_WITH = 'ends_with'
|
33
|
+
REGEX = 'regex'
|
34
|
+
EQUALS = 'equals'
|
35
|
+
end
|
36
|
+
|
37
|
+
module OperatorTypes
|
38
|
+
AND = 'and'
|
39
|
+
OR = 'or'
|
40
|
+
NOT = 'not'
|
41
|
+
end
|
42
|
+
|
43
|
+
module OperandTypes
|
44
|
+
CUSTOM_VARIABLE = 'custom_variable'
|
45
|
+
USER = 'user'
|
46
|
+
end
|
47
|
+
|
48
|
+
module OperandValuesBooleanTypes
|
49
|
+
TRUE = 'true'
|
50
|
+
FALSE = 'false'
|
51
|
+
end
|
52
|
+
|
53
|
+
module StatusEnum
|
54
|
+
PASSED = 'passed'
|
55
|
+
FAILED = 'failed'
|
56
|
+
end
|
57
|
+
|
58
|
+
module SegmentationTypeEnum
|
59
|
+
WHITELISTING = 'whitelisting'
|
60
|
+
PRE_SEGMENTATION = 'pre-segmentation'
|
61
|
+
end
|
62
|
+
|
23
63
|
module FileNameEnum
|
24
64
|
VWO_PATH = 'vwo'
|
25
65
|
UTIL_PATH = 'vwo/utils'
|
@@ -28,14 +68,19 @@ class VWO
|
|
28
68
|
Bucketer = VWO_PATH + '/core/bucketer'
|
29
69
|
VariationDecider = VWO_PATH + '/core/variation_decider'
|
30
70
|
EventDispatcher = VWO_PATH + '/services/event_dispatcher'
|
71
|
+
SegmentEvaluator = VWO_PATH + '/services/segment_evaluator'
|
31
72
|
Logger = VWO_PATH + '/logger'
|
32
73
|
SettingsFileProcessor = VWO_PATH + '/services/settings_file_processor'
|
74
|
+
BatchEventsQueue = VWO_PATH + '/services/batch_events_queue'
|
75
|
+
BatchEventsDispatcher = VWO_PATH + '/services/batch_events_dispatcher'
|
33
76
|
|
34
77
|
CampaignUtil = UTIL_PATH + '/campaign'
|
35
78
|
FunctionUtil = UTIL_PATH + '/function'
|
79
|
+
FeatureUtil = UTIL_PATH + '/feature'
|
36
80
|
ImpressionUtil = UTIL_PATH + '/impression'
|
37
81
|
UuidUtil = UTIL_PATH + '/uuid'
|
38
82
|
ValidateUtil = UTIL_PATH + '/validations'
|
83
|
+
CustomDimensionsUtil = UTIL_PATH + '/custom_dimensions_util'
|
39
84
|
end
|
40
85
|
|
41
86
|
# Logging Enums
|
@@ -61,12 +106,19 @@ class VWO
|
|
61
106
|
IMPRESSION_FOR_TRACK_USER = '(%<file>s): Impression built for track-user - %<properties>s'
|
62
107
|
IMPRESSION_FOR_TRACK_GOAL = '(%<file>s): Impression built for track-goal - %<properties>s'
|
63
108
|
GOT_VARIATION_FOR_USER = '(%<file>s): userId:%<user_id>s for campaign:%<campaign_key>s got variationName:%<variation_name>s'
|
109
|
+
SEGMENTATION_STATUS = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s of campaign:%<campaign_key>s with variables:%<custom_variables>s %<status>s %<segmentation_type>s for %<variation_name>s'
|
110
|
+
PARAMS_FOR_PUSH_CALL = '(%<file>s): Params for push call - %<properties>s'
|
111
|
+
CAMPAIGN_NOT_ACTIVATED = '(%<file>s): Campaign:%<campaign_key>s for User ID:%<user_id>s is not yet activated for API:%<api_name>s. Use activate API to activate A/B test or isFeatureEnabled API to activate Feature Test.'
|
112
|
+
BATCH_EVENT_LIMIT_EXCEEDED = '(%<file>s): Impression event - %<end_point>s failed due to exceeding payload size. Parameter eventsPerRequest in batchEvents config in launch API has value:%<eventsPerRequest>s for accountId:%<accountId>s. Please read the official documentation for knowing the size limits.'
|
113
|
+
BULK_NOT_PROCESSED = "(%<file>s): Batch events couldn't be received by VWO. Calling Flush Callback with error and data."
|
114
|
+
BEFORE_FLUSHING = '(%<file>s): Flushing events queue %<manually>s having %<length>s events %<timer>s queue summary: %<queue_metadata>s'
|
115
|
+
EVENT_BATCHING_INSUFFICIENT = '(%<file>s): %<key>s not provided, assigning default value'
|
64
116
|
end
|
65
117
|
|
66
118
|
# Info Messages
|
67
119
|
module InfoMessages
|
68
120
|
VARIATION_RANGE_ALLOCATION = '(%<file>s): Campaign:%<campaign_key>s having variations:%<variation_name>s with weight:%<variation_weight>s got range as: ( %<start>s - %<end>s ))'
|
69
|
-
VARIATION_ALLOCATED = '(%<file>s): UserId:%<user_id>s of Campaign:%<campaign_key>s got variation: %<variation_name>s'
|
121
|
+
VARIATION_ALLOCATED = '(%<file>s): UserId:%<user_id>s of Campaign:%<campaign_key>s type: %<campaign_type>s got variation: %<variation_name>s'
|
70
122
|
LOOKING_UP_USER_STORAGE_SERVICE = '(%<file>s): Looked into UserStorageService for userId:%<user_id>s %<status>s'
|
71
123
|
SAVING_DATA_USER_STORAGE_SERVICE = '(%<file>s): Saving into UserStorageService for userId:%<user_id>s successful'
|
72
124
|
GOT_STORED_VARIATION = '(%<file>s): Got stored variation:%<variation_name>s of campaign:%<campaign_key>s for userId:%<user_id>s from UserStorageService'
|
@@ -75,8 +127,34 @@ class VWO
|
|
75
127
|
AUDIENCE_CONDITION_NOT_MET = '(%<file>s): userId:%<user_id>s does not become part of campaign because of not meeting audience conditions'
|
76
128
|
GOT_VARIATION_FOR_USER = '(%<file>s): userId:%<user_id>s for campaign:%<campaign_key>s got variationName:%<variation_name>s'
|
77
129
|
USER_GOT_NO_VARIATION = '(%<file>s): userId:%<user_id>s for campaign:%<campaign_key>s did not allot any variation'
|
78
|
-
IMPRESSION_SUCCESS = '(%<file>s): Impression event - %<end_point>s was successfully received by VWO having main keys:
|
130
|
+
IMPRESSION_SUCCESS = '(%<file>s): Impression event - %<end_point>s was successfully received by VWO having main keys: sdkKey:%<sdk_key>s accountId:%<account_id>s campaignId:%<campaign_id>s and variationId:%<variation_id>s'
|
131
|
+
MAIN_KEYS_FOR_IMPRESSION = '(%<file>s): Having main keys: {sdkKey:%<sdk_key>s accountId:%<account_id>s campaignId:%<campaign_id>s and variationId:%<variation_id>s}'
|
132
|
+
MAIN_KEYS_FOR_PUSH_API = '(%<file>s): Having main keys: {sdkKey:%<sdk_key>s accountId:%<account_id>s u:%<u>s and tags:%<tags>s}'
|
79
133
|
INVALID_VARIATION_KEY = '(%<file>s): Variation was not assigned to userId:%<user_id>s for campaign:%<campaign_key>s'
|
134
|
+
|
135
|
+
USER_IN_FEATURE_ROLLOUT = '(%<file>s): User ID:%<user_id>s is in feature rollout:%<campaign_key>s'
|
136
|
+
USER_NOT_IN_FEATURE_ROLLOUT = '(%<file>s): User ID:%<user_id>s is NOT in feature rollout:%<campaign_key>s'
|
137
|
+
FEATURE_ENABLED_FOR_USER = '(%<file>s): In API: %<api_name>s Feature having feature-key:%<feature_key>s for user ID:%<user_id>s is enabled'
|
138
|
+
FEATURE_NOT_ENABLED_FOR_USER = '(%<file>s): In API: %<api_name>s Feature having feature-key:%<feature_key>s for user ID:%<user_id>s is not enabled'
|
139
|
+
|
140
|
+
VARIABLE_FOUND = '(%<file>s): In API: %<api_name>s Value for variable:%<variable_key>s of campaign:%<campaign_key>s and campaign type: %<campaign_type>s is:%<variable_value>s for user:%<user_id>s'
|
141
|
+
|
142
|
+
USER_PASSED_SEGMENTATION = '(%<file>s): UserId:%<user_id>s of campaign:%<campaign_key>s with custom_variables:%<custom_variables>s passed segmentation'
|
143
|
+
USER_FAILED_SEGMENTATION = '(%<file>s): UserId:%<user_id>s of campaign:%<campaign_key>s with custom_variables:%<custom_variables>s failed segmentation'
|
144
|
+
|
145
|
+
NO_CUSTOM_VARIABLES = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s preSegments/customVariables are not passed for campaign:%<campaign_key>s and campaign has pre-segmentation'
|
146
|
+
SKIPPING_SEGMENTATION = '(%<file>s): In API: %<api_name>s, Skipping segmentation:%<variation>s for UserId:%<user_id>s as no valid segments found in campaign:%<campaign_key>s'
|
147
|
+
|
148
|
+
SEGMENTATION_STATUS = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s of campaign:%<campaign_key>s with variables:%<custom_variables>s %<status>s %<segmentation_type>s %<variation_name>s'
|
149
|
+
WHITELISTING_SKIPPED = '(%<file>s): In API: %<api_name>s, Skipping whitelisting for UserId:%<user_id>s of campaign:%<campaign_key>s'
|
150
|
+
SETTINGS_NOT_UPDATED = '(%<file>s): Settings-file fetched are same as earlier fetched settings'
|
151
|
+
SETTINGS_FILE_UPDATED = '(%<file>s): %<api_name>s vwo_sdk_instance is updated with the latest settings_file'
|
152
|
+
CAMPAIGN_NOT_ACTIVATED = '(%<file>s): Activate the campaign:%<campaign_key>s for User ID:%<user_id>s to %<reason>s.'
|
153
|
+
GOAL_ALREADY_TRACKED = '(%<file>s): Goal:%<goal_identifier>s of Campaign:%<campaign_key>s for User ID:%<user_id>s has already been tracked earlier. Skipping now'
|
154
|
+
USER_ALREADY_TRACKED = '(%<file>s): User ID:%<user_id>s for Campaign:%<campaign_key>s has already been tracked earlier for "%<api_name>s" API. Skipping now'
|
155
|
+
API_CALLED = '(%<file>s): API: {api_name} called for UserId:%<user_id>s'
|
156
|
+
BULK_IMPRESSION_SUCCESS = '(%<file>s): Impression event - %<end_point>s was successfully received by VWO having accountId:%<a>s'
|
157
|
+
AFTER_FLUSHING = '(%<file>s): Events queue having %<length>s events has been flushed %<manually>s queue summary: %<queue_metadata>s'
|
80
158
|
end
|
81
159
|
|
82
160
|
# Warning Messages
|
@@ -85,22 +163,47 @@ class VWO
|
|
85
163
|
# Error Messages
|
86
164
|
module ErrorMessages
|
87
165
|
SETTINGS_FILE_CORRUPTED = '(%<file>s): Settings file is corrupted. Please contact VWO Support for help.'
|
88
|
-
ACTIVATE_API_MISSING_PARAMS = '(%<file>s):
|
89
|
-
|
90
|
-
|
166
|
+
ACTIVATE_API_MISSING_PARAMS = '(%<file>s): %<api_name>s API got bad parameters. It expects campaignTestKey(String) as first and userId(String) as second argument, customVariables(Hash) can be passed via options for pre-segmentation'
|
167
|
+
API_CONFIG_CORRUPTED = '(%<file>s): %<api_name>s API has corrupted configuration'
|
168
|
+
GET_VARIATION_NAME_API_INVALID_PARAMS = '(%<file>s): %<api_name>s API got bad parameters. It expects campaignTestKey(String) as first and userId(String) as second argument, customVariables(Hash) can be passed via options for pre-segmentation'
|
91
169
|
GET_VARIATION_API_CONFIG_CORRUPTED = '(%<file>s): "getVariation" API has corrupted configuration'
|
92
|
-
|
170
|
+
TRACK_API_INVALID_PARAMS = '(%<file>s): %<api_name>s API got bad parameters. It expects campaignTestKey(Nil/String/Array) as first userId(String) as second and goalIdentifier(String/Number) as third argument. Fourth is revenueValue(Float/Number/String) and is required for revenue goal only. customVariables(Hash) can be passed via options for pre-segmentation'
|
93
171
|
TRACK_API_CONFIG_CORRUPTED = '(%<file>s): "track" API has corrupted configuration'
|
94
172
|
TRACK_API_GOAL_NOT_FOUND = '(%<file>s): Goal:%<goal_identifier>s not found for campaign:%<campaign_key>s and userId:%<user_id>s'
|
95
173
|
TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL = '(%<file>s): Revenue value should be passed for revenue goal:%<goal_identifier>s for campaign:%<campaign_key>s and userId:%<user_id>s'
|
96
174
|
TRACK_API_VARIATION_NOT_FOUND = '(%<file>s): Variation not found for campaign:%<campaign_key>s and userId:%<user_id>s'
|
97
|
-
CAMPAIGN_NOT_RUNNING = '(%<file>s): API used:%<
|
175
|
+
CAMPAIGN_NOT_RUNNING = '(%<file>s): API used:%<api_name>s - Campaign:%<campaign_key>s is not RUNNING. Please verify from VWO App'
|
98
176
|
LOOK_UP_USER_STORAGE_SERVICE_FAILED = '(%<file>s): Looking data from UserStorageService failed for userId:%<user_id>s'
|
99
177
|
SAVE_USER_STORAGE_SERVICE_FAILED = '(%<file>s): Saving data into UserStorageService failed for userId:%<user_id>s'
|
100
178
|
INVALID_CAMPAIGN = '(%<file>s): Invalid campaign passed to %<method>s of this file'
|
101
179
|
INVALID_USER_ID = '(%<file>s): Invalid userId:%<user_id>s passed to %<method>s of this file'
|
102
180
|
IMPRESSION_FAILED = '(%<file>s): Impression event could not be sent to VWO - %<end_point>s'
|
103
181
|
CUSTOM_LOGGER_MISCONFIGURED = '(%<file>s): Custom logger is provided but seems to have mis-configured. %<extra_info>s Please check the API Docs. Using default logger.'
|
182
|
+
INVALID_API = '(%<file>s): %<api_name>s API is not valid for user ID: %<user_id>s in campaign ID: %<campaign_key>s having campaign type: %<campaign_type>s.'
|
183
|
+
IS_FEATURE_ENABLED_API_INVALID_PARAMS = '(%<file>s): %<api_name>s API got bad parameters. It expects campaign_key(String) as first and user_id(String) as second argument, customVariables(dict) can be passed via options for pre-segmentation'
|
184
|
+
GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS = '(%<file>s): "get_feature_variable" API got bad parameters. It expects campaign_key(String) as first, variable_key(string) as second and user_id(String) as third argument, customVariables(dict) can be passed via options for pre-segmentation'
|
185
|
+
|
186
|
+
VARIABLE_NOT_FOUND = '(%<file>s): In API: %<api_name>s Variable %<variable_key>s not found for campaign %<campaign_key>s and type %<campaign_type>s for user ID %<user_id>s'
|
187
|
+
UNABLE_TO_TYPE_CAST = '(%<file>s): Unable to typecast value: %<value>s of type: %<of_type>s to type: %<variable_type>s.'
|
188
|
+
|
189
|
+
USER_NOT_IN_CAMPAIGN = '(%<file>s): userId:%<user_id>s did not become part of campaign:%<campaign_key>s and campaign type:%<campaign_type>s'
|
190
|
+
API_NOT_WORKING = '(%<file>s): API: %<api_name>s not working, exception caught: %<exception>s. Please contact VWO Support for help.'
|
191
|
+
|
192
|
+
SEGMENTATION_ERROR = '(%<file>s): Error while segmenting the UserId:%<user_id>s of campaign:%<campaign_key>s with custom_variables:%<custom_variables>s. Error message: %<error_message>s'
|
193
|
+
|
194
|
+
PUSH_API_INVALID_PARAMS = '(%<file>s): %<api_name>s API got bad parameters. It expects tag_key(String) as first and tag_value(String) as second argument and user_id(String) as third argument'
|
195
|
+
TAG_VALUE_LENGTH_EXCEEDED = '(%<file>s): In API: %<api_name>s, the length of tag_value:%<tag_value>s and userID: %<user_id>s can not be greater than 255'
|
196
|
+
TAG_KEY_LENGTH_EXCEEDED = '(%<file>s): In API: %<api_name>s, the length of tag_key:%<tag_key>s and userID: %<user_id>s can not be greater than 255'
|
197
|
+
TRACK_API_MISSING_PARAMS = '(%<file>s): "track" API got bad parameters. It expects campaignKey(null/String/array) as first, userId(String/Number) as second and goalIdentifier (string) as third argument. options is revenueValue(Float/Number/String) and is required for revenue goal only.'
|
198
|
+
NO_CAMPAIGN_FOUND = '(%<file>s): No campaign found for goal_identifier:%<goal_identifier>s. Please verify from VWO app.'
|
199
|
+
INVALID_TRACK_RETURNING_USER_VALUE = '(%<file>s): should_track_returning_user should be boolean'
|
200
|
+
INVALID_GOAL_TYPE = '(%<file>s): goal_type_to_track should be certain strings'
|
201
|
+
EVENT_BATCHING_NOT_OBJECT = '(%<file>s): Batch events settings are not of type object.'
|
202
|
+
EVENTS_PER_REQUEST_INVALID = '(%<file>s): events_per_request should be an integer'
|
203
|
+
REQUEST_TIME_INTERVAL_INVALID = '(%<file>s): request_time_interval should be a number'
|
204
|
+
EVENTS_PER_REQUEST_OUT_OF_BOUNDS = '(%<file>s): events_per_request should be >= %<min_value>s and <= %<max_value>s'
|
205
|
+
REQUEST_TIME_INTERVAL_OUT_OF_BOUNDS = '(%<file>s): request_time_interval should be >= %<min_value>s'
|
206
|
+
FLUSH_CALLBACK_INVALID = '(%<file>s): flush_callback is not callable'
|
104
207
|
end
|
105
208
|
end
|
106
209
|
|
data/lib/vwo/logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2019 Wingify Software Pvt. Ltd.
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,8 +12,6 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# frozen_string_literal: true
|
16
|
-
|
17
15
|
require 'logger'
|
18
16
|
|
19
17
|
class VWO
|
@@ -33,5 +31,13 @@ class VWO
|
|
33
31
|
def log(level, message)
|
34
32
|
@@logger_instance.log(level, message)
|
35
33
|
end
|
34
|
+
|
35
|
+
def instance
|
36
|
+
@@logger_instance
|
37
|
+
end
|
38
|
+
|
39
|
+
def level
|
40
|
+
@@logger_instance.level
|
41
|
+
end
|
36
42
|
end
|
37
43
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2019 Wingify Software Pvt. Ltd.
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,8 +12,6 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# frozen_string_literal: true
|
16
|
-
|
17
15
|
require 'json'
|
18
16
|
|
19
17
|
class VWO
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require_relative '../logger'
|
16
|
+
require_relative '../enums'
|
17
|
+
require_relative '../utils/request'
|
18
|
+
class VWO
|
19
|
+
module Services
|
20
|
+
class BatchEventsDispatcher
|
21
|
+
include VWO::Enums
|
22
|
+
# Initialize the BatchEventDispatcher with logger and development mode
|
23
|
+
#
|
24
|
+
# @param [Boolean] : To specify whether the request
|
25
|
+
# to our server should be made or not.
|
26
|
+
#
|
27
|
+
def initialize
|
28
|
+
@logger = VWO::Logger.get_instance
|
29
|
+
@queue = []
|
30
|
+
end
|
31
|
+
|
32
|
+
# Dispatch the impression event having properties object only if dev-mode is OFF
|
33
|
+
#
|
34
|
+
# @param[Hash] :properties hash having impression properties
|
35
|
+
# the request to be dispatched to the VWO server
|
36
|
+
# @return[Boolean]
|
37
|
+
#
|
38
|
+
def dispatch(impression, callback, query_params)
|
39
|
+
url = CONSTANTS::HTTPS_PROTOCOL + CONSTANTS::ENDPOINTS::BASE_URL + CONSTANTS::ENDPOINTS::BATCH_EVENTS
|
40
|
+
account_id = query_params[:a]
|
41
|
+
resp = VWO::Utils::Request.post(url, query_params, impression)
|
42
|
+
if resp.code == '200'
|
43
|
+
@logger.log(
|
44
|
+
LogLevelEnum::INFO,
|
45
|
+
format(
|
46
|
+
LogMessageEnum::InfoMessages::BULK_IMPRESSION_SUCCESS,
|
47
|
+
file: FileNameEnum::BatchEventsDispatcher,
|
48
|
+
end_point: url,
|
49
|
+
a: account_id
|
50
|
+
)
|
51
|
+
)
|
52
|
+
message = nil
|
53
|
+
elsif resp.code == '413'
|
54
|
+
@logger.log(
|
55
|
+
LogLevelEnum::DEBUG,
|
56
|
+
format(
|
57
|
+
LogMessageEnum::DebugMessages::BATCH_EVENT_LIMIT_EXCEEDED,
|
58
|
+
file: FileNameEnum::BatchEventsDispatcher,
|
59
|
+
end_point: url,
|
60
|
+
accountId: impression[:a],
|
61
|
+
eventsPerRequest: impression.length()
|
62
|
+
)
|
63
|
+
)
|
64
|
+
|
65
|
+
@logger.log(
|
66
|
+
LogLevelEnum::ERROR,
|
67
|
+
format(
|
68
|
+
LogMessageEnum::ErrorMessages::IMPRESSION_FAILED,
|
69
|
+
file: FileNameEnum::BatchEventsDispatcher,
|
70
|
+
end_point: url
|
71
|
+
)
|
72
|
+
)
|
73
|
+
message = resp.message
|
74
|
+
else
|
75
|
+
@logger.log(
|
76
|
+
LogLevelEnum::DEBUG,
|
77
|
+
format(
|
78
|
+
LogMessageEnum::DebugMessages::BULK_NOT_PROCESSED,
|
79
|
+
file: FileNameEnum::BatchEventsDispatcher
|
80
|
+
)
|
81
|
+
)
|
82
|
+
|
83
|
+
@logger.log(
|
84
|
+
LogLevelEnum::ERROR,
|
85
|
+
format(LogMessageEnum::ErrorMessages::IMPRESSION_FAILED, file: FileNameEnum::BatchEventsDispatcher, end_point: url)
|
86
|
+
)
|
87
|
+
message = resp.message
|
88
|
+
end
|
89
|
+
if callback
|
90
|
+
callback.call(message, impression)
|
91
|
+
end
|
92
|
+
rescue StandardError => e
|
93
|
+
@logger.log(
|
94
|
+
LogLevelEnum::DEBUG,
|
95
|
+
format(
|
96
|
+
LogMessageEnum::DebugMessages::BULK_NOT_PROCESSED,
|
97
|
+
file: FileNameEnum::BatchEventsDispatcher
|
98
|
+
)
|
99
|
+
)
|
100
|
+
|
101
|
+
@logger.log(
|
102
|
+
LogLevelEnum::ERROR,
|
103
|
+
format(LogMessageEnum::ErrorMessages::IMPRESSION_FAILED, file: FileNameEnum::BatchEventsDispatcher, end_point: url)
|
104
|
+
)
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require_relative '../logger'
|
16
|
+
require_relative '../enums'
|
17
|
+
require_relative '../utils/request'
|
18
|
+
|
19
|
+
class VWO
|
20
|
+
module Services
|
21
|
+
class BatchEventsQueue
|
22
|
+
include VWO::Enums
|
23
|
+
|
24
|
+
def initialize(batch_config, is_development_mode = false)
|
25
|
+
@is_development_mode = is_development_mode
|
26
|
+
@logger = VWO::Logger.get_instance
|
27
|
+
@queue = []
|
28
|
+
@queue_metadata = {}
|
29
|
+
@batch_config = batch_config
|
30
|
+
|
31
|
+
if batch_config[:request_time_interval]
|
32
|
+
@request_time_interval = batch_config[:request_time_interval]
|
33
|
+
else
|
34
|
+
@request_time_interval = CONSTANTS::DEFAULT_REQUEST_TIME_INTERVAL
|
35
|
+
@logger.log(
|
36
|
+
LogLevelEnum::DEBUG,
|
37
|
+
format(
|
38
|
+
LogMessageEnum::DebugMessages::EVENT_BATCHING_INSUFFICIENT,
|
39
|
+
file: FileNameEnum::BatchEventsQueue,
|
40
|
+
key: 'request_time_interval'
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
if batch_config[:events_per_request]
|
46
|
+
@events_per_request = batch_config[:events_per_request]
|
47
|
+
else
|
48
|
+
@events_per_request = CONSTANTS::DEFAULT_EVENTS_PER_REQUEST
|
49
|
+
@logger.log(
|
50
|
+
LogLevelEnum::DEBUG,
|
51
|
+
format(
|
52
|
+
LogMessageEnum::DebugMessages::EVENT_BATCHING_INSUFFICIENT,
|
53
|
+
file: FileNameEnum::BatchEventsQueue,
|
54
|
+
key: 'events_per_request'
|
55
|
+
)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
@flush_callback = nil
|
60
|
+
if batch_config.key?(:flushCallback) && batch_config[:flushCallback].is_a?(Method)
|
61
|
+
@flush_callback = batch_config[:flushCallback]
|
62
|
+
end
|
63
|
+
|
64
|
+
@dispatcher = batch_config[:dispatcher]
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_new_batch_timer
|
68
|
+
@timer = Time.now + @request_time_interval
|
69
|
+
end
|
70
|
+
|
71
|
+
def enqueue(event)
|
72
|
+
return true if @is_development_mode
|
73
|
+
@queue.push(event)
|
74
|
+
update_queue_metadata(event)
|
75
|
+
unless @timer
|
76
|
+
create_new_batch_timer
|
77
|
+
@thread = Thread.new{flush_when_request_times_up}
|
78
|
+
end
|
79
|
+
if @events_per_request === @queue.length()
|
80
|
+
flush
|
81
|
+
kill_old_thread
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def flush_when_request_times_up
|
86
|
+
while @timer > Time.now
|
87
|
+
sleep(1)
|
88
|
+
end
|
89
|
+
flush
|
90
|
+
kill_old_thread
|
91
|
+
end
|
92
|
+
|
93
|
+
def flush(manual = false)
|
94
|
+
if @queue.length() > 0
|
95
|
+
@logger.log(
|
96
|
+
LogLevelEnum::DEBUG,
|
97
|
+
format(
|
98
|
+
LogMessageEnum::DebugMessages::BEFORE_FLUSHING,
|
99
|
+
file: FileNameEnum::BatchEventsQueue,
|
100
|
+
manually: manual ? 'manually' : '',
|
101
|
+
length: @queue.length(),
|
102
|
+
timer: manual ? 'Timer will be cleared and registered again,' : '',
|
103
|
+
queue_metadata: @queue_metadata
|
104
|
+
)
|
105
|
+
)
|
106
|
+
|
107
|
+
@dispatcher.call(@queue, @flush_callback)
|
108
|
+
@logger.log(
|
109
|
+
LogLevelEnum::INFO,
|
110
|
+
format(
|
111
|
+
LogMessageEnum::InfoMessages::AFTER_FLUSHING,
|
112
|
+
file: FILE,
|
113
|
+
manually: manual ? 'manually,' : '',
|
114
|
+
length: @queue.length(),
|
115
|
+
queue_metadata: @queue_metadata
|
116
|
+
)
|
117
|
+
)
|
118
|
+
@queue_metadata = {}
|
119
|
+
@queue = []
|
120
|
+
else
|
121
|
+
@logger.log(
|
122
|
+
LogLevelEnum::INFO,
|
123
|
+
format(
|
124
|
+
'Batch queue is empty. Nothing to flush.',
|
125
|
+
file: FILE
|
126
|
+
)
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
clear_request_timer
|
131
|
+
unless manual
|
132
|
+
if @thread
|
133
|
+
@old_thread = @thread
|
134
|
+
end
|
135
|
+
end
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
def clear_request_timer
|
140
|
+
@timer = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
def kill_thread
|
144
|
+
if @thread
|
145
|
+
@thread.kill
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def kill_old_thread
|
150
|
+
if @old_thread
|
151
|
+
@old_thread.kill
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def update_queue_metadata(event)
|
156
|
+
if event[:eT] == 1
|
157
|
+
unless @queue_metadata.key?(VWO::EVENTS::TRACK_USER)
|
158
|
+
@queue_metadata[VWO::EVENTS::TRACK_USER] = 0
|
159
|
+
end
|
160
|
+
@queue_metadata[VWO::EVENTS::TRACK_USER] = @queue_metadata[VWO::EVENTS::TRACK_USER] + 1
|
161
|
+
elsif event[:eT] == 2
|
162
|
+
unless @queue_metadata.key?(VWO::EVENTS::TRACK_GOAL)
|
163
|
+
@queue_metadata[VWO::EVENTS::TRACK_GOAL] = 0
|
164
|
+
end
|
165
|
+
@queue_metadata[VWO::EVENTS::TRACK_GOAL] = @queue_metadata[VWO::EVENTS::TRACK_GOAL] + 1
|
166
|
+
elsif event[:eT] == 3
|
167
|
+
unless @queue_metadata.key?(VWO::EVENTS::PUSH)
|
168
|
+
@queue_metadata[VWO::EVENTS::PUSH] = 0
|
169
|
+
end
|
170
|
+
@queue_metadata[VWO::EVENTS::PUSH] = @queue_metadata[VWO::EVENTS::PUSH] + 1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|