vwo-fme-ruby-sdk 1.2.0 → 1.3.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 +8 -1
  3. data/lib/resources/error_messages.json +5 -1
  4. data/lib/resources/info_messages.json +9 -1
  5. data/lib/vwo/api/get_flag.rb +30 -27
  6. data/lib/vwo/api/set_attribute.rb +10 -3
  7. data/lib/vwo/api/track_event.rb +11 -3
  8. data/lib/vwo/constants/constants.rb +6 -2
  9. data/lib/vwo/decorators/storage_decorator.rb +1 -1
  10. data/lib/vwo/enums/api_enum.rb +1 -1
  11. data/lib/vwo/enums/campaign_type_enum.rb +1 -1
  12. data/lib/vwo/enums/decision_types_enum.rb +1 -1
  13. data/lib/vwo/enums/event_enum.rb +1 -1
  14. data/lib/vwo/enums/headers_enum.rb +1 -1
  15. data/lib/vwo/enums/hooks_enum.rb +1 -1
  16. data/lib/vwo/enums/http_method_enum.rb +1 -1
  17. data/lib/vwo/enums/log_level_enum.rb +1 -1
  18. data/lib/vwo/enums/status_enum.rb +1 -1
  19. data/lib/vwo/enums/storage_enum.rb +1 -1
  20. data/lib/vwo/enums/url_enum.rb +2 -1
  21. data/lib/vwo/models/campaign/campaign_model.rb +1 -1
  22. data/lib/vwo/models/campaign/feature_model.rb +1 -1
  23. data/lib/vwo/models/campaign/impact_campaign_model.rb +1 -1
  24. data/lib/vwo/models/campaign/metric_model.rb +1 -1
  25. data/lib/vwo/models/campaign/rule_model.rb +1 -1
  26. data/lib/vwo/models/campaign/variable_model.rb +1 -1
  27. data/lib/vwo/models/campaign/variation_model.rb +1 -1
  28. data/lib/vwo/models/gateway_service_model.rb +1 -1
  29. data/lib/vwo/models/schemas/settings_schema_validation.rb +1 -1
  30. data/lib/vwo/models/settings/settings_model.rb +8 -2
  31. data/lib/vwo/models/storage/storage_data_model.rb +1 -1
  32. data/lib/vwo/models/user/context_model.rb +1 -1
  33. data/lib/vwo/models/user/context_vwo_model.rb +1 -1
  34. data/lib/vwo/models/user/get_flag_response.rb +1 -1
  35. data/lib/vwo/models/vwo_options_model.rb +1 -1
  36. data/lib/vwo/packages/decision_maker/decision_maker.rb +1 -1
  37. data/lib/vwo/packages/logger/core/log_manager.rb +1 -1
  38. data/lib/vwo/packages/logger/core/transport_manager.rb +1 -1
  39. data/lib/vwo/packages/logger/log_message_builder.rb +1 -1
  40. data/lib/vwo/packages/logger/logger.rb +1 -1
  41. data/lib/vwo/packages/logger/transports/console_transport.rb +1 -1
  42. data/lib/vwo/packages/network_layer/client/network_client.rb +39 -25
  43. data/lib/vwo/packages/network_layer/handlers/request_handler.rb +1 -1
  44. data/lib/vwo/packages/network_layer/manager/network_manager.rb +6 -4
  45. data/lib/vwo/packages/network_layer/models/global_request_model.rb +1 -1
  46. data/lib/vwo/packages/network_layer/models/request_model.rb +1 -1
  47. data/lib/vwo/packages/network_layer/models/response_model.rb +9 -1
  48. data/lib/vwo/packages/segmentation_evaluator/core/segmentation_manager.rb +1 -1
  49. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_regex_enum.rb +1 -1
  50. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operand_value_enum.rb +1 -1
  51. data/lib/vwo/packages/segmentation_evaluator/enums/segment_operator_value_enum.rb +1 -1
  52. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +1 -1
  53. data/lib/vwo/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +1 -1
  54. data/lib/vwo/packages/segmentation_evaluator/utils/segment_util.rb +1 -1
  55. data/lib/vwo/packages/storage/connector.rb +1 -1
  56. data/lib/vwo/packages/storage/storage.rb +3 -1
  57. data/lib/vwo/services/batch_event_queue.rb +179 -0
  58. data/lib/vwo/services/campaign_decision_service.rb +1 -1
  59. data/lib/vwo/services/hooks_service.rb +1 -1
  60. data/lib/vwo/services/logger_service.rb +1 -1
  61. data/lib/vwo/services/settings_service.rb +4 -2
  62. data/lib/vwo/services/storage_service.rb +1 -1
  63. data/lib/vwo/utils/batch_event_dispatcher.rb +117 -0
  64. data/lib/vwo/utils/campaign_util.rb +1 -1
  65. data/lib/vwo/utils/data_type_util.rb +1 -1
  66. data/lib/vwo/utils/decision_util.rb +1 -1
  67. data/lib/vwo/utils/function_util.rb +5 -1
  68. data/lib/vwo/utils/gateway_service_util.rb +1 -1
  69. data/lib/vwo/utils/impression_util.rb +10 -3
  70. data/lib/vwo/utils/log_message_util.rb +1 -1
  71. data/lib/vwo/utils/meg_util.rb +1 -1
  72. data/lib/vwo/utils/network_util.rb +16 -7
  73. data/lib/vwo/utils/rule_evaluation_util.rb +1 -1
  74. data/lib/vwo/utils/settings_util.rb +1 -1
  75. data/lib/vwo/utils/url_util.rb +1 -1
  76. data/lib/vwo/utils/uuid_util.rb +1 -1
  77. data/lib/vwo/vwo_builder.rb +97 -24
  78. data/lib/vwo/vwo_client.rb +23 -4
  79. data/lib/vwo.rb +2 -1
  80. metadata +4 -2
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -69,10 +69,12 @@ class NetworkManager
69
69
  begin
