vwo-fme-ruby-sdk 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d13710bca2e74d196e8f16dae0d76687b063f0b9ffab675bb425e63cd381b863
4
- data.tar.gz: 237b9215295d8562dc340eabf4a0670c04615410606f4e950b6b6ded3eb9afdd
3
+ metadata.gz: 46ef28eb680c91f4a2009e0fdff9053a4c2f82cfacbe2b09c5a3359b469a104a
4
+ data.tar.gz: a5aeb2e3856e53a62f8c52ff1da83c7396260f50087441f2537b94319459013f
5
5
  SHA512:
6
- metadata.gz: d04499359ef1b97ae2d7aac4df5fb0a1084eb7274596877cc84ea64dc11ab08975514b94412f48871d6682cc2bbbe8a277543a744baaf6a854e5a07da128fd03
7
- data.tar.gz: 27cd8399d7d7768ff7ac7928df99c09e6d8eba26b2367e9301acb7a0586c709b612d15f7f988589a025c214e2525e59815ca041608acc0c7b232e9f60b1095b5
6
+ metadata.gz: 216b54b6567c982b2c6392c1bb52a940cb0eb083604f7bcc8040e1017acf06a8da1438a665706b9e0f618e57ccbc7146f8a59cda2bce8eba6c8fb7fbcb05af96
7
+ data.tar.gz: 5ed4c55969fe455f57b946b67314382a2f50534fdc4e62948a54b88ed0a81bb9c94b5c0abe01b24c255bb2f15c449893545865a3a4ad8e8b7467ffd5d43e24bc
@@ -15,28 +15,24 @@
15
15
  require_relative '../models/user/context_model'
16
16
  require_relative '../enums/event_enum'
17
17
  require_relative '../utils/network_util'
18
- require_relative '../models/settings/settings_model'
19
18
  require_relative '../services/batch_event_queue'
20
19
 
21
20
  class SetAttributeApi
22
21
  # Sets multiple attributes for a user in a single network call.
23
- # @param settings [SettingsModel] Configuration settings.
24
22
  # @param attributes [Hash] Key-value map of attributes.
25
23
  # @param context [ContextModel] Context containing user information.
26
- def set_attribute(settings, attributes, context)
27
- create_impression_for_attributes(settings, attributes, context)
24
+ def set_attribute(attributes, context)
25
+ create_impression_for_attributes(attributes, context)
28
26
  end
29
27
 
30
28
  private
31
29
 
32
30
  # Creates an impression for multiple user attributes and sends it to the server.
33
- # @param settings [SettingsModel] Configuration settings.
34
31
  # @param attributes [Hash] Key-value map of attributes.
35
32
  # @param context [ContextModel] Context containing user information.
36
- def create_impression_for_attributes(settings, attributes, context)
33
+ def create_impression_for_attributes(attributes, context)
37
34
  # Retrieve base properties for the event
