wingify-fme-ruby-sdk 1.50.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 +7 -0
- data/lib/resources/debug_messages.json +21 -0
- data/lib/resources/error_messages.json +63 -0
- data/lib/resources/info_messages.json +43 -0
- data/lib/resources/warn_messages.json +1 -0
- data/lib/vwo.rb +40 -0
- data/lib/wingify/api/get_flag.rb +244 -0
- data/lib/wingify/api/set_attribute.rb +57 -0
- data/lib/wingify/api/track_event.rb +80 -0
- data/lib/wingify/constants/constants.rb +106 -0
- data/lib/wingify/decorators/storage_decorator.rb +82 -0
- data/lib/wingify/enums/api_enum.rb +23 -0
- data/lib/wingify/enums/campaign_type_enum.rb +19 -0
- data/lib/wingify/enums/debug_category_enum.rb +20 -0
- data/lib/wingify/enums/decision_types_enum.rb +18 -0
- data/lib/wingify/enums/event_enum.rb +22 -0
- data/lib/wingify/enums/headers_enum.rb +20 -0
- data/lib/wingify/enums/hooks_enum.rb +17 -0
- data/lib/wingify/enums/http_method_enum.rb +18 -0
- data/lib/wingify/enums/log_level_enum.rb +21 -0
- data/lib/wingify/enums/log_level_to_number.rb +27 -0
- data/lib/wingify/enums/status_enum.rb +19 -0
- data/lib/wingify/enums/storage_enum.rb +22 -0
- data/lib/wingify/enums/url_enum.rb +22 -0
- data/lib/wingify/models/campaign/campaign_model.rb +192 -0
- data/lib/wingify/models/campaign/feature_model.rb +111 -0
- data/lib/wingify/models/campaign/impact_campaign_model.rb +38 -0
- data/lib/wingify/models/campaign/metric_model.rb +44 -0
- data/lib/wingify/models/campaign/rule_model.rb +56 -0
- data/lib/wingify/models/campaign/variable_model.rb +51 -0
- data/lib/wingify/models/campaign/variation_model.rb +137 -0
- data/lib/wingify/models/gateway_service_model.rb +39 -0
- data/lib/wingify/models/schemas/settings_schema_validation.rb +104 -0
- data/lib/wingify/models/settings/settings_model.rb +101 -0
- data/lib/wingify/models/storage/storage_data_model.rb +44 -0
- data/lib/wingify/models/user/context_model.rb +154 -0
- data/lib/wingify/models/user/context_vwo_model.rb +38 -0
- data/lib/wingify/models/user/get_flag_response.rb +50 -0
- data/lib/wingify/models/vwo_options_model.rb +129 -0
- data/lib/wingify/packages/decision_maker/decision_maker.rb +60 -0
- data/lib/wingify/packages/logger/core/log_manager.rb +92 -0
- data/lib/wingify/packages/logger/core/transport_manager.rb +76 -0
- data/lib/wingify/packages/logger/log_message_builder.rb +70 -0
- data/lib/wingify/packages/logger/logger.rb +38 -0
- data/lib/wingify/packages/logger/transports/console_transport.rb +49 -0
- data/lib/wingify/packages/network_layer/client/network_client.rb +276 -0
- data/lib/wingify/packages/network_layer/handlers/request_handler.rb +37 -0
- data/lib/wingify/packages/network_layer/manager/network_manager.rb +145 -0
- data/lib/wingify/packages/network_layer/models/global_request_model.rb +105 -0
- data/lib/wingify/packages/network_layer/models/request_model.rb +179 -0
- data/lib/wingify/packages/network_layer/models/response_model.rb +62 -0
- data/lib/wingify/packages/segmentation_evaluator/core/segmentation_manager.rb +77 -0
- data/lib/wingify/packages/segmentation_evaluator/enums/segment_operand_regex_enum.rb +29 -0
- data/lib/wingify/packages/segmentation_evaluator/enums/segment_operand_value_enum.rb +26 -0
- data/lib/wingify/packages/segmentation_evaluator/enums/segment_operator_value_enum.rb +33 -0
- data/lib/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.rb +218 -0
- data/lib/wingify/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.rb +415 -0
- data/lib/wingify/packages/segmentation_evaluator/utils/segment_util.rb +44 -0
- data/lib/wingify/packages/storage/connector.rb +26 -0
- data/lib/wingify/packages/storage/storage.rb +47 -0
- data/lib/wingify/services/batch_event_queue.rb +179 -0
- data/lib/wingify/services/campaign_decision_service.rb +161 -0
- data/lib/wingify/services/hooks_service.rb +51 -0
- data/lib/wingify/services/logger_service.rb +114 -0
- data/lib/wingify/services/settings_service.rb +178 -0
- data/lib/wingify/services/storage_service.rb +66 -0
- data/lib/wingify/utils/batch_event_dispatcher_util.rb +178 -0
- data/lib/wingify/utils/brand_context.rb +33 -0
- data/lib/wingify/utils/brand_util.rb +53 -0
- data/lib/wingify/utils/campaign_util.rb +284 -0
- data/lib/wingify/utils/data_type_util.rb +105 -0
- data/lib/wingify/utils/debugger_service_util.rb +40 -0
- data/lib/wingify/utils/decision_util.rb +259 -0
- data/lib/wingify/utils/event_util.rb +55 -0
- data/lib/wingify/utils/function_util.rb +141 -0
- data/lib/wingify/utils/gateway_service_util.rb +101 -0
- data/lib/wingify/utils/impression_util.rb +66 -0
- data/lib/wingify/utils/log_message_util.rb +42 -0
- data/lib/wingify/utils/meg_util.rb +357 -0
- data/lib/wingify/utils/network_util.rb +503 -0
- data/lib/wingify/utils/rule_evaluation_util.rb +57 -0
- data/lib/wingify/utils/settings_util.rb +38 -0
- data/lib/wingify/utils/usage_stats_util.rb +119 -0
- data/lib/wingify/utils/uuid_util.rb +96 -0
- data/lib/wingify/wingify_builder.rb +261 -0
- data/lib/wingify/wingify_client.rb +227 -0
- data/lib/wingify.rb +117 -0
- metadata +327 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
# Copyright 2024-2026 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/log_level_enum'
|
|
16
|
+
require_relative '../services/logger_service'
|
|
17
|
+
require_relative '../enums/headers_enum'
|
|
18
|
+
require_relative '../enums/http_method_enum'
|
|
19
|
+
require_relative '../enums/url_enum'
|
|
20
|
+
require_relative '../constants/constants'
|
|
21
|
+
require_relative '../packages/network_layer/manager/network_manager'
|
|
22
|
+
require_relative '../packages/network_layer/models/request_model'
|
|
23
|
+
require_relative '../packages/network_layer/models/response_model'
|
|
24
|
+
require_relative '../utils/uuid_util'
|
|
25
|
+
require_relative '../utils/usage_stats_util'
|
|
26
|
+
require_relative '../models/user/context_model'
|
|
27
|
+
require_relative '../utils/log_message_util'
|
|
28
|
+
require_relative '../utils/function_util'
|
|
29
|
+
require_relative '../enums/api_enum'
|
|
30
|
+
|
|
31
|
+
class NetworkUtil
|
|
32
|
+
class << self
|
|
33
|
+
# Converts hash map query parameters to URL-encoded query string
|
|
34
|
+
# @param params [Hash] Hash containing query parameters
|
|
35
|
+
# @return [String] URL-encoded query string
|
|
36
|
+
def convert_params_to_string(params)
|
|
37
|
+
return '' if params.nil? || params.empty?
|
|
38
|
+
|
|
39
|
+
'?' + params.map do |key, value|
|
|
40
|
+
"#{URI.encode_www_form_component(key.to_s)}=#{URI.encode_www_form_component(value.to_s)}"
|
|
41
|
+
end.join('&')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns the base properties for bulk operations
|
|
45
|
+
def get_base_properties_for_bulk(account_id, user_id)
|
|
46
|
+
{
|
|
47
|
+
sId: get_current_unix_timestamp, # Session ID
|
|
48
|
+
u: UUIDUtil.get_uuid(user_id, account_id) # UUID based on user and account ID
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns settings path with sdkKey and accountId
|
|
53
|
+
def get_settings_path(sdk_key, account_id)
|
|
54
|
+
{
|
|
55
|
+
i: sdk_key, # API key
|
|
56
|
+
r: rand, # Random number for cache busting
|
|
57
|
+
a: account_id # Account ID
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns the event tracking path
|
|
62
|
+
def get_track_event_path(event, account_id, user_id)
|
|
63
|
+
{
|
|
64
|
+
event_type: event, # Type of event
|
|
65
|
+
account_id: account_id, # Account ID
|
|
66
|
+
uId: user_id, # User ID
|
|
67
|
+
u: UUIDUtil.get_uuid(user_id, account_id), # UUID for user
|
|
68
|
+
sdk: SettingsService.instance.sdk_name, # SDK Name
|
|
69
|
+
'sdk-v': Constants::SDK_VERSION, # SDK Version
|
|
70
|
+
random: get_random_number, # Random number for uniqueness
|
|
71
|
+
sId: get_current_unix_timestamp, # Session ID
|
|
72
|
+
ed: JSON.generate({ p: 'server' }) # Additional encoded data
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Returns query params for event batching
|
|
77
|
+
def get_event_batching_query_params(account_id)
|
|
78
|
+
{
|
|
79
|
+
a: account_id, # Account ID
|
|
80
|
+
sd: SettingsService.instance.sdk_name, # SDK Name
|
|
81
|
+
sv: Constants::SDK_VERSION # SDK Version
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Builds generic properties for different tracking calls
|
|
86
|
+
def get_events_base_properties(event_name, visitor_user_agent = '', ip_address = '', is_usage_stats_event = false, usage_stat_account_id = '')
|
|
87
|
+
properties = {
|
|
88
|
+
en: event_name,
|
|
89
|
+
a: SettingsService.instance.account_id,
|
|
90
|
+
eTime: get_current_unix_timestamp_in_millis,
|
|
91
|
+
random: get_random_number,
|
|
92
|
+
p: 'FS',
|
|
93
|
+
visitor_ua: visitor_user_agent || '',
|
|
94
|
+
visitor_ip: ip_address || ''
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if !is_usage_stats_event
|
|
98
|
+
# set env key for standard sdk events
|
|
99
|
+
properties[:env] = SettingsService.instance.sdk_key
|
|
100
|
+
else
|
|
101
|
+
# set env key for usage stats events
|
|
102
|
+
properties[:a] = usage_stat_account_id
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
properties
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Builds base payload for tracking events
|
|
109
|
+
def _get_event_base_payload(user_id, event_name, visitor_user_agent = '', ip_address = '', is_usage_stats_event = false, usage_stat_account_id = '')
|
|
110
|
+
account_id = SettingsService.instance.account_id
|
|
111
|
+
|
|
112
|
+
if is_usage_stats_event
|
|
113
|
+
account_id = usage_stat_account_id
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
uuid = UUIDUtil.get_uuid(user_id.to_s, account_id.to_s)
|
|
117
|
+
sdk_key = SettingsService.instance.sdk_key
|
|
118
|
+
|
|
119
|
+
payload = {
|
|
120
|
+
d: {
|
|
121
|
+
msgId: "#{uuid}-#{get_current_unix_timestamp_in_millis}",
|
|
122
|
+
visId: uuid,
|
|
123
|
+
sessionId: get_current_unix_timestamp,
|
|
124
|
+
event: {
|
|
125
|
+
props: {
|
|
126
|
+
vwo_sdkName: SettingsService.instance.sdk_name,
|
|
127
|
+
vwo_sdkVersion: Constants::SDK_VERSION,
|
|
128
|
+
},
|
|
129
|
+
name: event_name,
|
|
130
|
+
time: get_current_unix_timestamp_in_millis
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if !is_usage_stats_event
|
|
136
|
+
# set env key for standard sdk events
|
|
137
|
+
payload[:d][:event][:props][:vwo_envKey] = sdk_key
|
|
138
|
+
|
|
139
|
+
# set visitor props for standard sdk events
|
|
140
|
+
payload[:d][:visitor] = {
|
|
141
|
+
props: {
|
|
142
|
+
vwo_fs_environment: sdk_key
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
payload
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Builds track-user payload data
|
|
151
|
+
def get_track_user_payload_data(event_name, campaign_id, variation_id, context)
|
|
152
|
+
user_id = context.get_id
|
|
153
|
+
visitor_user_agent = context.get_user_agent
|
|
154
|
+
ip_address = context.get_ip_address
|
|
155
|
+
custom_variables = context.get_custom_variables
|
|
156
|
+
post_segmentation_variables = context.get_post_segmentation_variables
|
|
157
|
+
|
|
158
|
+
properties = _get_event_base_payload(user_id, event_name, visitor_user_agent, ip_address)
|
|
159
|
+
|
|
160
|
+
# use sessionId from context if present
|
|
161
|
+
if context.get_session_id
|
|
162
|
+
properties[:d][:sessionId] = context.get_session_id
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# use uuid from context if present
|
|
166
|
+
if context.get_uuid && !context.get_uuid.empty?
|
|
167
|
+
properties[:d][:visId] = context.get_uuid
|
|
168
|
+
properties[:d][:msgId] = "#{context.get_uuid}-#{get_current_unix_timestamp_in_millis}"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
properties[:d][:event][:props][:id] = campaign_id
|
|
172
|
+
properties[:d][:event][:props][:variation] = variation_id
|
|
173
|
+
properties[:d][:event][:props][:isFirst] = 1
|
|
174
|
+
|
|
175
|
+
# Only add visitor_ua and visitor_ip if they are non-null
|
|
176
|
+
properties[:d][:visitor_ua] = visitor_user_agent if visitor_user_agent && !visitor_user_agent.empty?
|
|
177
|
+
properties[:d][:visitor_ip] = ip_address if ip_address && !ip_address.empty?
|
|
178
|
+
|
|
179
|
+
# Add post-segmentation variables if they exist in custom variables
|
|
180
|
+
if post_segmentation_variables&.any? && custom_variables&.any?
|
|
181
|
+
post_segmentation_variables.each do |key|
|
|
182
|
+
# Try to get value using string key first, then symbol key
|
|
183
|
+
value = custom_variables[key] || custom_variables[key.to_sym]
|
|
184
|
+
if value
|
|
185
|
+
properties[:d][:visitor][:props][key] = value
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Add IP address as a standard attribute if available
|
|
191
|
+
if ip_address && !ip_address.empty?
|
|
192
|
+
properties[:d][:visitor][:props][:ip] = ip_address
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_TRACK_USER", {
|
|
196
|
+
accountId: SettingsService.instance.account_id,
|
|
197
|
+
userId: user_id,
|
|
198
|
+
campaignId: campaign_id
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
properties
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Constructs payload for tracking goals with custom event properties
|
|
205
|
+
def get_track_goal_payload_data(event_name, event_properties, context)
|
|
206
|
+
properties = _get_event_base_payload(context.id, event_name, context.user_agent, context.ip_address)
|
|
207
|
+
properties[:d][:event][:props][:isCustomEvent] = true
|
|
208
|
+
|
|
209
|
+
# use sessionId from context if present
|
|
210
|
+
if context.get_session_id
|
|
211
|
+
properties[:d][:sessionId] = context.get_session_id
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# use uuid from context if present
|
|
215
|
+
if context.get_uuid && !context.get_uuid.empty?
|
|
216
|
+
properties[:d][:visId] = context.get_uuid
|
|
217
|
+
properties[:d][:msgId] = "#{context.get_uuid}-#{get_current_unix_timestamp_in_millis}"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
if SettingsService.instance.is_gateway_service_provided
|
|
221
|
+
properties[:d][:event][:props][:variation] = 1
|
|
222
|
+
properties[:d][:event][:props][:id] = 1 # Temporary value for ID
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
if event_properties.is_a?(Hash) && !event_properties.empty?
|
|
226
|
+
event_properties.each { |key, value| properties[:d][:event][:props][key] = value }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_TRACK_GOAL", {
|
|
230
|
+
eventName: event_name,
|
|
231
|
+
accountId: SettingsService.instance.account_id,
|
|
232
|
+
userId: context.id
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
properties
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def get_attribute_payload_data(event_name, event_properties, context)
|
|
239
|
+
properties = _get_event_base_payload(context.id, event_name, context.user_agent, context.ip_address)
|
|
240
|
+
properties[:d][:event][:props][:isCustomEvent] = true
|
|
241
|
+
|
|
242
|
+
# use sessionId from context if present
|
|
243
|
+
if context.get_session_id
|
|
244
|
+
properties[:d][:sessionId] = context.get_session_id
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# use uuid from context if present
|
|
248
|
+
if context.get_uuid && !context.get_uuid.empty?
|
|
249
|
+
properties[:d][:visId] = context.get_uuid
|
|
250
|
+
properties[:d][:msgId] = "#{context.get_uuid}-#{get_current_unix_timestamp_in_millis}"
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
if event_properties.is_a?(Hash) && !event_properties.empty?
|
|
254
|
+
event_properties.each { |key, value| properties[:d][:visitor][:props][key] = value }
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
LoggerService.log(LogLevelEnum::DEBUG, "IMPRESSION_FOR_SYNC_VISITOR_PROP", {
|
|
258
|
+
eventName: event_name,
|
|
259
|
+
accountId: SettingsService.instance.account_id,
|
|
260
|
+
userId: context.id
|
|
261
|
+
})
|
|
262
|
+
properties
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Constructs the payload for init called event.
|
|
266
|
+
# @param event_name - The name of the event.
|
|
267
|
+
# @param settings_fetch_time - Time taken to fetch settings in milliseconds.
|
|
268
|
+
# @param sdk_init_time - Time taken to initialize the SDK in milliseconds.
|
|
269
|
+
# @returns The constructed payload with required fields.
|
|
270
|
+
def get_sdk_init_event_payload(event_name, settings_fetch_time, sdk_init_time)
|
|
271
|
+
user_id = SettingsService.instance.account_id.to_s + "_" + SettingsService.instance.sdk_key
|
|
272
|
+
properties = _get_event_base_payload(user_id, event_name, nil, nil)
|
|
273
|
+
properties[:d][:event][:props][:vwo_fs_environment] = SettingsService.instance.sdk_key
|
|
274
|
+
properties[:d][:event][:props][:product] = Constants::PRODUCT_NAME
|
|
275
|
+
data = {
|
|
276
|
+
"isSDKInitialized": true,
|
|
277
|
+
"settingsFetchTime": settings_fetch_time,
|
|
278
|
+
"sdkInitTime": sdk_init_time
|
|
279
|
+
}
|
|
280
|
+
properties[:d][:event][:props][:data] = data
|
|
281
|
+
properties
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Constructs the payload for usage stats called event.
|
|
285
|
+
# @param event_name - The name of the event.
|
|
286
|
+
# @param usage_stats_account_id - The account id for usage stats.
|
|
287
|
+
# @returns The constructed payload with required fields.
|
|
288
|
+
def get_sdk_usage_stats_payload_data(event_name, usage_stats_account_id)
|
|
289
|
+
user_id = SettingsService.instance.account_id.to_s + "_" + SettingsService.instance.sdk_key
|
|
290
|
+
properties = _get_event_base_payload(user_id, event_name, nil, nil, true, usage_stats_account_id)
|
|
291
|
+
properties[:d][:event][:props][:product] = Constants::PRODUCT_NAME
|
|
292
|
+
properties[:d][:event][:props][:vwoMeta] = UsageStatsUtil.get_usage_stats
|
|
293
|
+
properties
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Sends a POST API request with given properties and payload
|
|
297
|
+
def send_post_api_request(properties, payload, campaign_info = {})
|
|
298
|
+
network_instance = NetworkManager.instance
|
|
299
|
+
headers = {}
|
|
300
|
+
headers[HeadersEnum::USER_AGENT] = payload[:d][:visitor_ua] if payload[:d][:visitor_ua]
|
|
301
|
+
headers[HeadersEnum::IP] = payload[:d][:visitor_ip] if payload[:d][:visitor_ip]
|
|
302
|
+
|
|
303
|
+
request = RequestModel.new(
|
|
304
|
+
SettingsService.instance.events_hostname,
|
|
305
|
+
HttpMethodEnum::POST,
|
|
306
|
+
SettingsService.instance.get_updated_endpoint_with_collection_prefix(UrlEnum::EVENTS, SettingsService.instance.is_gateway_service_provided),
|
|
307
|
+
properties,
|
|
308
|
+
payload,
|
|
309
|
+
headers,
|
|
310
|
+
SettingsService.instance.protocol,
|
|
311
|
+
SettingsService.instance.port
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
api_name = nil
|
|
315
|
+
extra_data_for_message = nil
|
|
316
|
+
if properties.key?(:en) && properties[:en] == EventEnum::VARIATION_SHOWN
|
|
317
|
+
api_name = ApiEnum::GET_FLAG
|
|
318
|
+
if campaign_info && campaign_info.key?(:campaign_type) && (campaign_info[:campaign_type] == CampaignTypeEnum::ROLLOUT || campaign_info[:campaign_type] == CampaignTypeEnum::PERSONALIZE)
|
|
319
|
+
extra_data_for_message = "feature: #{campaign_info[:feature_key]}, rule: #{campaign_info[:variation_name]}"
|
|
320
|
+
elsif campaign_info
|
|
321
|
+
extra_data_for_message = "feature: #{campaign_info[:feature_key]}, rule: #{campaign_info[:campaign_key]} and variation: #{campaign_info[:variation_name]}"
|
|
322
|
+
end
|
|
323
|
+
elsif properties.key?(:en) && properties[:en] != EventEnum::VARIATION_SHOWN
|
|
324
|
+
if properties.key?(:en) && properties[:en] == EventEnum::SYNC_VISITOR_PROP
|
|
325
|
+
api_name = ApiEnum::SET_ATTRIBUTE
|
|
326
|
+
extra_data_for_message = api_name
|
|
327
|
+
elsif properties.key?(:en) && properties[:en] != EventEnum::VARIATION_SHOWN && properties[:en] != EventEnum::DEBUGGER_EVENT && properties[:en] != EventEnum::INIT_CALLED
|
|
328
|
+
api_name = ApiEnum::TRACK_EVENT
|
|
329
|
+
extra_data_for_message = "event: #{properties[:en]}"
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
begin
|
|
333
|
+
if network_instance.get_client.get_should_use_threading
|
|
334
|
+
network_instance.get_client.get_thread_pool.post {
|
|
335
|
+
response = network_instance.post(request)
|
|
336
|
+
if response.get_total_attempts > 0
|
|
337
|
+
debug_event_props = create_network_and_retry_debug_event(response, request.get_body, api_name, extra_data_for_message)
|
|
338
|
+
debug_event_props[:uuid] = request.get_body[:d][:visId]
|
|
339
|
+
DebuggerServiceUtil.send_debugger_event(debug_event_props)
|
|
340
|
+
end
|
|
341
|
+
if response.get_status_code == 200
|
|
342
|
+
LoggerService.log(LogLevelEnum::INFO, "NETWORK_CALL_SUCCESS", {
|
|
343
|
+
event: properties[:en],
|
|
344
|
+
endPoint: UrlEnum::EVENTS,
|
|
345
|
+
accountId: SettingsService.instance.account_id,
|
|
346
|
+
uuid: request.get_body[:d][:visId]
|
|
347
|
+
})
|
|
348
|
+
end
|
|
349
|
+
response
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
response = network_instance.post(request)
|
|
353
|
+
if response.get_status_code == 200
|
|
354
|
+
LoggerService.log(LogLevelEnum::INFO, "NETWORK_CALL_SUCCESS", {
|
|
355
|
+
event: properties[:en],
|
|
356
|
+
endPoint: UrlEnum::EVENTS,
|
|
357
|
+
accountId: SettingsService.instance.account_id,
|
|
358
|
+
uuid: request.get_body[:d][:visId]
|
|
359
|
+
})
|
|
360
|
+
end
|
|
361
|
+
response
|
|
362
|
+
end
|
|
363
|
+
rescue ResponseModel => err
|
|
364
|
+
LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
|
|
365
|
+
method: extra_data_for_message,
|
|
366
|
+
err: get_formatted_error_message(err.get_error)
|
|
367
|
+
})
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Sends an event to VWO (generic event sender).
|
|
372
|
+
# @param properties - Query parameters for the request.
|
|
373
|
+
# @param payload - The payload for the request.
|
|
374
|
+
# @param event_name - The name of the event to send.
|
|
375
|
+
def send_event(properties, payload)
|
|
376
|
+
network_instance = NetworkManager.instance
|
|
377
|
+
headers = {}
|
|
378
|
+
headers[HeadersEnum::USER_AGENT] = payload[:d][:visitor_ua] if payload[:d][:visitor_ua]
|
|
379
|
+
headers[HeadersEnum::IP] = payload[:d][:visitor_ip] if payload[:d][:visitor_ip]
|
|
380
|
+
|
|
381
|
+
request = RequestModel.new(
|
|
382
|
+
SettingsService.instance.events_hostname,
|
|
383
|
+
HttpMethodEnum::POST,
|
|
384
|
+
SettingsService.instance.get_updated_endpoint_with_collection_prefix(UrlEnum::EVENTS, SettingsService.instance.is_gateway_service_provided),
|
|
385
|
+
properties,
|
|
386
|
+
payload,
|
|
387
|
+
headers,
|
|
388
|
+
SettingsService.instance.protocol,
|
|
389
|
+
SettingsService.instance.port,
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
begin
|
|
393
|
+
if network_instance.get_client.get_should_use_threading
|
|
394
|
+
network_instance.get_client.get_thread_pool.post {
|
|
395
|
+
response = network_instance.post(request)
|
|
396
|
+
if response.get_status_code == 200
|
|
397
|
+
LoggerService.log(LogLevelEnum::INFO, "NETWORK_CALL_SUCCESS", {
|
|
398
|
+
event: properties[:en],
|
|
399
|
+
endPoint: UrlEnum::EVENTS,
|
|
400
|
+
accountId: SettingsService.instance.account_id,
|
|
401
|
+
uuid: request.get_body[:d][:visId]
|
|
402
|
+
})
|
|
403
|
+
end
|
|
404
|
+
response
|
|
405
|
+
}
|
|
406
|
+
else
|
|
407
|
+
response = network_instance.post(request)
|
|
408
|
+
if response.get_status_code == 200
|
|
409
|
+
LoggerService.log(LogLevelEnum::INFO, "NETWORK_CALL_SUCCESS", {
|
|
410
|
+
event: properties[:en],
|
|
411
|
+
endPoint: UrlEnum::EVENTS,
|
|
412
|
+
accountId: SettingsService.instance.account_id,
|
|
413
|
+
uuid: request.get_body[:d][:visId]
|
|
414
|
+
})
|
|
415
|
+
end
|
|
416
|
+
response
|
|
417
|
+
end
|
|
418
|
+
rescue ResponseModel => err
|
|
419
|
+
if properties.key?(:en) && properties[:en] != EventEnum::DEBUGGER_EVENT
|
|
420
|
+
LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
|
|
421
|
+
method: "event: #{properties[:en]}",
|
|
422
|
+
err: get_formatted_error_message(err.get_error)
|
|
423
|
+
})
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# get debugger event payload
|
|
429
|
+
def get_debugger_event_payload(event_props)
|
|
430
|
+
user_id = SettingsService.instance.account_id.to_s + "_" + SettingsService.instance.sdk_key
|
|
431
|
+
properties = _get_event_base_payload(user_id, EventEnum::DEBUGGER_EVENT, nil, nil)
|
|
432
|
+
|
|
433
|
+
# check if event_props contains uuid key and should be non null and non empty string
|
|
434
|
+
if event_props.key?(:uuid) && event_props[:uuid].is_a?(String) && !event_props[:uuid].empty?
|
|
435
|
+
properties[:d][:msgId] = "#{event_props[:uuid]}-#{get_current_unix_timestamp_in_millis}"
|
|
436
|
+
properties[:d][:visId] = event_props[:uuid]
|
|
437
|
+
else
|
|
438
|
+
event_props[:uuid] = properties[:d][:visId]
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# check if event_props contains sessionId key
|
|
442
|
+
if event_props.key?(:sId)
|
|
443
|
+
properties[:d][:sessionId] = event_props[:sId]
|
|
444
|
+
else
|
|
445
|
+
event_props[:sId] = properties[:d][:sessionId]
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
event_props[:a] = SettingsService.instance.account_id.to_s
|
|
449
|
+
event_props[:product] = Constants::PRODUCT_NAME
|
|
450
|
+
event_props[:sn] = SettingsService.instance.sdk_name
|
|
451
|
+
event_props[:sv] = Constants::SDK_VERSION
|
|
452
|
+
event_props[:eventId] = UUIDUtil.get_random_uuid(SettingsService.instance.sdk_key)
|
|
453
|
+
|
|
454
|
+
properties[:d][:event][:props] = {}
|
|
455
|
+
properties[:d][:event][:props][:vwoMeta] = event_props
|
|
456
|
+
properties
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def create_network_and_retry_debug_event(response, payload, api_name, extra_data)
|
|
460
|
+
begin
|
|
461
|
+
category = DebugCategoryEnum::RETRY
|
|
462
|
+
msg_t = Constants::NETWORK_CALL_SUCCESS_WITH_RETRIES
|
|
463
|
+
msg = build_message(LoggerService.get_messages(LogLevelEnum::INFO)[msg_t], {
|
|
464
|
+
extraData: extra_data,
|
|
465
|
+
attempts: response.get_total_attempts,
|
|
466
|
+
err: get_formatted_error_message(response.get_error)
|
|
467
|
+
})
|
|
468
|
+
lt = LogLevelEnum::INFO.to_s
|
|
469
|
+
if response.get_status_code != 200
|
|
470
|
+
category = DebugCategoryEnum::NETWORK
|
|
471
|
+
msg_t = Constants::NETWORK_CALL_FAILURE_AFTER_MAX_RETRIES
|
|
472
|
+
msg = build_message(LoggerService.get_messages(LogLevelEnum::ERROR)[msg_t], {
|
|
473
|
+
extraData: extra_data,
|
|
474
|
+
attempts: response.get_total_attempts,
|
|
475
|
+
err: get_formatted_error_message(response.get_error)
|
|
476
|
+
})
|
|
477
|
+
lt = LogLevelEnum::ERROR.to_s
|
|
478
|
+
end
|
|
479
|
+
debug_event_props = {
|
|
480
|
+
cg: category,
|
|
481
|
+
msg_t: msg_t,
|
|
482
|
+
msg: msg,
|
|
483
|
+
lt: lt
|
|
484
|
+
}
|
|
485
|
+
if api_name
|
|
486
|
+
debug_event_props[:an] = api_name
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
if payload && payload[:d] && payload[:d][:sessionId]
|
|
490
|
+
debug_event_props[:sId] = payload[:d][:sessionId]
|
|
491
|
+
else
|
|
492
|
+
debug_event_props[:sId] = get_current_unix_timestamp
|
|
493
|
+
end
|
|
494
|
+
debug_event_props
|
|
495
|
+
rescue StandardError => err
|
|
496
|
+
LoggerService.log(LogLevelEnum::ERROR, "NETWORK_CALL_FAILED", {
|
|
497
|
+
method: extra_data,
|
|
498
|
+
err: get_formatted_error_message(err)
|
|
499
|
+
})
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Copyright 2024-2026 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/campaign/campaign_model'
|
|
16
|
+
require_relative '../models/campaign/feature_model'
|
|
17
|
+
require_relative '../models/settings/settings_model'
|
|
18
|
+
require_relative '../models/user/context_model'
|
|
19
|
+
require_relative '../services/storage_service'
|
|
20
|
+
require_relative './data_type_util'
|
|
21
|
+
require_relative './decision_util'
|
|
22
|
+
require_relative './network_util'
|
|
23
|
+
require_relative './impression_util'
|
|
24
|
+
|
|
25
|
+
# Evaluates the rules for a given campaign and feature based on the provided context.
|
|
26
|
+
#
|
|
27
|
+
# @param settings [SettingsModel] The settings configuration for evaluation.
|
|
28
|
+
# @param feature [FeatureModel] The feature being evaluated.
|
|
29
|
+
# @param campaign [CampaignModel] The campaign associated with the feature.
|
|
30
|
+
# @param context [ContextModel] The user context for evaluation.
|
|
31
|
+
# @param evaluated_feature_map [Hash] A hash of evaluated features.
|
|
32
|
+
# @param meg_group_winner_campaigns [Hash] A hash of MEG group winner campaigns.
|
|
33
|
+
# @param storage_service [StorageService] The storage service for persistence.
|
|
34
|
+
# @param decision [Hash] The decision object that will be updated based on the evaluation.
|
|
35
|
+
# @return [Hash] A hash containing the result of the pre-segmentation and the whitelisted object.
|
|
36
|
+
def evaluate_rule(settings, feature, campaign, context, evaluated_feature_map, meg_group_winner_campaigns, storage_service, decision)
|
|
37
|
+
# Perform whitelisting and pre-segmentation checks
|
|
38
|
+
pre_segmentation_result, whitelisted_object = DecisionUtil.check_whitelisting_and_pre_seg(
|
|
39
|
+
settings, feature, campaign, context, evaluated_feature_map, meg_group_winner_campaigns, storage_service, decision
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# If pre-segmentation is successful and a whitelisted object exists, proceed to send an impression
|
|
43
|
+
if pre_segmentation_result && whitelisted_object.is_a?(Hash) && !whitelisted_object.empty?
|
|
44
|
+
# Update the decision object with campaign and variation details
|
|
45
|
+
decision.merge!(
|
|
46
|
+
experiment_id: campaign.get_id,
|
|
47
|
+
experiment_key: campaign.get_key,
|
|
48
|
+
experiment_variation_id: whitelisted_object[:variation_id]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Send an impression for the variation shown
|
|
52
|
+
create_and_send_impression_for_variation_shown(settings, campaign.get_id, whitelisted_object[:variation_id], context, feature.get_key)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Return the results of the evaluation
|
|
56
|
+
{ pre_segmentation_result: pre_segmentation_result, whitelisted_object: whitelisted_object, updated_decision: decision }
|
|
57
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright 2024-2026 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/settings/settings_model'
|
|
16
|
+
require_relative 'campaign_util'
|
|
17
|
+
require_relative 'function_util'
|
|
18
|
+
require_relative 'gateway_service_util'
|
|
19
|
+
|
|
20
|
+
# Sets settings and adds campaigns to rules
|
|
21
|
+
#
|
|
22
|
+
# @param settings [Hash] The settings configuration
|
|
23
|
+
# @param vwo_client_instance [VWOClient] The VWOClient instance
|
|
24
|
+
def set_settings_and_add_campaigns_to_rules(settings, vwo_client_instance)
|
|
25
|
+
# Create settings model and assign it to vwo_client_instance
|
|
26
|
+
vwo_client_instance.settings = SettingsModel.new(settings)
|
|
27
|
+
vwo_client_instance.original_settings = settings
|
|
28
|
+
|
|
29
|
+
# Optimize loop by avoiding multiple calls to get_campaigns()
|
|
30
|
+
campaigns = vwo_client_instance.settings.get_campaigns
|
|
31
|
+
campaigns.each_with_index do |campaign, index|
|
|
32
|
+
CampaignUtil.set_variation_allocation(campaign)
|
|
33
|
+
campaigns[index] = campaign
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
add_linked_campaigns_to_settings(vwo_client_instance.settings)
|
|
37
|
+
add_is_gateway_service_required_flag(vwo_client_instance.settings)
|
|
38
|
+
end
|