vwo-fme-ruby-sdk 1.0.0 → 1.2.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/lib/resources/debug_messages.json +13 -0
  3. data/lib/resources/error_messages.json +30 -0
  4. data/lib/resources/info_messages.json +33 -0
  5. data/lib/resources/warn_messages.json +1 -0
  6. data/lib/vwo/api/get_flag.rb +236 -0
  7. data/lib/vwo/api/set_attribute.rb +57 -0
  8. data/lib/vwo/api/track_event.rb +77 -0
  9. data/lib/vwo/constants/constants.rb +54 -0
  10. data/lib/vwo/decorators/storage_decorator.rb +86 -0
  11. data/lib/vwo/{utils/logger_helper.rb → enums/api_enum.rb} +5 -10
  12. data/lib/vwo/enums/campaign_type_enum.rb +19 -0
  13. data/lib/vwo/enums/decision_types_enum.rb +18 -0
  14. data/lib/vwo/enums/event_enum.rb +19 -0
  15. data/lib/vwo/enums/headers_enum.rb +20 -0
  16. data/lib/vwo/enums/hooks_enum.rb +17 -0
  17. data/lib/vwo/enums/http_method_enum.rb +18 -0
  18. data/lib/vwo/enums/log_level_enum.rb +21 -0
  19. data/lib/vwo/enums/status_enum.rb +19 -0
  20. data/lib/vwo/enums/storage_enum.rb +22 -0
  21. data/lib/vwo/enums/url_enum.rb +21 -0
  22. data/lib/vwo/models/campaign/campaign_model.rb +192 -0
  23. data/lib/vwo/models/campaign/feature_model.rb +111 -0
  24. data/lib/vwo/models/campaign/impact_campaign_model.rb +38 -0
  25. data/lib/vwo/models/campaign/metric_model.rb +44 -0
  26. data/lib/vwo/models/campaign/rule_model.rb +56 -0
  27. data/lib/vwo/models/campaign/variable_model.rb +51 -0
  28. data/lib/vwo/models/campaign/variation_model.rb +137 -0
  29. data/lib/vwo/models/gateway_service_model.rb +39 -0
  30. data/lib/vwo/models/schemas/settings_schema_validation.rb +102 -0
  31. data/lib/vwo/models/settings/settings_model.rb +85 -0
  32. data/lib/vwo/models/storage/storage_data_model.rb +44 -0
  33. data/lib/vwo/models/user/context_model.rb +100 -0
  34. data/lib/vwo/models/user/context_vwo_model.rb +38 -0
  35. data/lib/vwo/{utils/feature_flag_response.rb → models/user/get_flag_response.rb} +14 -14
  36. data/lib/vwo/models/vwo_options_model.rb +107 -0
  37. data/lib/vwo/packages/decision_maker/decision_maker.rb +60 -0
  38. data/lib/vwo/packages/logger/core/log_manager.rb +90 -0
  39. data/lib/vwo/packages/logger/core/transport_manager.rb +87 -0
  40. data/lib/vwo/packages/logger/log_message_builder.rb +70 -0
  41. data/lib/vwo/packages/logger/logger.rb +38 -0
  42. data/lib/vwo/packages/logger/transports/console_transport.rb +49 -0
  43. data/lib/vwo/packages/network_layer/client/network_client.rb +107 -0
  44. data/lib/vwo/packages/network_layer/handlers/request_handler.rb +37 -0
  45. data/lib/vwo/packages/network_layer/manager/network_manager.rb +78 -0
  46. data/lib/vwo/packages/network_layer/models/global_request_model.rb +105 -0
  47. data/lib/vwo/packages/network_layer/models/request_model.rb +145 -0
  48. data/lib/vwo/packages/network_layer/models/response_model.rb +45 -0
  49. data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +76 -0
  50. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_regex_enum.rb +29 -0
  51. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_value_enum.rb +26 -0
  52. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operator_value_enum.rb +30 -0
  53. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +210 -0
  54. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +198 -0
  55. data/lib/vwo/packages/segmentation_evaluator/utils/segment_util.rb +44 -0
  56. data/lib/vwo/{constants.rb → packages/storage/connector.rb} +12 -10
  57. data/lib/vwo/packages/storage/storage.rb +45 -0
  58. data/lib/vwo/services/campaign_decision_service.rb +153 -0
  59. data/lib/vwo/services/hooks_service.rb +51 -0
  60. data/lib/vwo/services/logger_service.rb +83 -0
  61. data/lib/vwo/services/settings_service.rb +120 -0
  62. data/lib/vwo/services/storage_service.rb +65 -0
  63. data/lib/vwo/utils/campaign_util.rb +249 -0
  64. data/lib/vwo/utils/data_type_util.rb +105 -0
  65. data/lib/vwo/utils/decision_util.rb +253 -0
  66. data/lib/vwo/utils/function_util.rb +123 -0
  67. data/lib/vwo/utils/gateway_service_util.rb +101 -0
  68. data/lib/vwo/utils/impression_util.rb +49 -0
  69. data/lib/vwo/utils/log_message_util.rb +42 -0
  70. data/lib/vwo/utils/meg_util.rb +350 -0
  71. data/lib/vwo/utils/network_util.rb +235 -0
  72. data/lib/vwo/utils/rule_evaluation_util.rb +57 -0
  73. data/lib/vwo/utils/settings_util.rb +38 -0
  74. data/lib/vwo/utils/url_util.rb +46 -0
  75. data/lib/vwo/utils/uuid_util.rb +55 -0
  76. data/lib/vwo/vwo_builder.rb +156 -11
  77. data/lib/vwo/vwo_client.rb +163 -113
  78. data/lib/vwo.rb +49 -31
  79. metadata +191 -9
  80. data/lib/vwo/utils/request.rb +0 -89