70
70
  network_options = create_request(request)
71
71
  raise 'No URL found' if network_options.get_url.nil?
72
-
73
- @client.post(network_options)
72
+
73
+ response = @client.post(network_options) # Return the response
74
+ response
74
75
  rescue => e
75
76
  LoggerService.log(LogLevelEnum::ERROR, "Error posting: #{e.message}", nil)
77
+ return ResponseModel.new.set_error(e.message) # Return error response
76
78
  end
77
- end
79
+ end
78
80
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -41,5 +41,13 @@ class ResponseModel
41
41
  def set_error(error)
42
42
  @error = error
43
43
  end
44
+
45
+ def get_error
46
+ @error
47
+ end
48
+
49
+ def get_status_code
50
+ @status_code
51
+ end
44
52
  end
45
53
 
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -18,9 +18,11 @@ class Storage
18
18
  @instance = nil
19
19
 
20
20
  attr_reader :connector
21
+ attr_accessor :is_storage_enabled
21
22
 
22
23
  def initialize
23
24
  @connector = nil
25
+ @is_storage_enabled = false
24
26
  end
25
27
 
26
28
  # Attach a connector (can be an instance or a class)
@@ -0,0 +1,179 @@
1
+ # Copyright 2024-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 '../utils/data_type_util'
16
+ require_relative '../services/logger_service'
17
+ require_relative '../enums/log_level_enum'
18
+ require_relative '../constants/constants'
19
+ require_relative '../packages/network_layer/manager/network_manager'
20
+ require 'concurrent'
21
+
22
+ class BatchEventsQueue
23
+ class << self
24
+ def instance
25
+ @instance ||= nil
26
+ end
27
+
28
+ def configure(batch_config)
29
+ @instance = new(batch_config)
30
+ end
31
+ end
32
+ # Initializes a new batch events queue with the specified configuration
33
+ # @param batch_config Configuration object containing:
34
+ # - request_time_interval: Time interval between batch requests (in seconds)
35
+ # - events_per_request: Maximum number of events to include in a single request
36
+ # - flush_callback: Callback function to execute after flushing events
37
+ # - dispatcher: Function to handle sending the batched events
38
+ def initialize(batch_config)
39
+ @queue = []
40
+ @batch_config = batch_config
41
+ @network_client = NetworkManager.instance.get_client
42
+
43
+ if DataTypeUtil.is_number(batch_config[:request_time_interval]) && batch_config[:request_time_interval] >= 1
44
+ @request_time_interval = batch_config[:request_time_interval]
45
+ else
46
+ @request_time_interval = Constants::DEFAULT_REQUEST_TIME_INTERVAL
47
+ LoggerService.log(LogLevelEnum::INFO, "EVENT_BATCH_DEFAULTS", {
48
+ parameter: 'request_time_interval',
49
+ minLimit: 0,
50
+ defaultValue: "#{@request_time_interval} seconds"
51
+ })
52
+ end
53
+
54
+ if DataTypeUtil.is_number(batch_config[:events_per_request]) &&
55
+ batch_config[:events_per_request] > 0 &&
56
+ batch_config[:events_per_request] <= Constants::MAX_EVENTS_PER_REQUEST
57
+ @events_per_request = batch_config[:events_per_request]
58
+ elsif DataTypeUtil.is_number(batch_config[:events_per_request]) &&
59
+ batch_config[:events_per_request] > Constants::MAX_EVENTS_PER_REQUEST
60
+ @events_per_request = Constants::MAX_EVENTS_PER_REQUEST
61
+ LoggerService.log(LogLevelEnum::INFO, "EVENT_BATCH_MAX_LIMIT", {
62
+ parameter: 'events_per_request',
63
+ maxLimit: Constants::MAX_EVENTS_PER_REQUEST.to_s
64
+ })
65
+ else
66
+ @events_per_request = Constants::DEFAULT_EVENTS_PER_REQUEST
67
+ LoggerService.log(LogLevelEnum::INFO, "EVENT_BATCH_DEFAULTS", {
68
+ parameter: 'events_per_request',
69
+ minLimit: 0,
70
+ defaultValue: @events_per_request.to_s
71
+ })
72
+ end
73
+
74
+ @flush_callback = batch_config[:flush_callback] if batch_config[:flush_callback].respond_to?(:call)
75
+
76
+ @dispatcher = batch_config[:dispatcher]
77
+ @batch_lock = Mutex.new
78
+ @timer = nil
79
+ create_new_batch_timer
80
+ end
81
+
82
+ # Creates a new timer thread to automatically flush events after request_time_interval
83
+ # The timer is only created if one doesn't already exist
84
+ def create_new_batch_timer
85
+ return if @timer
86
+
87
+ @timer = Time.now + @request_time_interval
88
+ @thread = Thread.new { flush_when_request_times_up }
89
+ end
90
+
91
+ # Adds a new event to the queue and manages batch processing
92
+ # If queue reaches events_per_request limit, it triggers an immediate flush
93
+ # @param event The event to be added to the queue
94
+ def enqueue(event)
95
+ @queue.push(event)
96
+
97
+ LoggerService.log(LogLevelEnum::INFO, "EVENT_QUEUE", {
98
+ queueType: 'batch',
99
+ event: event.to_json
100
+ })
101
+
102
+ # if the number of events in the queue is equal to the events_per_request, flush
103
+ if @queue.length >= @events_per_request
104
+ flush
105
+ end
106
+ end
107
+
108
+ # Background thread function that monitors the timer
109
+ # When the timer expires, it flushes the queue and cleans up
110
+ def flush_when_request_times_up
111
+ sleep(1) while @timer && Time.now < @timer
112
+ flush
113
+ end
114
+
115
+ # Processes and sends all queued events
116
+ # @param manual Boolean indicating if flush was triggered manually
117
+ # Clears the queue after successful processing
118
+ def flush(manual = false)
119
+ @batch_lock.synchronize do
120
+ if @queue.any?
121
+ LoggerService.log(LogLevelEnum::DEBUG, "EVENT_BATCH_BEFORE_FLUSHING", {
122
+ manually: manual ? 'manually' : '',
123
+ length: @queue.length,
124
+ accountId: @batch_config[:account_id],
125
+ timer: manual ? 'Timer will be cleared and registered again' : ''
126
+ })
127
+
128
+ # add events to another queue
129
+ temp_queue = @queue.dup
130
+ @queue = []
131
+
132
+ if manual
133
+ future = Concurrent::Future.new(executor: @network_client.get_thread_pool) do
134
+ handle_flush_response(temp_queue, manual)
135
+ end
136
+ future.execute
137
+ @response = future.value
138
+ else
139
+ @network_client.get_thread_pool.post do
140
+ handle_flush_response(temp_queue, manual)
141
+ end
142
+ end
143
+ else
144
+ LoggerService.log(LogLevelEnum::DEBUG, "BATCH_QUEUE_EMPTY")
145
+ @response = {status: "success", events: []}
146
+ end
147
+ kill_old_thread if !manual && @thread
148
+ clear_request_timer
149
+ create_new_batch_timer
150
+ @response
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def handle_flush_response(temp_queue, manual)
157
+ @response = @dispatcher.call(temp_queue, @flush_callback)
158
+ if @response[:status] == "success"
159
+ LoggerService.log(LogLevelEnum::INFO, "EVENT_BATCH_After_FLUSHING", {
160
+ manually: manual ? 'manually' : '',
161
+ length: temp_queue.length
162
+ })
163
+ else
164
+ @queue.concat(temp_queue)
165
+ end
166
+ temp_queue = []
167
+ @response
168
+ end
169
+
170
+ # Resets the request timer to nil
171
+ def clear_request_timer
172
+ @timer = nil
173
+ end
174
+
175
+ def kill_old_thread
176
+ @old_thread&.kill
177
+ end
178
+ end
179
+
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -23,7 +23,7 @@ require_relative '../enums/log_level_enum'
23
23
  require_relative '../models/schemas/settings_schema_validation'
