vwo-fme-ruby-sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/vwo/api/get_flag.rb +236 -0
- data/lib/vwo/api/set_attribute.rb +57 -0
- data/lib/vwo/api/track_event.rb +77 -0
- data/lib/vwo/constants/constants.rb +54 -0
- data/lib/vwo/decorators/storage_decorator.rb +86 -0
- data/lib/vwo/{utils/logger_helper.rb → enums/api_enum.rb} +5 -10
- data/lib/vwo/enums/campaign_type_enum.rb +19 -0
- data/lib/vwo/enums/decision_types_enum.rb +18 -0
- data/lib/vwo/enums/event_enum.rb +19 -0
- data/lib/vwo/enums/headers_enum.rb +20 -0
- data/lib/vwo/enums/hooks_enum.rb +17 -0
- data/lib/vwo/enums/http_method_enum.rb +18 -0
- data/lib/vwo/enums/log_level_enum.rb +21 -0
- data/lib/vwo/enums/status_enum.rb +19 -0
- data/lib/vwo/enums/storage_enum.rb +22 -0
- data/lib/vwo/enums/url_enum.rb +21 -0
- data/lib/vwo/models/campaign/campaign_model.rb +192 -0
- data/lib/vwo/models/campaign/feature_model.rb +111 -0
- data/lib/vwo/models/campaign/impact_campaign_model.rb +38 -0
- data/lib/vwo/models/campaign/metric_model.rb +44 -0
- data/lib/vwo/models/campaign/rule_model.rb +56 -0
- data/lib/vwo/models/campaign/variable_model.rb +51 -0
- data/lib/vwo/models/campaign/variation_model.rb +137 -0
- data/lib/vwo/models/gateway_service_model.rb +39 -0
- data/lib/vwo/models/schemas/settings_schema_validation.rb +102 -0
- data/lib/vwo/models/settings/settings_model.rb +85 -0
- data/lib/vwo/models/storage/storage_data_model.rb +44 -0
- data/lib/vwo/models/user/context_model.rb +100 -0
- data/lib/vwo/models/user/context_vwo_model.rb +38 -0
- data/lib/vwo/{utils/feature_flag_response.rb → models/user/get_flag_response.rb} +14 -14
- data/lib/vwo/models/vwo_options_model.rb +107 -0
- data/lib/vwo/packages/decision_maker/decision_maker.rb +60 -0
- data/lib/vwo/packages/logger/core/log_manager.rb +90 -0
- data/lib/vwo/packages/logger/core/transport_manager.rb +87 -0
- data/lib/vwo/packages/logger/log_message_builder.rb +70 -0
- data/lib/vwo/packages/logger/logger.rb +38 -0
- data/lib/vwo/packages/logger/transports/console_transport.rb +49 -0
- data/lib/vwo/packages/network_layer/client/network_client.rb +107 -0
- data/lib/vwo/packages/network_layer/handlers/request_handler.rb +37 -0
- data/lib/vwo/packages/network_layer/manager/network_manager.rb +78 -0
- data/lib/vwo/packages/network_layer/models/global_request_model.rb +105 -0
- data/lib/vwo/packages/network_layer/models/request_model.rb +145 -0
- data/lib/vwo/packages/network_layer/models/response_model.rb +45 -0
- data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +76 -0
- data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_regex_enum.rb +29 -0
- data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_value_enum.rb +26 -0
- data/lib/vwo/packages/segmentation_evaluator/enums/segment_operator_value_enum.rb +30 -0
- data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +210 -0
- data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +198 -0
- data/lib/vwo/packages/segmentation_evaluator/utils/segment_util.rb +44 -0
- data/lib/vwo/{constants.rb → packages/storage/connector.rb} +12 -10
- data/lib/vwo/packages/storage/storage.rb +45 -0
- data/lib/vwo/services/campaign_decision_service.rb +153 -0
- data/lib/vwo/services/hooks_service.rb +51 -0
- data/lib/vwo/services/logger_service.rb +83 -0
- data/lib/vwo/services/settings_service.rb +120 -0
- data/lib/vwo/services/storage_service.rb +65 -0
- data/lib/vwo/utils/campaign_util.rb +249 -0
- data/lib/vwo/utils/data_type_util.rb +105 -0
- data/lib/vwo/utils/decision_util.rb +253 -0
- data/lib/vwo/utils/function_util.rb +123 -0
- data/lib/vwo/utils/gateway_service_util.rb +101 -0
- data/lib/vwo/utils/impression_util.rb +49 -0
- data/lib/vwo/utils/log_message_util.rb +42 -0
- data/lib/vwo/utils/meg_util.rb +350 -0
- data/lib/vwo/utils/network_util.rb +235 -0
- data/lib/vwo/utils/rule_evaluation_util.rb +57 -0
- data/lib/vwo/utils/settings_util.rb +38 -0
- data/lib/vwo/utils/url_util.rb +46 -0
- data/lib/vwo/utils/uuid_util.rb +55 -0
- data/lib/vwo/vwo_builder.rb +156 -11
- data/lib/vwo/vwo_client.rb +163 -113
- data/lib/vwo.rb +49 -31
- metadata +187 -9
- data/lib/vwo/utils/request.rb +0 -89
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aada3854c27b1f02171aec6d36a2b605bca660185f85c9ed3b43f8cf00e59be6
|
4
|
+
data.tar.gz: b0867531feb107702998081a5efd74481e74841fc215f633c01ff634e90bce7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8a51b02267805bbfea0f4f9a8ae2c3bcc0432326c725fd266f267809f12806bc6f09b630cd18aa9955648094f909b2890500c32d885ec5d4d4552b3e38e222c
|
7
|
+
data.tar.gz: e140e5da27a7f43efb0383f966ca19b69a4c21ed18f0cb1e649217df8602bd863c576f05052faab968cd7fba3b61f1ecf872f95ff803250b993af533098f4034
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# Copyright 2025 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 '../enums/api_enum'
|
16
|
+
require_relative '../enums/campaign_type_enum'
|
17
|
+
require_relative '../enums/decision_types_enum'
|
18
|
+
require_relative '../decorators/storage_decorator'
|
19
|
+
require_relative '../services/storage_service'
|
20
|
+
require_relative '../models/campaign/feature_model'
|
21
|
+
require_relative '../models/campaign/campaign_model'
|
22
|
+
require_relative '../packages/segmentation_evaluator/core/segmentation_manager'
|
23
|
+
require_relative '../services/logger_service'
|
24
|
+
require_relative '../utils/campaign_util'
|
25
|
+
require_relative '../utils/rule_evaluation_util'
|
26
|
+
require_relative '../utils/impression_util'
|
27
|
+
require_relative '../utils/decision_util'
|
28
|
+
require_relative '../models/user/get_flag_response'
|
29
|
+
|
30
|
+
class FlagApi
|
31
|
+
# Get the flag for a given feature key and context
|
32
|
+
# @param feature_key [String] The key of the feature to get the flag for
|
33
|
+
# @param settings [SettingsModel] The settings for the VWO instance
|
34
|
+
# @param context [ContextModel] The context for the evaluation
|
35
|
+
# @param hooks_service [HooksService] The hooks service for the VWO instance
|
36
|
+
# @return [GetFlagResponse] The flag for the given feature key and context
|
37
|
+
def get(feature_key, settings, context, hooks_service)
|
38
|
+
is_enabled = false
|
39
|
+
rollout_variation_to_return = nil
|
40
|
+
experiment_variation_to_return = nil
|
41
|
+
should_check_for_experiments_rules = false
|
42
|
+
|
43
|
+
passed_rules_information = {} # for storing integration callback
|
44
|
+
evaluated_feature_map = {}
|
45
|
+
|
46
|
+
# Fetch feature object using the feature key
|
47
|
+
feature = get_feature_from_key(settings, feature_key)
|
48
|
+
|
49
|
+
decision = {
|
50
|
+
feature_name: feature&.get_name,
|
51
|
+
feature_id: feature&.get_id,
|
52
|
+
feature_key: feature&.get_key,
|
53
|
+
user_id: context&.get_id,
|
54
|
+
api: ApiEnum::GET_FLAG
|
55
|
+
}
|
56
|
+
|
57
|
+
storage_service = StorageService.new
|
58
|
+
stored_data = StorageDecorator.new.get_feature_from_storage(feature_key, context, storage_service)
|
59
|
+
|
60
|
+
if stored_data && stored_data[:experiment_variation_id]
|
61
|
+
if stored_data[:experiment_key]
|
62
|
+
variation = CampaignUtil.get_variation_from_campaign_key(settings, stored_data[:experiment_key], stored_data[:experiment_variation_id])
|
63
|
+
|
64
|
+
if variation
|
65
|
+
LoggerService.log(LogLevelEnum::INFO, "STORED_VARIATION_FOUND", {variationKey: variation.get_key, userId: context.get_id, experimentKey: stored_data[:experiment_key], experimentType: "experiment"})
|
66
|
+
return GetFlagResponse.new(true, variation.get_variables)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
elsif stored_data && stored_data[:rollout_key] && stored_data[:rollout_id]
|
70
|
+
variation = CampaignUtil.get_variation_from_campaign_key(settings, stored_data[:rollout_key], stored_data[:rollout_variation_id])
|
71
|
+
|
72
|
+
if variation
|
73
|
+
LoggerService.log(LogLevelEnum::INFO, "STORED_VARIATION_FOUND", {variationKey: variation.get_key, userId: context.get_id, experimentKey: stored_data[:rollout_key], experimentType: "rollout"})
|
74
|
+
LoggerService.log(LogLevelEnum::DEBUG, "EXPERIMENTS_EVALUATION_WHEN_ROLLOUT_PASSED", {userId: context.get_id})
|
75
|
+
|
76
|
+
is_enabled = true
|
77
|
+
should_check_for_experiments_rules = true
|
78
|
+
rollout_variation_to_return = variation
|
79
|
+
feature_info = {
|
80
|
+
rollout_id: stored_data[:rollout_id],
|
81
|
+
rollout_key: stored_data[:rollout_key],
|
82
|
+
rollout_variation_id: stored_data[:rollout_variation_id]
|
83
|
+
}
|
84
|
+
evaluated_feature_map[feature_key] = feature_info
|
85
|
+
passed_rules_information.merge!(feature_info)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if feature.nil?
|
90
|
+
LoggerService.log(LogLevelEnum::ERROR, "FEATURE_NOT_FOUND", {featureKey: feature_key})
|
91
|
+
return GetFlagResponse.new(false, [])
|
92
|
+
end
|
93
|
+
|
94
|
+
# Segmentation evaluation
|
95
|
+
SegmentationManager.instance.set_contextual_data(settings, feature, context)
|
96
|
+
|
97
|
+
# Get all rollout rules
|
98
|
+
rollout_rules = get_specific_rules_based_on_type(feature, CampaignTypeEnum::ROLLOUT)
|
99
|
+
|
100
|
+
if rollout_rules.any? && !is_enabled
|
101
|
+
rollout_rules_to_evaluate = []
|
102
|
+
|
103
|
+
rollout_rules.each do |rule|
|
104
|
+
result = evaluate_rule(settings, feature, rule, context, evaluated_feature_map, nil, storage_service, decision)
|
105
|
+
pre_segmentation_result = result[:pre_segmentation_result]
|
106
|
+
updated_decision = result[:updated_decision]
|
107
|
+
decision.merge!(updated_decision) if updated_decision
|
108
|
+
|
109
|
+
if pre_segmentation_result
|
110
|
+
rollout_rules_to_evaluate << rule
|
111
|
+
evaluated_feature_map[feature_key] = {
|
112
|
+
rollout_id: rule.get_id,
|
113
|
+
rollout_key: rule.get_key,
|
114
|
+
rollout_variation_id: rule.get_variations.first&.get_id
|
115
|
+
}
|
116
|
+
break
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if rollout_rules_to_evaluate.any?
|
121
|
+
passed_rollout_campaign = CampaignModel.new.model_from_dictionary(rollout_rules_to_evaluate.first)
|
122
|
+
variation = DecisionUtil.evaluate_traffic_and_get_variation(settings, passed_rollout_campaign, context.get_id)
|
123
|
+
|
124
|
+
if variation
|
125
|
+
is_enabled = true
|
126
|
+
should_check_for_experiments_rules = true
|
127
|
+
rollout_variation_to_return = variation
|
128
|
+
update_integrations_decision_object(passed_rollout_campaign, variation, passed_rules_information, decision)
|
129
|
+
|
130
|
+
create_and_send_impression_for_variation_shown(settings, passed_rollout_campaign.get_id, variation.get_id, context)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
elsif rollout_rules.empty?
|
134
|
+
LoggerService.log(LogLevelEnum::DEBUG, "EXPERIMENTS_EVALUATION_WHEN_NO_ROLLOUT_PRESENT")
|
135
|
+
should_check_for_experiments_rules = true
|
136
|
+
end
|
137
|
+
|
138
|
+
if should_check_for_experiments_rules
|
139
|
+
experiment_rules = get_all_experiment_rules(feature)
|
140
|
+
experiment_rules_to_evaluate = []
|
141
|
+
meg_group_winner_campaigns = {}
|
142
|
+
|
143
|
+
experiment_rules.each do |rule|
|
144
|
+
result = evaluate_rule(settings, feature, rule, context, evaluated_feature_map, meg_group_winner_campaigns, storage_service, decision)
|
145
|
+
pre_segmentation_result = result[:pre_segmentation_result]
|
146
|
+
whitelisted_object = result[:whitelisted_object]
|
147
|
+
updated_decision = result[:updated_decision]
|
148
|
+
decision.merge!(updated_decision) if updated_decision
|
149
|
+
|
150
|
+
if pre_segmentation_result
|
151
|
+
if whitelisted_object.nil?
|
152
|
+
experiment_rules_to_evaluate << rule
|
153
|
+
else
|
154
|
+
is_enabled = true
|
155
|
+
experiment_variation_to_return = whitelisted_object[:variation]
|
156
|
+
passed_rules_information.merge!(
|
157
|
+
experiment_id: rule.get_id,
|
158
|
+
experiment_key: rule.get_key,
|
159
|
+
experiment_variation_id: whitelisted_object[:variation_id]
|
160
|
+
)
|
161
|
+
end
|
162
|
+
break
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
if experiment_rules_to_evaluate.any?
|
167
|
+
campaign = CampaignModel.new.model_from_dictionary(experiment_rules_to_evaluate.first)
|
168
|
+
variation = DecisionUtil.evaluate_traffic_and_get_variation(settings, campaign, context.get_id)
|
169
|
+
|
170
|
+
if variation
|
171
|
+
is_enabled = true
|
172
|
+
experiment_variation_to_return = variation
|
173
|
+
update_integrations_decision_object(campaign, variation, passed_rules_information, decision)
|
174
|
+
|
175
|
+
create_and_send_impression_for_variation_shown(settings, campaign.get_id, variation.get_id, context)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Store evaluated feature in storage
|
181
|
+
if is_enabled
|
182
|
+
StorageDecorator.new.set_data_in_storage(
|
183
|
+
{ feature_key: feature_key, context: context }.merge(passed_rules_information),
|
184
|
+
storage_service
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Execute hooks
|
189
|
+
hooks_service.set(decision)
|
190
|
+
hooks_service.execute(hooks_service.get)
|
191
|
+
|
192
|
+
if feature&.get_impact_campaign&.get_campaign_id
|
193
|
+
LoggerService.log(
|
194
|
+
LogLevelEnum::INFO,
|
195
|
+
"IMPACT_ANALYSIS",
|
196
|
+
{
|
197
|
+
userId: context.get_id,
|
198
|
+
featureKey: feature_key,
|
199
|
+
status: is_enabled ? 'enabled' : 'disabled'
|
200
|
+
}
|
201
|
+
)
|
202
|
+
|
203
|
+
variation_id = is_enabled ? 2 : 1 # 2 for Variation(flag enabled), 1 for Control(flag disabled)
|
204
|
+
|
205
|
+
create_and_send_impression_for_variation_shown(
|
206
|
+
settings,
|
207
|
+
feature&.get_impact_campaign&.get_campaign_id,
|
208
|
+
variation_id,
|
209
|
+
context
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Return final evaluated feature flag
|
214
|
+
return GetFlagResponse.new(is_enabled, experiment_variation_to_return&.get_variables || rollout_variation_to_return&.get_variables || [])
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def update_integrations_decision_object(campaign, variation, passed_rules_information, decision)
|
220
|
+
if campaign.get_type == CampaignTypeEnum::ROLLOUT
|
221
|
+
passed_rules_information.merge!(
|
222
|
+
rollout_id: campaign.get_id,
|
223
|
+
rollout_key: campaign.get_key,
|
224
|
+
rollout_variation_id: variation.get_id
|
225
|
+
)
|
226
|
+
else
|
227
|
+
passed_rules_information.merge!(
|
228
|
+
experiment_id: campaign.get_id,
|
229
|
+
experiment_key: campaign.get_key,
|
230
|
+
experiment_variation_id: variation.get_id
|
231
|
+
)
|
232
|
+
end
|
233
|
+
decision.merge!(passed_rules_information)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright 2025 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 '../models/user/context_model'
|
16
|
+
require_relative '../enums/event_enum'
|
17
|
+
require_relative '../utils/network_util'
|
18
|
+
require_relative '../models/settings/settings_model'
|
19
|
+
|
20
|
+
class SetAttributeApi
|
21
|
+
# Sets multiple attributes for a user in a single network call.
|
22
|
+
# @param settings [SettingsModel] Configuration settings.
|
23
|
+
# @param attributes [Hash] Key-value map of attributes.
|
24
|
+
# @param context [ContextModel] Context containing user information.
|
25
|
+
def set_attribute(settings, attributes, context)
|
26
|
+
create_impression_for_attributes(settings, attributes, context)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Creates an impression for multiple user attributes and sends it to the server.
|
32
|
+
# @param settings [SettingsModel] Configuration settings.
|
33
|
+
# @param attributes [Hash] Key-value map of attributes.
|
34
|
+
# @param context [ContextModel] Context containing user information.
|
35
|
+
def create_impression_for_attributes(settings, attributes, context)
|
36
|
+
# Retrieve base properties for the event
|
37
|
+
properties = NetworkUtil.get_events_base_properties(
|
38
|
+
settings,
|
39
|
+
EventEnum::VWO_SYNC_VISITOR_PROP,
|
40
|
+
URI.encode_www_form_component(context.user_agent),
|
41
|
+
context.ip_address
|
42
|
+
)
|
43
|
+
|
44
|
+
# Construct payload data for multiple attributes
|
45
|
+
payload = NetworkUtil.get_attribute_payload_data(
|
46
|
+
settings,
|
47
|
+
context.id,
|
48
|
+
EventEnum::VWO_SYNC_VISITOR_PROP,
|
49
|
+
attributes,
|
50
|
+
context.user_agent,
|
51
|
+
context.ip_address
|
52
|
+
)
|
53
|
+
|
54
|
+
# Send the constructed payload via POST request
|
55
|
+
NetworkUtil.send_post_api_request(properties, payload)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Copyright 2025 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 '../enums/api_enum'
|
16
|
+
require_relative '../models/settings/settings_model'
|
17
|
+
require_relative '../models/user/context_model'
|
18
|
+
require_relative '../services/hooks_service'
|
19
|
+
require_relative '../utils/function_util'
|
20
|
+
require_relative '../utils/network_util'
|
21
|
+
require_relative '../services/logger_service'
|
22
|
+
class TrackApi
|
23
|
+
# Tracks an event with given properties and context.
|
24
|
+
# @param settings [SettingsModel] Configuration settings.
|
25
|
+
# @param event_name [String] Name of the event to track.
|
26
|
+
# @param context [ContextModel] Contextual information like user details.
|
27
|
+
# @param event_properties [Hash] Properties associated with the event.
|
28
|
+
# @param hooks_service [HooksService] Manager for handling hooks and callbacks.
|
29
|
+
# @return [Hash] A hash indicating success or failure of event tracking.
|
30
|
+
def track(settings, event_name, context, event_properties, hooks_service)
|
31
|
+
if does_event_belong_to_any_feature(event_name, settings)
|
32
|
+
# Create an impression for the track event
|
33
|
+
create_impression_for_track(settings, event_name, context, event_properties)
|
34
|
+
|
35
|
+
# Set and execute integration callback for the track event
|
36
|
+
hooks_service.set({ event_name: event_name, api: ApiEnum::TRACK })
|
37
|
+
hooks_service.execute(hooks_service.get)
|
38
|
+
|
39
|
+
return { event_name: true }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Log an error if the event does not exist
|
43
|
+
LoggerService.log(LogLevelEnum::ERROR, "EVENT_NOT_FOUND", { eventName: event_name })
|
44
|
+
|
45
|
+
{ event_name: false }
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Creates an impression for a track event and sends it via a POST API request.
|
51
|
+
# @param settings [SettingsModel] Configuration settings.
|
52
|
+
# @param event_name [String] Name of the event to track.
|
53
|
+
# @param context [ContextModel] User details.
|
54
|
+
# @param event_properties [Hash] Properties associated with the event.
|
55
|
+
def create_impression_for_track(settings, event_name, context, event_properties)
|
56
|
+
# Get base properties for the event
|
57
|
+
properties = NetworkUtil.get_events_base_properties(
|
58
|
+
settings,
|
59
|
+
event_name,
|
60
|
+
URI.encode_www_form_component(context.user_agent),
|
61
|
+
context.ip_address
|
62
|
+
)
|
63
|
+
|
64
|
+
# Prepare the payload for the track goal
|
65
|
+
payload = NetworkUtil.get_track_goal_payload_data(
|
66
|
+
settings,
|
67
|
+
context.id,
|
68
|
+
event_name,
|
69
|
+
event_properties,
|
70
|
+
context.user_agent,
|
71
|
+
context.ip_address
|
72
|
+
)
|
73
|
+
|
74
|
+
# Send the prepared payload via POST API request
|
75
|
+
NetworkUtil.send_post_api_request(properties, payload)
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright 2025 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
|
+
# Constants file for Ruby SDK
|
16
|
+
|
17
|
+
# Define the Constants module
|
18
|
+
module Constants
|
19
|
+
SDK_NAME = 'vwo-fme-ruby-sdk'.freeze
|
20
|
+
SDK_VERSION = '1.1.0'.freeze
|
21
|
+
|
22
|
+
MAX_TRAFFIC_PERCENT = 100
|
23
|
+
MAX_TRAFFIC_VALUE = 10_000
|
24
|
+
STATUS_RUNNING = 'RUNNING'.freeze
|
25
|
+
|
26
|
+
SEED_VALUE = 1
|
27
|
+
MAX_EVENTS_PER_REQUEST = 5_000
|
28
|
+
DEFAULT_REQUEST_TIME_INTERVAL = 600 # 10 minutes in seconds
|
29
|
+
DEFAULT_EVENTS_PER_REQUEST = 100
|
30
|
+
|
31
|
+
SEED_URL = 'https://vwo.com'.freeze # Define SEED_URL
|
32
|
+
HTTP_PROTOCOL = 'http'.freeze
|
33
|
+
HTTPS_PROTOCOL = 'https'.freeze
|
34
|
+
|
35
|
+
SETTINGS = 'settings'.freeze
|
36
|
+
SETTINGS_EXPIRY = 10_000_000
|
37
|
+
SETTINGS_TIMEOUT = 50_000
|
38
|
+
|
39
|
+
HOST_NAME = 'dev.visualwebsiteoptimizer.com'.freeze
|
40
|
+
SETTINGS_ENDPOINT = '/server-side/v2-settings'.freeze
|
41
|
+
WEBHOOK_SETTINGS_ENDPOINT = '/server-side/v2-pull'.freeze
|
42
|
+
LOCATION_ENDPOINT = '/getLocation'.freeze
|
43
|
+
|
44
|
+
VWO_FS_ENVIRONMENT = 'vwo_fs_environment'.freeze
|
45
|
+
|
46
|
+
RANDOM_ALGO = 1
|
47
|
+
|
48
|
+
API_VERSION = '1'.freeze
|
49
|
+
|
50
|
+
VWO_META_MEG_KEY = '_vwo_meta_meg_'.freeze
|
51
|
+
|
52
|
+
SHOULD_USE_THREADING = true
|
53
|
+
MAX_POOL_SIZE = 5
|
54
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Copyright 2025 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 '../enums/storage_enum'
|
16
|
+
require_relative '../models/campaign/feature_model'
|
17
|
+
require_relative '../models/campaign/variation_model'
|
18
|
+
require_relative '../services/storage_service'
|
19
|
+
require_relative '../models/user/context_model'
|
20
|
+
require_relative '../services/logger_service'
|
21
|
+
require_relative '../enums/log_level_enum'
|
22
|
+
class StorageDecorator
|
23
|
+
# Retrieves a feature from storage based on the feature key and user.
|
24
|
+
# @param feature_key [String] The key of the feature to retrieve.
|
25
|
+
# @param context [ContextModel] The user object.
|
26
|
+
# @param storage_service [StorageService] The storage service instance.
|
27
|
+
# @return [Hash, StorageEnum] The retrieved feature or relevant status.
|
28
|
+
def get_feature_from_storage(feature_key, context, storage_service)
|
29
|
+
campaign_map = storage_service.get_data_from_storage(feature_key, context)
|
30
|
+
|
31
|
+
case campaign_map
|
32
|
+
when StorageEnum::STORAGE_UNDEFINED, StorageEnum::NO_DATA_FOUND,
|
33
|
+
StorageEnum::CAMPAIGN_PAUSED, StorageEnum::WHITELISTED_VARIATION
|
34
|
+
nil # Return nil when there's no valid data
|
35
|
+
when StorageEnum::INCORRECT_DATA, StorageEnum::VARIATION_NOT_FOUND
|
36
|
+
campaign_map # Return the relevant error constant
|
37
|
+
else
|
38
|
+
campaign_map # Return valid stored data
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets data in storage based on the provided data object.
|
43
|
+
# @param data [Hash] The data to be stored, including feature key and user details.
|
44
|
+
# @param storage_service [StorageService] The storage service instance.
|
45
|
+
def set_data_in_storage(data, storage_service)
|
46
|
+
feature_key = data[:feature_key]
|
47
|
+
context = data[:context]
|
48
|
+
rollout_id = data[:rollout_id]
|
49
|
+
rollout_key = data[:rollout_key]
|
50
|
+
rollout_variation_id = data[:rollout_variation_id]
|
51
|
+
experiment_id = data[:experiment_id]
|
52
|
+
experiment_key = data[:experiment_key]
|
53
|
+
experiment_variation_id = data[:experiment_variation_id]
|
54
|
+
|
55
|
+
if feature_key.nil?
|
56
|
+
LoggerService.log(LogLevelEnum::ERROR, "STORING_DATA_ERROR", { key: 'featureKey' })
|
57
|
+
raise 'Feature key is missing'
|
58
|
+
end
|
59
|
+
|
60
|
+
if context.nil? || context.id.nil?
|
61
|
+
LoggerService.log(LogLevelEnum::ERROR, "STORING_DATA_ERROR", { key: 'Context or Context.id' })
|
62
|
+
raise 'Context ID is missing'
|
63
|
+
end
|
64
|
+
|
65
|
+
if rollout_key && !experiment_key && !rollout_variation_id
|
66
|
+
LoggerService.log(LogLevelEnum::ERROR, "STORING_DATA_ERROR", { key: 'Variation:(rolloutKey, experimentKey or rolloutVariationId)' })
|
67
|
+
raise 'Invalid rollout variation'
|
68
|
+
end
|
69
|
+
|
70
|
+
if experiment_key && !experiment_variation_id
|
71
|
+
LoggerService.log(LogLevelEnum::ERROR, "STORING_DATA_ERROR", { key: 'Variation:(experimentKey or rolloutVariationId)' })
|
72
|
+
raise 'Invalid experiment variation'
|
73
|
+
end
|
74
|
+
|
75
|
+
storage_service.set_data_in_storage({
|
76
|
+
feature_key: feature_key,
|
77
|
+
user_id: context.id,
|
78
|
+
rollout_id: rollout_id,
|
79
|
+
rollout_key: rollout_key,
|
80
|
+
rollout_variation_id: rollout_variation_id,
|
81
|
+
experiment_id: experiment_id,
|
82
|
+
experiment_key: experiment_key,
|
83
|
+
experiment_variation_id: experiment_variation_id
|
84
|
+
})
|
85
|
+
end
|
86
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2025 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,13 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# Singleton logger instance
|
19
|
-
def self.logger
|
20
|
-
@logger ||= Logger.new(STDOUT) # You can log to a file like 'application.log'
|
21
|
-
@logger.level = Logger::DEBUG # Set the default logging level
|
22
|
-
@logger
|
15
|
+
module ApiEnum
|
16
|
+
GET_FLAG = 'getFlag'
|
17
|
+
TRACK = 'track'
|
23
18
|
end
|
24
|
-
|
19
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright 2025 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
|
+
module CampaignTypeEnum
|
16
|
+
ROLLOUT = 'FLAG_ROLLOUT'
|
17
|
+
AB = 'FLAG_TESTING'
|
18
|
+
PERSONALIZE = 'FLAG_PERSONALIZE'
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2025 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
|
+
module DecisionTypes
|
16
|
+
CAMPAIGN_DECISION = 'CAMPAIGN_DECISION'
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright 2025 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
|
+
# Event types
|
16
|
+
module EventEnum
|
17
|
+
VWO_VARIATION_SHOWN = 'vwo_variationShown'
|
18
|
+
VWO_SYNC_VISITOR_PROP = 'vwo_syncVisitorProp'
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright 2025 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
|
+
# HTTP Headers
|
16
|
+
module HeadersEnum
|
17
|
+
USER_AGENT = 'X-Device-User-Agent'
|
18
|
+
IP = 'VWO-X-Forwarded-For'
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright 2025 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
|
+
module HooksEnum
|
16
|
+
DECISION_TYPES = DecisionTypes
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2025 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
|
+
module HttpMethodEnum
|
16
|
+
GET = 'GET'
|
17
|
+
POST = 'POST'
|
18
|
+
end
|