@@ -0,0 +1,46 @@
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 '../services/settings_service'
16
+
17
+ class UrlUtil
18
+ @collection_prefix = nil
19
+
20
+ class << self
21
+ attr_accessor :collection_prefix
22
+
23
+ # Initializes the UrlUtil with an optional collection prefix.
24
+ #
25
+ # @param collection_prefix [String] Optional prefix for URL collections.
26
+ # @return [UrlUtil] The singleton instance of UrlUtil with updated properties.
27
+ def init(collection_prefix: nil)
28
+ @collection_prefix = collection_prefix if collection_prefix.is_a?(String)
29
+ self
30
+ end
31
+
32
+ # Retrieves the base URL.
33
+ #
34
+ # @return [String] The base URL.
35
+ def get_base_url
36
+ base_url = SettingsService.instance.hostname
37
+
38
+ return base_url if SettingsService.instance.is_gateway_service_provided
39
+
40
+ # Construct URL with collection_prefix if it exists
41
+ return "#{base_url}/#{@collection_prefix}" if @collection_prefix
42
+
43
+ base_url
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,55 @@
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 'uuidtools'
16
+ require 'securerandom'
17
+
18
+ SEED_URL = 'https://vwo.com' # Replace with actual SEED_URL
19
+
20
+ class UUIDUtil
21
+ # Generates a random UUID based on an API key.
22
+ #
23
+ # @param sdk_key [String] The API key used to generate a namespace for the UUID.
24
+ # @return [String] A random UUID string.
25
+ def self.get_random_uuid(sdk_key)
26
+ namespace = UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, sdk_key)
27
+ random_uuid = UUIDTools::UUID.sha1_create(namespace, SecureRandom.uuid)
28
+ random_uuid.to_s
29
+ end
30
+
31
+ # Generates a UUID for a user based on their user_id and account_id.
32
+ #
33
+ # @param user_id [String] The user's ID.
34
+ # @param account_id [String] The account ID associated with the user.
35
+ # @return [String] A UUID string formatted without dashes and in uppercase.
36
+ def self.get_uuid(user_id, account_id)
37
+ vwo_namespace = UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, SEED_URL)
38
+ user_id_namespace = generate_uuid(account_id, vwo_namespace)
39
+ uuid_for_user_id_account_id = generate_uuid(user_id, user_id_namespace)
40
+
41
+ uuid_for_user_id_account_id.to_s.delete('-').upcase
42
+ end
43
+
44
+ # Helper function to generate a UUID v5 based on a name and a namespace.
45
+ #
46
+ # @param name [String] The name from which to generate the UUID.
47
+ # @param namespace [UUIDTools::UUID] The namespace used to generate the UUID.
48
+ # @return [UUIDTools::UUID] A UUID string or nil if inputs are invalid.
49
+ def self.generate_uuid(name, namespace)
50
+ return nil if name.nil? || namespace.nil?
51
+ # Convert name to string to handle integer inputs
52
+ name_str = name.to_s
53
+ UUIDTools::UUID.sha1_create(namespace, name_str)
54
+ end
55
+ 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,18 +12,163 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require_relative 'constants'
16
- require_relative 'utils/request' # Include your request utilities
15
+ # require 'json'
16
+ # require 'uri'
17
+ require_relative './enums/log_level_enum'
18
+ require_relative 'vwo_client'
19
+ require_relative './services/settings_service'
20
+ require_relative './packages/storage/storage'
21
+ require_relative './packages/network_layer/manager/network_manager'
22
+ require_relative './packages/segmentation_evaluator/core/segmentation_manager'
23
+ require_relative './services/logger_service'
17
24
 