24
24
 
25
25
  class SettingsService
26
- attr_accessor :sdk_key, :account_id, :expiry, :network_timeout, :hostname, :port, :protocol, :is_gateway_service_provided
26
+ attr_accessor :sdk_key, :account_id, :expiry, :network_timeout, :hostname, :port, :protocol, :is_gateway_service_provided, :is_settings_valid
27
27
 
28
28
  class << self
29
29
  attr_accessor :instance
@@ -38,6 +38,7 @@ class SettingsService
38
38
  @account_id = options[:account_id]
39
39
  @expiry = options.dig(:settings, :expiry) || Constants::SETTINGS_EXPIRY
40
40
  @network_timeout = options.dig(:settings, :timeout) || Constants::SETTINGS_TIMEOUT
41
+ @is_settings_valid = false
41
42
 
42
43
  if options[:gateway_service] && options[:gateway_service][:url]
43
44
  parsed_url = URI.parse(options[:gateway_service][:url].start_with?(Constants::HTTP_PROTOCOL) || options[:gateway_service][:url].start_with?(Constants::HTTPS_PROTOCOL) ? options[:gateway_service][:url] : "#{Constants::HTTPS_PROTOCOL}#{options[:gateway_service][:url]}")
@@ -109,6 +110,7 @@ class SettingsService
109
110
  settings = fetch_settings_and_cache_in_storage
