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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vwo/api/get_flag.rb +236 -0
  3. data/lib/vwo/api/set_attribute.rb +57 -0
  4. data/lib/vwo/api/track_event.rb +77 -0
  5. data/lib/vwo/constants/constants.rb +54 -0
  6. data/lib/vwo/decorators/storage_decorator.rb +86 -0
  7. data/lib/vwo/{utils/logger_helper.rb → enums/api_enum.rb} +5 -10
  8. data/lib/vwo/enums/campaign_type_enum.rb +19 -0
  9. data/lib/vwo/enums/decision_types_enum.rb +18 -0
  10. data/lib/vwo/enums/event_enum.rb +19 -0
  11. data/lib/vwo/enums/headers_enum.rb +20 -0
  12. data/lib/vwo/enums/hooks_enum.rb +17 -0
  13. data/lib/vwo/enums/http_method_enum.rb +18 -0
  14. data/lib/vwo/enums/log_level_enum.rb +21 -0
  15. data/lib/vwo/enums/status_enum.rb +19 -0
  16. data/lib/vwo/enums/storage_enum.rb +22 -0
  17. data/lib/vwo/enums/url_enum.rb +21 -0
  18. data/lib/vwo/models/campaign/campaign_model.rb +192 -0
  19. data/lib/vwo/models/campaign/feature_model.rb +111 -0
  20. data/lib/vwo/models/campaign/impact_campaign_model.rb +38 -0
  21. data/lib/vwo/models/campaign/metric_model.rb +44 -0
  22. data/lib/vwo/models/campaign/rule_model.rb +56 -0
  23. data/lib/vwo/models/campaign/variable_model.rb +51 -0
  24. data/lib/vwo/models/campaign/variation_model.rb +137 -0
  25. data/lib/vwo/models/gateway_service_model.rb +39 -0
  26. data/lib/vwo/models/schemas/settings_schema_validation.rb +102 -0
  27. data/lib/vwo/models/settings/settings_model.rb +85 -0
  28. data/lib/vwo/models/storage/storage_data_model.rb +44 -0
  29. data/lib/vwo/models/user/context_model.rb +100 -0
  30. data/lib/vwo/models/user/context_vwo_model.rb +38 -0
  31. data/lib/vwo/{utils/feature_flag_response.rb → models/user/get_flag_response.rb} +14 -14
  32. data/lib/vwo/models/vwo_options_model.rb +107 -0
  33. data/lib/vwo/packages/decision_maker/decision_maker.rb +60 -0
  34. data/lib/vwo/packages/logger/core/log_manager.rb +90 -0
  35. data/lib/vwo/packages/logger/core/transport_manager.rb +87 -0
  36. data/lib/vwo/packages/logger/log_message_builder.rb +70 -0
  37. data/lib/vwo/packages/logger/logger.rb +38 -0
  38. data/lib/vwo/packages/logger/transports/console_transport.rb +49 -0
  39. data/lib/vwo/packages/network_layer/client/network_client.rb +107 -0
  40. data/lib/vwo/packages/network_layer/handlers/request_handler.rb +37 -0
  41. data/lib/vwo/packages/network_layer/manager/network_manager.rb +78 -0
  42. data/lib/vwo/packages/network_layer/models/global_request_model.rb +105 -0
  43. data/lib/vwo/packages/network_layer/models/request_model.rb +145 -0
  44. data/lib/vwo/packages/network_layer/models/response_model.rb +45 -0
  45. data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +76 -0
  46. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_regex_enum.rb +29 -0
  47. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_value_enum.rb +26 -0
  48. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operator_value_enum.rb +30 -0
  49. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +210 -0
  50. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +198 -0
  51. data/lib/vwo/packages/segmentation_evaluator/utils/segment_util.rb +44 -0
  52. data/lib/vwo/{constants.rb → packages/storage/connector.rb} +12 -10
  53. data/lib/vwo/packages/storage/storage.rb +45 -0
  54. data/lib/vwo/services/campaign_decision_service.rb +153 -0
  55. data/lib/vwo/services/hooks_service.rb +51 -0
  56. data/lib/vwo/services/logger_service.rb +83 -0
  57. data/lib/vwo/services/settings_service.rb +120 -0
  58. data/lib/vwo/services/storage_service.rb +65 -0
  59. data/lib/vwo/utils/campaign_util.rb +249 -0
  60. data/lib/vwo/utils/data_type_util.rb +105 -0
  61. data/lib/vwo/utils/decision_util.rb +253 -0
  62. data/lib/vwo/utils/function_util.rb +123 -0
  63. data/lib/vwo/utils/gateway_service_util.rb +101 -0
  64. data/lib/vwo/utils/impression_util.rb +49 -0
  65. data/lib/vwo/utils/log_message_util.rb +42 -0
  66. data/lib/vwo/utils/meg_util.rb +350 -0
  67. data/lib/vwo/utils/network_util.rb +235 -0
  68. data/lib/vwo/utils/rule_evaluation_util.rb +57 -0
  69. data/lib/vwo/utils/settings_util.rb +38 -0
  70. data/lib/vwo/utils/url_util.rb +46 -0
  71. data/lib/vwo/utils/uuid_util.rb +55 -0
  72. data/lib/vwo/vwo_builder.rb +156 -11
  73. data/lib/vwo/vwo_client.rb +163 -113
  74. data/lib/vwo.rb +49 -31
  75. metadata +187 -9
  76. data/lib/vwo/utils/request.rb +0 -89
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f333409ec82d99443663437007b9b0934fe205e07e1cef53d905c911faf7980
4
- data.tar.gz: 7a866f482484ff481d503a90bca9534bbce6832daf99e81a1791a36d0e41e290
3
+ metadata.gz: aada3854c27b1f02171aec6d36a2b605bca660185f85c9ed3b43f8cf00e59be6
4
+ data.tar.gz: b0867531feb107702998081a5efd74481e74841fc215f633c01ff634e90bce7c
5
5
  SHA512:
6
- metadata.gz: 0db232a732e10984da13efbc1b47a4e9bb72103a9453da6f910e4c76b43f35b507db4fbd556175e8428c10d9dd17c89fc45b8d097435b1e2133b247d3e101686
7
- data.tar.gz: 80119347d3b874637c6af47aa2ee91bdc2fe095a665c4b63de3d8761466e7e587557ad42c24cae879630a06fff211decec14328441fbf0cbf8175ef23ab389a2
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 2024 Wingify Software Pvt. Ltd.
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
- require 'logger'
16
-
17
- module LoggerHelper
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
- end
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