18
- module VWO
19
- class VWOBuilder
20
- def initialize(options)
21
- @options = options
25
+ class VWOBuilder
26
+ attr_reader :settings, :storage, :log_manager, :is_settings_fetch_in_progress, :vwo_instance
27
+
28
+ # Initialize the VWOBuilder with the given options
29
+ # @param options [Hash] The options for the VWOBuilder
30
+ def initialize(options)
31
+ @options = options
32
+ @settings = nil
33
+ @storage = nil
34
+ @log_manager = nil
35
+ @is_settings_fetch_in_progress = false
36
+ @vwo_instance = nil
37
+ end
38
+
39
+ # Set the network manager
40
+ # @return [VWOBuilder] The VWOBuilder instance
41
+ def set_network_manager
42
+ begin
43
+ network_instance = NetworkManager.instance(@options[:threading] || {})
44
+ network_instance.attach_client(@options[:network][:client]) if @options[:network] && @options[:network][:client]
45
+ LoggerService.log(LogLevelEnum::DEBUG, "SERVICE_INITIALIZED", {service: "Network Layer"})
46
+ network_instance.get_config.set_development_mode(@options[:is_development_mode]) if @options[:is_development_mode]
47
+ self
48
+ rescue StandardError => e
49
+ LoggerService.log(LogLevelEnum::ERROR, "Failed to initialize network manager: #{e.message}", nil)
50
+ self
51
+ end
52
+ end
53
+
54
+ # Set the segmentation manager
55
+ # @return [VWOBuilder] The VWOBuilder instance
56
+ def set_segmentation
57
+ SegmentationManager.instance.attach_evaluator(@options[:segmentation]) if @options[:segmentation]
58
+ LoggerService.log(LogLevelEnum::DEBUG, "SERVICE_INITIALIZED", {service: "Segmentation Evaluator"})
59
+ self
60
+ end
61
+
62
+ # Fetch the settings from the server
63
+ # @param force [Boolean] Whether to force the fetch of settings
64
+ # @return [Hash] The settings
65
+ def fetch_settings(force = false)
66
+ return @settings if !force && @settings
67
+
68
+ @is_settings_fetch_in_progress = true
69
+ settings = SettingsService.new(@options).get_settings(force)
70
+ @is_settings_fetch_in_progress = false
71
+ @settings = settings unless force
72
+ settings
73
+ end
74
+
75
+ # Get the settings from the server
76
+ # @param force [Boolean] Whether to force the fetch of settings
77
+ # @return [Hash] The settings
78
+ def get_settings(force = false)
79
+ return @settings if !force && @settings
80
+
81
+ begin
82
+ fetch_settings(force)
83
+ rescue StandardError => e
84
+ LoggerService.log(LogLevelEnum::ERROR, "Failed to fetch settings: #{e.message}", nil)
85
+ {}
86
+ end
87
+ end
88
+
89
+ # Set the storage
90
+ # @return [VWOBuilder] The VWOBuilder instance
91
+ def set_storage
92
+ @storage = @options[:storage] ? Storage.instance.attach_connector(@options[:storage]) : nil
93
+ LoggerService.log(LogLevelEnum::DEBUG, "SERVICE_INITIALIZED", {service: "Storage"})
94
+ self
95
+ end
96
+
97
+ # Set the settings service
98
+ # @return [VWOBuilder] The VWOBuilder instance
99
+ def set_settings_service
100
+ @settings_service = SettingsService.new(@options)
101
+ self
102
+ end
103
+
104
+ # Set the logger
105
+ # @return [VWOBuilder] The VWOBuilder instance
106
+ def set_logger
107
+ begin
108
+ @log_manager = LoggerService.new(@options[:logger] || {})
109
+ LoggerService.log(LogLevelEnum::DEBUG, "SERVICE_INITIALIZED", {service: "Logger"})
110
+ rescue => e
111
+ puts "Got error while setting logger: #{e.message}"
112
+ end
113
+ self
114
+ end
115
+
116
+ # Initialize the polling
117
+ # @return [VWOBuilder] The VWOBuilder instance
118
+ def init_polling
119
+ return self unless @options[:poll_interval]
120
+
121
+ unless @options[:poll_interval].is_a?(Numeric)
122
+ LoggerService.log(LogLevelEnum::ERROR, "INIT_OPTIONS_INVALID", {
123
+ key: 'poll_interval',
124
+ correctType: 'number'
125
+ })
126
+ return self
22
127
  end