110
111
  is_valid = SettingsSchema.new.is_settings_valid(settings)
111
112
  if is_valid
113
+ @is_settings_valid = true
112
114
  LoggerService.log(LogLevelEnum::INFO, "SETTINGS_FETCH_SUCCESS")
113
115
  settings
114
116
  else
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -0,0 +1,117 @@
1
+ # Copyright 2024-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 './network_util'
16
+ require_relative '../enums/http_method_enum'
17
+ require_relative '../enums/url_enum'
18
+ require_relative '../enums/log_level_enum'
19
+ require_relative '../services/logger_service'
20
+ require_relative '../packages/network_layer/manager/network_manager'
21
+ require_relative '../packages/network_layer/models/request_model'
22
+
23
+ class BatchEventDispatcher
24
+
25
+ class << self
26
+
27
+ # Dispatches a batch of events to the VWO server
28
+ # @param properties [Hash] The event properties to send
29
+ # @param callback [Proc] Optional callback function to execute after the request (defaults to empty proc)
30
+ # @param query_params [Hash] Query parameters to include in the request
31
+ def dispatch(properties, callback = -> {}, query_params)
32
+ # Send the prepared payload via POST API request
33
+ send_batch_post_api_request(query_params, properties, callback)
34
+ end
35
+
36
+ # Sends a POST API request with given properties and payload
37
+ def send_batch_post_api_request(properties, payload, callback)
38
+ network_instance = NetworkManager.instance
39
+ headers = {}
40
+ headers['Authorization'] = "#{SettingsService.instance.sdk_key}"
41
+
42
+ request = RequestModel.new(
43
+ UrlUtil.get_base_url,
44
+ HttpMethodEnum::POST,
45
+ UrlEnum::BATCH_EVENTS,
46
+ properties,
47
+ payload,
48
+ headers,
49
+ SettingsService.instance.protocol,
50
+ SettingsService.instance.port
51
+ )
52
+
53
+ begin
54
+ response = network_instance.post(request)
55
+ handle_batch_response(UrlEnum::BATCH_EVENTS, payload, properties, response, response.get_data, callback)
56
+ rescue StandardError => err
57
+ LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
58
+ method: "#{HttpMethodEnum::POST} #{UrlEnum::BATCH_EVENTS}",
59
+ err: err.is_a?(Hash) ? err.to_json : err
60
+ })
61
+ end
62
+ end
63
+
64
+ # Handles the response from a batch event API call
65
+ # @param end_point [String] The API endpoint that was called
66
+ # @param payload [Hash] The payload that was sent in the request
67
+ # @param query_params [Hash] The query parameters used in the request
68
+ # @param res [ResponseModel] The response object from the API call
69
+ # @param raw_data [String] The raw response data from the API
70
+ # @param callback [Proc] Optional callback to be executed after handling the response
71
+ def handle_batch_response(end_point, payload, query_params, res, raw_data, callback)
72
+ events_per_request = payload[:ev].length
73
+ account_id = query_params[:a]
74
+
75
+ error = res.get_error
76
+ if error
77
+ LoggerService.log(LogLevelEnum::INFO, "IMPRESSION_BATCH_FAILED")
78
+ LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
79
+ method: "#{HttpMethodEnum::POST} #{UrlEnum::BATCH_EVENTS}",
80
+ err: error
81
+ })
82
+ callback.call(error, payload.to_json) if callback.respond_to?(:call)
83
+ return {status: "error", events: payload}
84
+ else
85
+ case res.get_status_code
86
+ when 200
87
+ LoggerService.log(LogLevelEnum::INFO, "IMPRESSION_BATCH_SUCCESS", {
88
+ accountId: account_id,
89
+ endPoint: end_point,
90
+ })
91
+ callback.call(nil, payload.to_json) if callback.respond_to?(:call)
92
+ return {status: "success", events: payload}
93
+ when 413
94
+ LoggerService.log(LogLevelEnum::DEBUG, "CONFIG_BATCH_EVENT_LIMIT_EXCEEDED", {
95
+ accountId: account_id,
96
+ endPoint: end_point,
97
+ eventsPerRequest: events_per_request
98
+ })
99
+ LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
100
+ method: "#{HttpMethodEnum::POST} #{UrlEnum::BATCH_EVENTS}",
101
+ err: error
102
+ })
103
+ callback.call(error, payload.to_json) if callback.respond_to?(:call)
104
+ return {status: "error", events: payload}
105
+ else
106
+ LoggerService.log(LogLevelEnum::INFO, "IMPRESSION_BATCH_FAILED")
107
+ LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
108
+ method: "#{HttpMethodEnum::POST} #{UrlEnum::BATCH_EVENTS}",
109
+ err: error
110
+ })
111
+ callback.call(error, payload.to_json) if callback.respond_to?(:call)
112
+ return {status: "error", events: payload}
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -17,6 +17,10 @@ require_relative '../models/campaign/campaign_model'
17
17
  require_relative '../models/campaign/feature_model'