38
35
  properties = NetworkUtil.get_events_base_properties(
39
- settings,
40
36
  EventEnum::VWO_SYNC_VISITOR_PROP,
41
37
  URI.encode_www_form_component(context.user_agent),
42
38
  context.ip_address
@@ -44,7 +40,6 @@ class SetAttributeApi
44
40
 
45
41
  # Construct payload data for multiple attributes
46
42
  payload = NetworkUtil.get_attribute_payload_data(
47
- settings,
48
43
  context.id,
49
44
  EventEnum::VWO_SYNC_VISITOR_PROP,
50
45
  attributes,
@@ -32,7 +32,7 @@ class TrackApi
32
32
  def track(settings, event_name, context, event_properties, hooks_service)
33
33
  if does_event_belong_to_any_feature(event_name, settings)
34
34
  # Create an impression for the track event
35
- create_impression_for_track(settings, event_name, context, event_properties)
35
+ create_impression_for_track(event_name, context, event_properties)
36
36
 
37
37
  # Set and execute integration callback for the track event
38
38
  hooks_service.set({ event_name: event_name, api: ApiEnum::TRACK })
@@ -50,14 +50,12 @@ class TrackApi
50
50
  private
51
51
 
52
52
  # Creates an impression for a track event and sends it via a POST API request.
53
- # @param settings [SettingsModel] Configuration settings.
54
53
  # @param event_name [String] Name of the event to track.
55
54
  # @param context [ContextModel] User details.
56
55
  # @param event_properties [Hash] Properties associated with the event.
57
- def create_impression_for_track(settings, event_name, context, event_properties)
56
+ def create_impression_for_track(event_name, context, event_properties)
58
57
  # Get base properties for the event
59
58
  properties = NetworkUtil.get_events_base_properties(
60
- settings,
61
59
  event_name,
62
60
  URI.encode_www_form_component(context.user_agent),
63
61
  context.ip_address
@@ -65,7 +63,6 @@ class TrackApi
65
63
 
66
64
  # Prepare the payload for the track goal
67
65
  payload = NetworkUtil.get_track_goal_payload_data(
68
- settings,
69
66
  context.id,
70
67
  event_name,
71
68
  event_properties,
@@ -17,7 +17,7 @@
17
17
  # Define the Constants module
18
18
  module Constants
19
19
  SDK_NAME = 'vwo-fme-ruby-sdk'.freeze
20
- SDK_VERSION = '1.3.2'.freeze
20
+ SDK_VERSION = '1.4.0'.freeze
21
21
 
22
22
  MAX_TRAFFIC_PERCENT = 100
23
23
  MAX_TRAFFIC_VALUE = 10_000
@@ -55,4 +55,6 @@ module Constants
55
55
  SHOULD_USE_THREADING = true
56
56
  MAX_POOL_SIZE = 5
57
57
  MAX_QUEUE_SIZE = 10000
58
+
59
+ PRODUCT_NAME = 'fme'.freeze
58
60
  end
@@ -15,5 +15,6 @@
15
15
  # Event types
16
16
  module EventEnum
17
17
  VWO_VARIATION_SHOWN = 'vwo_variationShown'
18
- VWO_SYNC_VISITOR_PROP = 'vwo_syncVisitorProp'
18
+ VWO_SYNC_VISITOR_PROP = 'vwo_syncVisitorProp',
19
+ VWO_INIT_CALLED = 'vwo_fmeSdkInit'
19
20
  end
@@ -89,6 +89,7 @@ class SettingsSchema
89
89
  optional(:groups).maybe(:hash)
90
90
  optional(:campaignGroups).maybe(:hash)
91
91
  optional(:collectionPrefix).maybe(:string)
92
+ optional(:sdkMetaInfo).maybe(:hash)
92
93
  end
93
94
  end
94
95
 
@@ -17,6 +17,7 @@ require 'securerandom'
17
17
  require_relative '../logger'
18
18
  require_relative 'transport_manager'
19
19
  require_relative '../transports/console_transport'
20
+ require_relative '../../../enums/log_level_enum'
20
21
 
21
22
  class LogManager < VWOLogger
22
23
  @instance = nil
@@ -62,8 +63,9 @@ class LogManager < VWOLogger
62
63
  @transport_manager.log('WARN', message)
63
64
  end
64
65
 
65
- def error(message)
66
+ def error(message, extraData = {})
66
67
  @transport_manager.log('ERROR', message)
68
+ # sendLogToVWO(message, LogLevelEnum::ERROR, extraData)
67
69
  end
68
70
 
69
71
  private
@@ -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, :is_settings_valid
26
+ attr_accessor :sdk_key, :account_id, :expiry, :network_timeout, :hostname, :port, :protocol, :is_gateway_service_provided, :is_settings_valid, :settings_fetch_time
27
27
 
28
28
  class << self
29
29
  attr_accessor :instance
@@ -93,8 +93,15 @@ class SettingsService
93
93
  request = RequestModel.new(@hostname, "GET", path, options, nil, nil, @protocol, @port)
94
94
  request.set_timeout(@network_timeout)
95
95
 
96
+ # store the current time in milliseconds
97
+ settings_fetch_start_time = (Time.now.to_f * 1000).to_i
98
+
96
99
  begin
97
100
  response = network_instance.get(request)
101
+ # calculate the time taken to fetch the settings
102
+ settings_fetch_end_time = (Time.now.to_f * 1000).to_i
103
+ time_taken = settings_fetch_end_time - settings_fetch_start_time
104
+ @settings_fetch_time = time_taken.to_s
98
105
  response.get_data
99
106
  rescue => e
100
107
  LoggerService.log(LogLevelEnum::ERROR, "Error fetching settings: #{e.message}", nil)
@@ -0,0 +1,36 @@
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/event_enum'
17
+ require_relative '../services/batch_event_queue'
18
+
19
+ # Sends an init called event to VWO.
20
+ # This event is triggered when the init function is called.
21
+ # @param settings_fetch_time [Number] Time taken to fetch settings in milliseconds.
22
+ # @param sdk_init_time [Number] Time taken to initialize the SDK in milliseconds.
23
+ def send_sdk_init_event(settings_fetch_time, sdk_init_time)
24
+ # Get base properties for the event
25
+ properties = NetworkUtil.get_events_base_properties(EventEnum::VWO_INIT_CALLED)
26
+ payload = NetworkUtil.get_sdk_init_event_payload(EventEnum::VWO_INIT_CALLED, settings_fetch_time, sdk_init_time)
27
+
28
+ # check if batching is enabled
29
+ if BatchEventsQueue.instance
30
+ # add the payload to the batch events queue
31
+ BatchEventsQueue.instance.enqueue(payload)
32
+ else
33
+ # Send the constructed payload via POST request
34
+ NetworkUtil.send_event(properties, payload)
35
+ end
36
+ end
@@ -28,7 +28,6 @@ require_relative '../services/batch_event_queue'
28
28
  def create_and_send_impression_for_variation_shown(settings, campaign_id, variation_id, context)
29
29
  # Get base properties for the event
30
30
  properties = NetworkUtil.get_events_base_properties(
31
- settings,
32
31
  EventEnum::VWO_VARIATION_SHOWN,
33
32
  URI.encode_www_form_component(context.get_user_agent), # Encode user agent for URL safety
34
33
  context.get_ip_address
@@ -36,7 +35,6 @@ def create_and_send_impression_for_variation_shown(settings, campaign_id, variat
36
35
 
37
36
  # Construct payload data for tracking the user
38
37
  payload = NetworkUtil.get_track_user_payload_data(
39
- settings,
40
38
  context.get_id,
41
39
  EventEnum::VWO_VARIATION_SHOWN,
42
40
  campaign_id,
@@ -80,11 +80,11 @@ class NetworkUtil
80
80
  end
81
81
 
82
82
  # Builds generic properties for different tracking calls
83
- def get_events_base_properties(setting, event_name, visitor_user_agent = '', ip_address = '')
84
- sdk_key = setting.sdk_key || ''
83
+ def get_events_base_properties(event_name, visitor_user_agent = '', ip_address = '')
84
+ sdk_key = SettingsService.instance.sdk_key || ''
85
85
  {
86
86
  en: event_name,
87
- a: setting.account_id,
87
+ a: SettingsService.instance.account_id,
88
88
  env: sdk_key,
89
89
  eTime: get_current_unix_timestamp_in_millis,
90
90
  random: get_random_number,
@@ -96,9 +96,9 @@ class NetworkUtil
96
96
  end
97
97
 
98
98
  # Builds base payload for tracking events
99
- def _get_event_base_payload(settings, user_id, event_name, visitor_user_agent = '', ip_address = '')
100
- uuid = UUIDUtil.get_uuid(user_id.to_s, settings.account_id)
101
- sdk_key = settings.sdk_key
99
+ def _get_event_base_payload(user_id, event_name, visitor_user_agent = '', ip_address = '')
100
+ uuid = UUIDUtil.get_uuid(user_id.to_s, SettingsService.instance.account_id)
101
+ sdk_key = SettingsService.instance.sdk_key
102
102
 
103
103
  {
104
104
  d: {
@@ -124,8 +124,8 @@ class NetworkUtil
124
124
  end
125
125
 
126
126
  # Builds track-user payload data
127
- def get_track_user_payload_data(settings, user_id, event_name, campaign_id, variation_id, visitor_user_agent = '', ip_address = '')
128
- properties = _get_event_base_payload(settings, user_id, event_name, visitor_user_agent, ip_address)
127
+ def get_track_user_payload_data(user_id, event_name, campaign_id, variation_id, visitor_user_agent = '', ip_address = '')
128
+ properties = _get_event_base_payload(user_id, event_name, visitor_user_agent, ip_address)
129
129
  properties[:d][:event][:props][:id] = campaign_id
130
130
  properties[:d][:event][:props][:variation] = variation_id
131
131
  properties[:d][:event][:props][:isFirst] = 1
@@ -141,7 +141,7 @@ class NetworkUtil
141
141
  end
142
142
 
143
143
  LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_TRACK_USER", {
144
- accountId: settings.account_id,
144
+ accountId: SettingsService.instance.account_id,
145
145
  userId: user_id,
146
146
  campaignId: campaign_id
147
147
  })
@@ -150,8 +150,8 @@ class NetworkUtil
150
150
  end
151
151
 
152
152
  # Constructs payload for tracking goals with custom event properties
153
- def get_track_goal_payload_data(settings, user_id, event_name, event_properties, visitor_user_agent = '', ip_address = '')
154
- properties = _get_event_base_payload(settings, user_id, event_name, visitor_user_agent, ip_address)
153
+ def get_track_goal_payload_data(user_id, event_name, event_properties, visitor_user_agent = '', ip_address = '')
154
+ properties = _get_event_base_payload(user_id, event_name, visitor_user_agent, ip_address)
155
155
  properties[:d][:event][:props][:isCustomEvent] = true
156
156
 
157
157
  if SettingsService.instance.is_gateway_service_provided
@@ -165,15 +165,15 @@ class NetworkUtil
165
165
 
166
166
  LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_TRACK_GOAL", {
167
167
  eventName: event_name,
168
- accountId: settings.account_id,
168
+ accountId: SettingsService.instance.account_id,
169
169
  userId: user_id
170
170
  })
171
171
 
172
172
  properties
173
173
  end
174
174
 
175
- def get_attribute_payload_data(settings, user_id, event_name, event_properties, visitor_user_agent = '', ip_address = '')
176
- properties = _get_event_base_payload(settings, user_id, event_name, visitor_user_agent, ip_address)
175
+ def get_attribute_payload_data(user_id, event_name, event_properties, visitor_user_agent = '', ip_address = '')
176
+ properties = _get_event_base_payload(user_id, event_name, visitor_user_agent, ip_address)
177
177
  properties[:d][:event][:props][:isCustomEvent] = true
178
178
 
179
179
  if event_properties.is_a?(Hash) && !event_properties.empty?
@@ -182,12 +182,31 @@ class NetworkUtil
182
182
 
183
183
  LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_SYNC_VISITOR_PROP", {
184
184
  eventName: event_name,
185
- accountId: settings.account_id,
185
+ accountId: SettingsService.instance.account_id,
186
186
  userId: user_id
187
187
  })
188
188
  properties
189
189
  end
190
190
 
191
+ # Constructs the payload for init called event.
192
+ # @param event_name - The name of the event.
193
+ # @param settings_fetch_time - Time taken to fetch settings in milliseconds.
194
+ # @param sdk_init_time - Time taken to initialize the SDK in milliseconds.
195
+ # @returns The constructed payload with required fields.
196
+ def get_sdk_init_event_payload(event_name, settings_fetch_time, sdk_init_time)
197
+ user_id = SettingsService.instance.account_id + "_" + SettingsService.instance.sdk_key
198
+ properties = _get_event_base_payload(user_id, event_name, nil, nil)
199
+ properties[:d][:event][:props][:vwo_fs_environment] = SettingsService.instance.sdk_key
200
+ properties[:d][:event][:props][:product] = Constants::PRODUCT_NAME
201
+ data = {
202
+ "isSDKInitialized": true,
203
+ "settingsFetchTime": settings_fetch_time,
204
+ "sdkInitTime": sdk_init_time
205
+ }
206
+ properties[:d][:event][:props][:data] = data
207
+ properties
208
+ end
209
+
191
210
  # Sends a POST API request with given properties and payload
192
211
  def send_post_api_request(properties, payload)
193
212
  network_instance = NetworkManager.instance
@@ -230,6 +249,41 @@ class NetworkUtil
230
249
  end
231
250
  end
232
251
 
252
+ # Sends an event to VWO (generic event sender).
253
+ # @param properties - Query parameters for the request.
254
+ # @param payload - The payload for the request.
255
+ # @param event_name - The name of the event to send.
256
+ def send_event(properties, payload)
257
+ network_instance = NetworkManager.instance
258
+ headers = {}
259
+ headers[HeadersEnum::USER_AGENT] = payload[:d][:visitor_ua] if payload[:d][:visitor_ua]
260
+ headers[HeadersEnum::IP] = payload[:d][:visitor_ip] if payload[:d][:visitor_ip]
261
+
262
+ request = RequestModel.new(
263
+ UrlUtil.get_base_url,
264
+ HttpMethodEnum::POST,
265
+ UrlEnum::EVENTS,
266
+ properties,
267
+ payload,
268
+ headers,
269
+ SettingsService.instance.protocol,
270
+ SettingsService.instance.port
271
+ )
272
+
273
+ begin
274
+ if network_instance.get_client.get_should_use_threading
275
+ network_instance.get_client.get_thread_pool.post {
276
+ response = network_instance.post(request)
277
+ response
278
+ }
279
+ else
280
+ response = network_instance.post(request)
281
+ response
282
+ end
283
+ rescue ResponseModel => err
284
+ end
285
+ end
286
+
233
287
  # Sends a GET API request to the specified endpoint with given properties
234
288
  def send_get_api_request(properties, endpoint)
235
289
  network_instance = NetworkManager.instance
@@ -146,7 +146,7 @@ class VWOClient
146
146
  end
147
147
 
148
148
  context_model = ContextModel.new.model_from_dictionary(context)
149
- SetAttributeApi.new.set_attribute(@settings, attributes, context_model)
149
+ SetAttributeApi.new.set_attribute(attributes, context_model)
150
150
  rescue StandardError => e
151
151
  LoggerService.log(LogLevelEnum::ERROR, "API_THROW_ERROR", {apiName: api_name, err: e.message})
152
152
  end
data/lib/vwo.rb CHANGED
@@ -16,6 +16,8 @@ require 'json'
16
16
  require 'uri'
17
17
  require_relative 'vwo/vwo_builder'
18
18
  require_relative 'vwo/vwo_client'
19
+ require_relative 'vwo/utils/event_util'
20
+ require_relative 'vwo/services/settings_service'
19
21
 
20
22
  class VWO
21
23
  @@vwo_builder = nil
@@ -67,7 +69,30 @@ class VWO
67
69
  puts "[ERROR]: VWO-SDK: Please provide VWO account ID in the options and should be a of type string|number"
68
70
  end
69
71
 
72
+ # store the current time in milliseconds
73
+ sdk_init_start_time = (Time.now.to_f * 1000).to_i
74
+ # initialize the vwo instance
70
75
  new(options)
76
+ # store the time after initializing the vwo instance in milliseconds
77
+ sdk_init_end_time = (Time.now.to_f * 1000).to_i
78
+ # calculate the time taken for initializing the vwo instance
79
+ time_taken_for_init = sdk_init_end_time - sdk_init_start_time
80
+ # get sdkMetaInfo from settings file to check if the sdk was initialized earlier
81
+ sdk_meta_info = nil
82
+ was_initialized_earlier = false
83
+
84
+ begin
85
+ if @@instance && @@instance.original_settings && @@instance.original_settings.is_a?(Hash)
86
+ sdk_meta_info = @@instance.original_settings["sdkMetaInfo"]
87
+ was_initialized_earlier = sdk_meta_info && sdk_meta_info.is_a?(Hash) ? sdk_meta_info["wasInitializedEarlier"] : false
88
+ end
89
+ rescue StandardError => e
90
+ was_initialized_earlier = false
91
+ end
92
+ if !was_initialized_earlier && SettingsService.instance.is_settings_valid
93
+ # send the sdk init info to vwo server
94
+ send_sdk_init_event(SettingsService.instance.settings_fetch_time, time_taken_for_init.to_s)
95
+ end
71
96
  @@instance
72
97
  rescue StandardError => e
73
98
  puts "[ERROR]: VWO-SDK: Got error while initializing VWO: #{e.message}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vwo-fme-ruby-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VWO
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-24 00:00:00.000000000 Z
11
+ date: 2025-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uuidtools
@@ -211,6 +211,7 @@ files:
211
211
  - lib/vwo/utils/campaign_util.rb
212
212
  - lib/vwo/utils/data_type_util.rb
213
213
  - lib/vwo/utils/decision_util.rb
214
+ - lib/vwo/utils/event_util.rb
214
215
  - lib/vwo/utils/function_util.rb
215
216
  - lib/vwo/utils/gateway_service_util.rb
216
217
  - lib/vwo/utils/impression_util.rb