23
128
 
24
- # Initializes the HTTP client for VWOBuilder
25
- def init_client
26
- Utils::Request.set_base_url(@options[:gateway_service_url] || Constants::HTTPS_PROTOCOL + Constants::BASE_URL)
129
+ # Check if the polling interval is greater than or equal to 1000
130
+ unless @options[:poll_interval] >= 1000
131
+ LoggerService.log(LogLevelEnum::ERROR, "INIT_OPTIONS_INVALID", {
132
+ key: 'poll_interval',
133
+ correctType: 'number'
134
+ })
135
+ return self
136
+ end
137
+
138
+ check_and_poll
139
+ self
140
+ end
141
+
142
+ # Build the VWO instance
143
+ # @param settings [Hash] The settings for the VWO instance
144
+ # @return [VWOClient] The VWO instance
145
+ def build(settings)
146
+ @vwo_instance = VWOClient.new(settings, @options)
147
+ @vwo_instance
148
+ end
149
+
150
+ # This method is used to check and poll the settings from the server
151
+ # @return [VWOBuilder] The VWOBuilder instance
152
+ def check_and_poll
153
+ polling_interval = @options[:poll_interval]
154
+
155
+ @thread_pool = NetworkManager.instance.get_client.get_thread_pool
156
+ @thread_pool.post do
157
+ loop do
158
+ sleep(polling_interval / 1000.0)
159
+ begin
160
+ latest_settings = fetch_settings(true)
161
+ if latest_settings.to_json != @settings.to_json
162
+ @settings = latest_settings
163
+ LoggerService.log(LogLevelEnum::INFO, "POLLING_SET_SETTINGS")
164
+ @vwo_instance.update_settings(latest_settings.clone, false) if @vwo_instance
165
+ else
166
+ LoggerService.log(LogLevelEnum::INFO, "POLLING_NO_CHANGE_IN_SETTINGS")
167
+ end
168
+ rescue StandardError => e
169
+ LoggerService.log(LogLevelEnum::ERROR, "POLLING_FETCH_SETTINGS_FAILED")
170
+ end
171
+ end
27
172
  end
28
173
  end
29
- end
174
+ 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,131 +12,181 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'json'
16
- require_relative 'utils/logger_helper'
17
- require_relative 'constants'
18
- require_relative 'utils/request'
19
- require_relative 'utils/feature_flag_response'
20
-
21
- module VWO
22
- # VWOClient class provides methods to interact with the VWO feature flag system,
23
- # including retrieving feature flags, tracking events, and setting attributes.
24
- class VWOClient
25
- # Makes the `options` instance variable private and only accessible within the class.
26
- private attr_reader :options
27
-
28
- # Initializes a new instance of the VWOClient.
29
- #
30
- # @param [Hash] options Configuration options like account_id and sdk_key.
31
- def initialize(options)
32
- @options = options
15
+ require_relative 'services/settings_service'
16
+ require_relative 'models/user/context_model'
17
+ require_relative 'api/get_flag'
18
+ require_relative 'api/set_attribute'
19
+ require_relative 'api/track_event'
20
+ require_relative 'utils/url_util'
21
+ require_relative 'utils/settings_util'
22
+ require_relative 'services/logger_service'
23
+ require_relative 'enums/log_level_enum'
24
+ require_relative 'utils/network_util'
25
+ require_relative 'models/schemas/settings_schema_validation'
26
+
27
+ class VWOClient
28
+ attr_accessor :settings, :original_settings
29
+ attr_reader :options
30
+
31
+ def initialize(settings, options)
32
+ @options = options
33
+ @settings = settings
34
+ @original_settings = settings.dup
35
+
36
+ begin
37
+ set_settings_and_add_campaigns_to_rules(settings, self)
38
+ UrlUtil.init(collection_prefix: @settings.get_collection_prefix)
39
+ rescue StandardError => e
40
+ LoggerService.log(LogLevelEnum::ERROR, "Error setting and adding campaigns to rules message: #{e.message}", nil)
33
41
  end