18
18
  require_relative '../models/settings/settings_model'
19
19
  require_relative '../utils/data_type_util'
20
+ require_relative '../services/logger_service'
21
+ require_relative '../enums/log_level_enum'
22
+ require_relative '../constants/constants'
23
+ require_relative '../utils/data_type_util'
20
24
 
21
25
  # Clones an object deeply.
22
26
  # @param obj [Object] The object to clone.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -16,7 +16,7 @@ require_relative '../models/settings/settings_model'
16
16
  require_relative './network_util'
17
17
  require_relative '../models/user/context_model'
18
18
  require_relative '../enums/event_enum'
19
-
19
+ require_relative '../services/batch_event_queue'
20
20
  # Creates and sends an impression for a variation shown event.
21
21
  # This function constructs the necessary properties and payload for the event
22
22
  # and uses the NetworkUtil to send a POST API request.
@@ -45,5 +45,12 @@ def create_and_send_impression_for_variation_shown(settings, campaign_id, variat
45
45
  context.get_ip_address
46
46
  )
47
47
 
48
- NetworkUtil.send_post_api_request(properties, payload)
48
+ # check if batching is enabled
49
+ if BatchEventsQueue.instance
50
+ # add the payload to the batch events queue
51
+ BatchEventsQueue.instance.enqueue(payload)
52
+ else
53
+ # Send the constructed payload via POST request
54
+ NetworkUtil.send_post_api_request(properties, payload)
55
+ end
49
56
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -104,8 +104,6 @@ class NetworkUtil
104
104
  msgId: "#{uuid}-#{get_current_unix_timestamp_in_millis}",