42
+ LoggerService.log(LogLevelEnum::INFO, "CLIENT_INITIALIZED")
43
+ self
44
+ end
34
45
 
35
- # Fetches a feature flag for a given feature_key and context.
36
- #
37
- # @param [String] feature_key The unique identifier for the feature flag.
38
- # @param [Hash] context The context data, which must include a `:id` for user identification.
39
- #
40
- # @return [FeatureFlagResponse] Returns a FeatureFlagResponse with the status of the feature flag and any associated variables.
41
- # Returns `isEnabled: false` and empty variables if any error occurs.
42
- #
43
- # @raise [StandardError] Raises an error if `feature_key`, `context`, or `userId` are missing or invalid.
44
- def get_flag(feature_key, context)
45
- # Raise an error if the SDK is not initialized with options.
46
- raise 'VWO is not initialized' if @options.nil?
47
-
48
- # Validate that feature_key and context are present, and userId is in context.
49
- raise 'feature_key is required to get the feature flag' if feature_key.nil? || feature_key.empty?
50
- raise 'context is required to get the feature flag' if context.nil?
51
- raise 'userId is required for flag evaluation, please provide id in context' if context[:id].nil? || context[:id].empty?
52
-
53
- # Add the feature key to the context.
54
- context['featureKey'] = feature_key
55
-
56
- # Construct the API endpoint for getting the feature flag.
57
- endpoint = "#{Constants::ENDPOINT_GET_FLAG}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
58
-
59
- # Send a POST request to retrieve the feature flag.
60
- response = Utils::Request.send_post_request(endpoint, context)
61
-
62
- # If a response is received, parse it and return a FeatureFlagResponse.
63
- if response
64
- parsed_response = JSON.parse(response)
65
- return FeatureFlagResponse.new(parsed_response['isEnabled'], parsed_response['variables'])
66
- else
67
- # Return a default disabled response if no response was received.
68
- return FeatureFlagResponse.new(false, [])
46
+ # Get the flag for a given feature key and context
47
+ # @param feature_key [String] The key of the feature to get the flag for
48
+ # @param context [Hash] The context of the user
49
+ # @return [GetFlagResponse] The flag for the given feature key and context
50
+ def get_flag(feature_key, context)
51
+ api_name = 'get_flag'
52
+ error_response = GetFlagResponse.new(false, [])
53
+
54
+ begin
55
+ hooks_service = HooksService.new(@options)
56
+ LoggerService.log(LogLevelEnum::DEBUG, "API_CALLED", {apiName: api_name})
57
+
58
+ unless feature_key.is_a?(String) && !feature_key.empty?
59
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'feature_key', type: feature_key.class.name , correctType: 'String'})
60
+ raise TypeError, 'feature_key should be a non-empty string'
61
+ end
62
+ unless SettingsSchema.new.is_settings_valid(@original_settings)
63
+ LoggerService.log(LogLevelEnum::ERROR, "API_SETTING_INVALID")
64
+ raise TypeError, 'Invalid Settings'
65
+ end
66
+ unless context.is_a?(Hash)
67
+ LoggerService.log(LogLevelEnum::ERROR, "API_CONTEXT_INVALID")
68
+ raise TypeError, 'Invalid context'
69
69
  end
70
+ unless context[:id].is_a?(String) && !context[:id].empty?
71
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'context.id', type: context[:id].class.name, correctType: 'String'})
72
+ raise TypeError, 'Invalid context, id should be a non-empty string'
73
+ end
74
+
75
+ context_model = ContextModel.new.model_from_dictionary(context)
76
+ FlagApi.new.get(feature_key, @settings, context_model, hooks_service)
70
77
  rescue StandardError => e
71
- # Log the error and return a default FeatureFlagResponse with `isEnabled: false`.
72
- LoggerHelper.logger.error("Error in get_flag: #{e.message}")
73
- return FeatureFlagResponse.new(false, [])
78
+ LoggerService.log(LogLevelEnum::ERROR, "API_THROW_ERROR", {apiName: api_name, err: e.message})
79
+ error_response
74
80
  end
81
+ end
75
82
 
76
- # Tracks an event for a given event_name and context.
77
- #
78
- # @param [String] event_name The name of the event to track.
79
- # @param [Hash] context The context data, which must include a `:id` for user identification.
80
- # @param [Hash] event_properties Optional properties related to the event.
81
- #
82
- # @return [String, nil] The response from the server, or nil if an error occurred.
83
- #
84
- # @raise [StandardError] Raises an error if `event_name`, `context`, or `userId` are missing or invalid.
85
- def track_event(event_name, context, event_properties = {})
86
- # Raise an error if the SDK is not initialized with options.
87
- raise 'VWO is not initialized' if @options.nil?
88
-
89
- # Validate that event_name and userId in context are present.
90
- raise 'event_name is required to track the event' if event_name.nil? || event_name.empty?
91
- raise 'userId is required to track the event, please provide id in context' if context.nil? || context[:id].nil? || context[:id].empty?
92
-
93
- # Add event details to the context.
94
- context['eventName'] = event_name
95
- context['eventProperties'] = event_properties
96
-
97
- # Construct the API endpoint for tracking the event.
98
- endpoint = "#{Constants::ENDPOINT_TRACK_EVENT}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
99
-
100
- # Send a POST request to track the event.
101
- response = Utils::Request.send_post_request(endpoint, context)
102
-
103
- # Return the server response.
104
- response
83
+ # Track an event with given properties and context
84
+ # @param event_name [String] The name of the event to track
85
+ # @param context [Hash] The context of the user
86
+ # @param event_properties [Hash] The properties of the event
87
+ # @return [Hash] The result of the event tracking
88
+ def track_event(event_name, context, event_properties = {})
89
+ api_name = 'track_event'
90
+
91
+ begin
92
+ hooks_service = HooksService.new(@options)
93
+ LoggerService.log(LogLevelEnum::DEBUG, "API_CALLED", {apiName: api_name})
94
+
95
+ unless event_name.is_a?(String) && !event_name.empty?
96
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'event_name', type: event_name.class.name, correctType: 'String'})
97
+ raise TypeError, 'event_name should be a non-empty string'
98
+ end
99
+ unless event_properties.is_a?(Hash)
100
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'event_properties', type: event_properties.class.name, correctType: 'Hash'})
101
+ raise TypeError, 'event_properties should be a hash'
102
+ end
103
+ unless SettingsSchema.new.is_settings_valid(@original_settings)
104
+ LoggerService.log(LogLevelEnum::ERROR, "API_SETTING_INVALID")
105
+ raise TypeError, 'Invalid Settings'
106
+ end
107
+ unless context[:id].is_a?(String) && !context[:id].empty?
108
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'context.id', type: context[:id].class.name, correctType: 'String'})
109
+ raise TypeError, 'Invalid context, id should be a non-empty string'
110
+ end
111
+
112
+ context_model = ContextModel.new.model_from_dictionary(context)
113
+ TrackApi.new.track(@settings, event_name, context_model, event_properties, hooks_service)
105
114
  rescue StandardError => e
106
- # Log the error if any occurs during event tracking.
107
- LoggerHelper.logger.error("Error tracking event: #{e.message}")
115
+ LoggerService.log(LogLevelEnum::ERROR, "API_THROW_ERROR", {apiName: api_name, err: e.message})
116
+ { event_name: false }
108
117
  end
118
+ end
109
119
 