105
105
  visId: uuid,
106
106
  sessionId: get_current_unix_timestamp,
107
- visitor_ua: visitor_user_agent,
108
- visitor_ip: ip_address,
109
107
  event: {
110
108
  props: {
111
109
  vwo_sdkName: Constants::SDK_NAME,
@@ -130,6 +128,10 @@ class NetworkUtil
130
128
  properties[:d][:event][:props][:id] = campaign_id
131
129
  properties[:d][:event][:props][:variation] = variation_id
132
130
  properties[:d][:event][:props][:isFirst] = 1
131
+
132
+ # Only add visitor_ua and visitor_ip if they are non-null
133
+ properties[:d][:visitor_ua] = visitor_user_agent if visitor_user_agent && !visitor_user_agent.empty?
134
+ properties[:d][:visitor_ip] = ip_address if ip_address && !ip_address.empty?
133
135
 
134
136
  LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_TRACK_USER", {
135
137
  accountId: settings.account_id,
@@ -196,9 +198,16 @@ class NetworkUtil
196
198
  SettingsService.instance.protocol,
197
199
  SettingsService.instance.port
198
200
  )
199
-
200
- begin
201
- network_instance.post(request)
201
+
202
+ begin
203
+ if network_instance.get_client.get_should_use_threading
204
+ network_instance.get_client.get_thread_pool.post {
205
+ response = network_instance.post(request)
206
+ response
207
+ }
208
+ else
209
+ response = network_instance.post(request)
210
+ end
202
211
  rescue ResponseModel => err
203
212
  LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
204
213
  method: HttpMethodEnum::POST,
@@ -224,7 +233,7 @@ class NetworkUtil
224
233
 
225
234
  begin
226
235
  network_instance.get(request)
227
- rescue ResponseModel => err
236
+ rescue StandardError => err
228
237
  LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
229
238
  method: HttpMethodEnum::GET,
230
239
  err: err.is_a?(Hash) ? err.to_json : err
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Wingify Software Pvt. Ltd.
1
+ # Copyright 2024-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.