110
- # Sets an attribute for a given user context.
111
- #
112
- # @param [String] attribute_key The key of the attribute to set.
113
- # @param [String] attribute_value The value of the attribute to set.
114
- # @param [Hash] context The context data, which must include a `:id` for user identification.
115
- #
116
- # @return [String, nil] The response from the server, or nil if an error occurred.
117
- #
118
- # @raise [StandardError] Raises an error if `attribute_key`, `attribute_value`, or `userId` are missing or invalid.
119
- def set_attribute(attribute_key, attribute_value, context)
120
- # Raise an error if the SDK is not initialized with options.
121
- raise 'VWO is not initialized' if @options.nil?
122
-
123
- # Validate that attribute_key, attribute_value, and userId in context are present.
124
- raise 'attribute_key is required for set_attribute' if attribute_key.nil? || attribute_key.empty?
125
- raise 'attribute_value is required for set_attribute' if attribute_value.nil?
126
- raise 'userId is required to set attribute, please provide id in context' if context.nil? || context[:id].nil? || context[:id].empty?
120
+ # Set attributes for a given context
121
+ # @param attributes [Hash] The attributes to set
122
+ # @param context [Hash] The context of the user
123
+ # @return [Hash] The result of the attribute setting
124
+ def set_attribute(attributes, context = nil)
125
+ api_name = 'set_attribute'
126
+
127
+ begin
128
+ LoggerService.log(LogLevelEnum::DEBUG, "API_CALLED", {apiName: api_name})
129
+
130
+ unless attributes.is_a?(Hash) && !attributes.empty?
131
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'attributes', type: attributes.class.name, correctType: 'Hash'})
132
+ raise TypeError, 'Attributes should be a hash with key-value pairs and non-empty'
133
+ end
134
+ unless context.is_a?(Hash)
135
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'context', type: context.class.name, correctType: 'Hash'})
136
+ raise TypeError, 'Invalid context'
137
+ end
138
+ unless context[:id].is_a?(String) && !context[:id].empty?
139
+ LoggerService.log(LogLevelEnum::ERROR, "API_INVALID_PARAM", {apiName: api_name, key: 'context.id', type: context[:id].class.name, correctType: 'String'})
140
+ raise TypeError, 'Invalid context, id should be a non-empty string'
141
+ end
142
+ unless SettingsSchema.new.is_settings_valid(@original_settings)
143
+ LoggerService.log(LogLevelEnum::ERROR, "API_SETTING_INVALID")
144
+ raise TypeError, 'Invalid Settings'
145
+ end
146
+
147
+ context_model = ContextModel.new.model_from_dictionary(context)
148
+ SetAttributeApi.new.set_attribute(@settings, attributes, context_model)
149
+ rescue StandardError => e
150
+ LoggerService.log(LogLevelEnum::ERROR, "API_THROW_ERROR", {apiName: api_name, err: e.message})
151
+ end
152
+ end
127
153
 
128
- # Add the attribute details to the context.
129
- context['attributeKey'] = attribute_key
130
- context['attributeValue'] = attribute_value
154
+ # Update the settings of the VWO client instance
155
+ # @param settings [Hash] The settings to update with (optional)
156
+ # @param is_via_webhook [Boolean] Whether the update is via webhook (default: true)
157
+ # @return [void]
158
+ def update_settings(settings = nil, is_via_webhook = true)
159
+ api_name = 'update_settings'
160
+
161
+ begin
162
+ LoggerService.log(LogLevelEnum::DEBUG, "API_CALLED", {apiName: api_name})
163
+
164
+ # Fetch settings from server or use provided settings if not empty
165
+ settings_to_update = if settings.nil? || settings.empty?
166
+ SettingsService.instance.fetch_settings(is_via_webhook)
167
+ else
168
+ settings
169
+ end
131
170
 
132
- # Construct the API endpoint for setting the attribute.
133
- endpoint = "#{Constants::ENDPOINT_SET_ATTRIBUTE}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
171
+ # Validate settings schema
172
+ unless SettingsSchema.new.is_settings_valid(settings_to_update)
173
+ LoggerService.log(LogLevelEnum::ERROR, "API_SETTING_INVALID")
174
+ raise TypeError, 'Invalid Settings'
175
+ end
134
176
 
135
- # Send a POST request to set the attribute.
136
- Utils::Request.send_post_request(endpoint, context)
177
+ # Set the settings on the client instance
178
+ set_settings_and_add_campaigns_to_rules(settings_to_update, self)
179
+ LoggerService.log(LogLevelEnum::INFO, "SETTINGS_UPDATED", {apiName: api_name, isViaWebhook: is_via_webhook})
137
180
  rescue StandardError => e
138
- # Log the error if any occurs during setting the attribute.
139
- LoggerHelper.logger.error("Error setting attribute: #{e.message}")
181
+ LoggerService.log(
182
+ LogLevelEnum::ERROR,
183
+ "SETTINGS_FETCH_FAILED",
184
+ {
185
+ apiName: api_name,
186
+ isViaWebhook: is_via_webhook,
187
+ err: e.message
188
+ }
189
+ )
140
190
  end
141
191
  end
142
192
  end