statsig 1.31.1 → 1.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/api_config.rb +128 -0
- data/lib/client_initialize_helpers.rb +78 -88
- data/lib/config_result.rb +17 -32
- data/lib/constants.rb +60 -0
- data/lib/diagnostics.rb +1 -38
- data/lib/dynamic_config.rb +1 -24
- data/lib/error_boundary.rb +0 -5
- data/lib/evaluation_details.rb +4 -1
- data/lib/evaluation_helpers.rb +35 -3
- data/lib/evaluator.rb +332 -327
- data/lib/feature_gate.rb +0 -24
- data/lib/id_list.rb +1 -1
- data/lib/interfaces/data_store.rb +1 -1
- data/lib/interfaces/user_persistent_storage.rb +1 -1
- data/lib/layer.rb +1 -20
- data/lib/network.rb +6 -33
- data/lib/spec_store.rb +86 -74
- data/lib/statsig.rb +72 -97
- data/lib/statsig_driver.rb +63 -70
- data/lib/statsig_errors.rb +1 -1
- data/lib/statsig_event.rb +8 -8
- data/lib/statsig_logger.rb +21 -21
- data/lib/statsig_options.rb +0 -50
- data/lib/statsig_user.rb +27 -68
- data/lib/ua_parser.rb +1 -1
- data/lib/uri_helper.rb +1 -9
- data/lib/user_persistent_storage_utils.rb +0 -17
- metadata +8 -6
data/lib/statsig_logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'constants'
|
2
2
|
require 'statsig_event'
|
3
3
|
require 'concurrent-ruby'
|
4
4
|
|
@@ -6,7 +6,7 @@ $gate_exposure_event = 'statsig::gate_exposure'
|
|
6
6
|
$config_exposure_event = 'statsig::config_exposure'
|
7
7
|
$layer_exposure_event = 'statsig::layer_exposure'
|
8
8
|
$diagnostics_event = 'statsig::diagnostics'
|
9
|
-
$ignored_metadata_keys = [
|
9
|
+
$ignored_metadata_keys = [:serverTime, :configSyncTime, :initTime, :reason]
|
10
10
|
module Statsig
|
11
11
|
class StatsigLogger
|
12
12
|
def initialize(network, options, error_boundary)
|
@@ -41,9 +41,9 @@ module Statsig
|
|
41
41
|
event = StatsigEvent.new($gate_exposure_event)
|
42
42
|
event.user = user
|
43
43
|
metadata = {
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
gate: gate_name,
|
45
|
+
gateValue: value.to_s,
|
46
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
47
47
|
}
|
48
48
|
return false if not is_unique_exposure(user, $gate_exposure_event, metadata)
|
49
49
|
event.metadata = metadata
|
@@ -59,8 +59,8 @@ module Statsig
|
|
59
59
|
event = StatsigEvent.new($config_exposure_event)
|
60
60
|
event.user = user
|
61
61
|
metadata = {
|
62
|
-
|
63
|
-
|
62
|
+
config: config_name,
|
63
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
64
64
|
}
|
65
65
|
return false if not is_unique_exposure(user, $config_exposure_event, metadata)
|
66
66
|
event.metadata = metadata
|
@@ -72,8 +72,8 @@ module Statsig
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
|
75
|
-
exposures = config_evaluation.undelegated_sec_exps
|
76
|
-
allocated_experiment =
|
75
|
+
exposures = config_evaluation.undelegated_sec_exps || []
|
76
|
+
allocated_experiment = Statsig::Const::EMPTY_STR
|
77
77
|
is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
|
78
78
|
if is_explicit
|
79
79
|
allocated_experiment = config_evaluation.config_delegate
|
@@ -83,13 +83,13 @@ module Statsig
|
|
83
83
|
event = StatsigEvent.new($layer_exposure_event)
|
84
84
|
event.user = user
|
85
85
|
metadata = {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
config: layer.name,
|
87
|
+
ruleID: layer.rule_id || Statsig::Const::EMPTY_STR,
|
88
|
+
allocatedExperiment: allocated_experiment,
|
89
|
+
parameterName: parameter_name,
|
90
|
+
isExplicitParameter: String(is_explicit)
|
91
91
|
}
|
92
|
-
return false
|
92
|
+
return false unless is_unique_exposure(user, $layer_exposure_event, metadata)
|
93
93
|
event.metadata = metadata
|
94
94
|
event.secondary_exposures = exposures.is_a?(Array) ? exposures : []
|
95
95
|
|
@@ -167,10 +167,10 @@ module Statsig
|
|
167
167
|
return
|
168
168
|
end
|
169
169
|
|
170
|
-
event.metadata[
|
171
|
-
event.metadata[
|
172
|
-
event.metadata[
|
173
|
-
event.metadata[
|
170
|
+
event.metadata[:reason] = eval_details.reason
|
171
|
+
event.metadata[:configSyncTime] = eval_details.config_sync_time
|
172
|
+
event.metadata[:initTime] = eval_details.init_time
|
173
|
+
event.metadata[:serverTime] = eval_details.server_time
|
174
174
|
end
|
175
175
|
|
176
176
|
def safe_add_exposure_context(context, event)
|
@@ -178,8 +178,8 @@ module Statsig
|
|
178
178
|
return
|
179
179
|
end
|
180
180
|
|
181
|
-
if context[
|
182
|
-
event.metadata[
|
181
|
+
if context[:is_manual_exposure]
|
182
|
+
event.metadata[:isManualExposure] = 'true'
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
data/lib/statsig_options.rb
CHANGED
@@ -1,142 +1,92 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require_relative 'interfaces/data_store'
|
5
2
|
require_relative 'interfaces/user_persistent_storage'
|
6
3
|
|
7
4
|
##
|
8
5
|
# Configuration options for the Statsig SDK.
|
9
6
|
class StatsigOptions
|
10
|
-
extend T::Sig
|
11
7
|
|
12
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
13
8
|
# Hash you can use to set environment variables that apply to all of your users in
|
14
9
|
# the same session and will be used for targeting purposes.
|
15
10
|
# eg. { "tier" => "development" }
|
16
11
|
attr_accessor :environment
|
17
12
|
|
18
|
-
sig { returns(String) }
|
19
13
|
# The base url used to make network calls to Statsig.
|
20
14
|
# default: https://statsigapi.net/v1
|
21
15
|
attr_accessor :api_url_base
|
22
16
|
|
23
17
|
# The base url used specifically to call download_config_specs.
|
24
18
|
# Takes precedence over api_url_base
|
25
|
-
sig { returns(String) }
|
26
19
|
attr_accessor :api_url_download_config_specs
|
27
20
|
|
28
|
-
sig { returns(T.any(Float, Integer)) }
|
29
21
|
# The interval (in seconds) to poll for changes to your Statsig configuration
|
30
22
|
# default: 10s
|
31
23
|
attr_accessor :rulesets_sync_interval
|
32
24
|
|
33
|
-
sig { returns(T.any(Float, Integer)) }
|
34
25
|
# The interval (in seconds) to poll for changes to your id lists
|
35
26
|
# default: 60s
|
36
27
|
attr_accessor :idlists_sync_interval
|
37
28
|
|
38
29
|
# Disable background syncing for rulesets
|
39
|
-
sig { returns(T::Boolean) }
|
40
30
|
attr_accessor :disable_rulesets_sync
|
41
31
|
|
42
32
|
# Disable background syncing for id lists
|
43
|
-
sig { returns(T::Boolean) }
|
44
33
|
attr_accessor :disable_idlists_sync
|
45
34
|
|
46
|
-
sig { returns(T.any(Float, Integer)) }
|
47
35
|
# How often to flush logs to Statsig
|
48
36
|
# default: 60s
|
49
37
|
attr_accessor :logging_interval_seconds
|
50
38
|
|
51
|
-
sig { returns(Integer) }
|
52
39
|
# The maximum number of events to batch before flushing logs to the server
|
53
40
|
# default: 1000
|
54
41
|
attr_accessor :logging_max_buffer_size
|
55
42
|
|
56
|
-
sig { returns(T::Boolean) }
|
57
43
|
# Restricts the SDK to not issue any network requests and only respond with default values (or local overrides)
|
58
44
|
# default: false
|
59
45
|
attr_accessor :local_mode
|
60
46
|
|
61
|
-
sig { returns(T.any(String, NilClass)) }
|
62
47
|
# A string that represents all rules for all feature gates, dynamic configs and experiments.
|
63
48
|
# It can be provided to bootstrap the Statsig server SDK at initialization in case your server runs
|
64
49
|
# into network issue or Statsig is down temporarily.
|
65
50
|
attr_accessor :bootstrap_values
|
66
51
|
|
67
|
-
sig { returns(T.any(Method, Proc, NilClass)) }
|
68
52
|
# A callback function that will be called anytime the rulesets are updated.
|
69
53
|
attr_accessor :rules_updated_callback
|
70
54
|
|
71
|
-
sig { returns(T.any(Statsig::Interfaces::IDataStore, NilClass)) }
|
72
55
|
# A class that extends IDataStore. Can be used to provide values from a
|
73
56
|
# common data store (like Redis) to initialize the Statsig SDK.
|
74
57
|
attr_accessor :data_store
|
75
58
|
|
76
|
-
sig { returns(Integer) }
|
77
59
|
# The number of threads allocated to syncing IDLists.
|
78
60
|
# default: 3
|
79
61
|
attr_accessor :idlist_threadpool_size
|
80
62
|
|
81
|
-
sig { returns(Integer) }
|
82
63
|
# The number of threads allocated to posting event logs.
|
83
64
|
# default: 3
|
84
65
|
attr_accessor :logger_threadpool_size
|
85
66
|
|
86
|
-
sig { returns(T::Boolean) }
|
87
67
|
# Should diagnostics be logged. These include performance metrics for initialize.
|
88
68
|
# default: false
|
89
69
|
attr_accessor :disable_diagnostics_logging
|
90
70
|
|
91
|
-
sig { returns(T::Boolean) }
|
92
71
|
# Statsig utilizes Sorbet (https://sorbet.org) to ensure type safety of the SDK. This includes logging
|
93
72
|
# to console when errors are detected. You can disable this logging by setting this flag to true.
|
94
73
|
# default: false
|
95
74
|
attr_accessor :disable_sorbet_logging_handlers
|
96
75
|
|
97
|
-
sig { returns(T.any(Integer, NilClass)) }
|
98
76
|
# Number of seconds before a network call is timed out
|
99
77
|
attr_accessor :network_timeout
|
100
78
|
|
101
|
-
sig { returns(Integer) }
|
102
79
|
# Number of times to retry sending a batch of failed log events
|
103
80
|
attr_accessor :post_logs_retry_limit
|
104
81
|
|
105
|
-
sig { returns(T.any(Method, Proc, Integer, NilClass)) }
|
106
82
|
# The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
|
107
83
|
# which overrides the default backoff time between retries
|
108
84
|
attr_accessor :post_logs_retry_backoff
|
109
85
|
|
110
|
-
sig { returns(T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)) }
|
111
86
|
# A storage adapter for persisted values. Can be used for sticky bucketing users in experiments.
|
112
87
|
# Implements Statsig::Interfaces::IUserPersistentStorage.
|
113
88
|
attr_accessor :user_persistent_storage
|
114
89
|
|
115
|
-
sig do
|
116
|
-
params(
|
117
|
-
environment: T.any(T::Hash[String, String], NilClass),
|
118
|
-
api_url_base: T.nilable(String),
|
119
|
-
api_url_download_config_specs: T.any(String, NilClass),
|
120
|
-
rulesets_sync_interval: T.any(Float, Integer),
|
121
|
-
idlists_sync_interval: T.any(Float, Integer),
|
122
|
-
disable_rulesets_sync: T::Boolean,
|
123
|
-
disable_idlists_sync: T::Boolean,
|
124
|
-
logging_interval_seconds: T.any(Float, Integer),
|
125
|
-
logging_max_buffer_size: Integer,
|
126
|
-
local_mode: T::Boolean,
|
127
|
-
bootstrap_values: T.any(String, NilClass),
|
128
|
-
rules_updated_callback: T.any(Method, Proc, NilClass),
|
129
|
-
data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
|
130
|
-
idlist_threadpool_size: Integer,
|
131
|
-
logger_threadpool_size: Integer,
|
132
|
-
disable_diagnostics_logging: T::Boolean,
|
133
|
-
disable_sorbet_logging_handlers: T::Boolean,
|
134
|
-
network_timeout: T.any(Integer, NilClass),
|
135
|
-
post_logs_retry_limit: Integer,
|
136
|
-
post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass),
|
137
|
-
user_persistent_storage: T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)
|
138
|
-
).void
|
139
|
-
end
|
140
90
|
def initialize(
|
141
91
|
environment = nil,
|
142
92
|
api_url_base = nil,
|
data/lib/statsig_user.rb
CHANGED
@@ -1,65 +1,49 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require 'json'
|
2
|
+
require 'constants'
|
5
3
|
|
6
4
|
##
|
7
5
|
# The user object to be evaluated against your Statsig configurations (gates/experiments/dynamic configs).
|
8
6
|
class StatsigUser
|
9
|
-
extend T::Sig
|
10
7
|
|
11
|
-
sig { returns(T.any(String, NilClass)) }
|
12
8
|
# An identifier for this user. Evaluated against the User ID criteria. (https://docs.statsig.com/feature-gates/conditions#userid)
|
13
9
|
attr_accessor :user_id
|
14
10
|
|
15
|
-
sig { returns(T.any(String, NilClass)) }
|
16
11
|
# An identifier for this user. Evaluated against the Email criteria. (https://docs.statsig.com/feature-gates/conditions#email)
|
17
12
|
attr_accessor :email
|
18
13
|
|
19
|
-
sig { returns(T.any(String, NilClass)) }
|
20
14
|
# An IP address associated with this user. Evaluated against the IP Address criteria. (https://docs.statsig.com/feature-gates/conditions#ip)
|
21
15
|
attr_accessor :ip
|
22
16
|
|
23
|
-
sig { returns(T.any(String, NilClass)) }
|
24
17
|
# A user agent string associated with this user. Evaluated against Browser Version and Name (https://docs.statsig.com/feature-gates/conditions#browser-version)
|
25
18
|
attr_accessor :user_agent
|
26
19
|
|
27
|
-
sig { returns(T.any(String, NilClass)) }
|
28
20
|
# The country code associated with this user (e.g New Zealand => NZ). Evaluated against the Country criteria. (https://docs.statsig.com/feature-gates/conditions#country)
|
29
21
|
attr_accessor :country
|
30
22
|
|
31
|
-
sig { returns(T.any(String, NilClass)) }
|
32
23
|
# An locale for this user.
|
33
24
|
attr_accessor :locale
|
34
25
|
|
35
|
-
sig { returns(T.any(String, NilClass)) }
|
36
26
|
# The current app version the user is interacting with. Evaluated against the App Version criteria. (https://docs.statsig.com/feature-gates/conditions#app-version)
|
37
27
|
attr_accessor :app_version
|
38
28
|
|
39
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
40
29
|
# A Hash you can use to set environment variables that apply to this user. e.g. { "tier" => "development" }
|
41
30
|
attr_accessor :statsig_environment
|
42
31
|
|
43
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
44
32
|
# Any Custom IDs to associated with the user. (See https://docs.statsig.com/guides/experiment-on-custom-id-types)
|
45
33
|
attr_accessor :custom_ids
|
46
34
|
|
47
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
48
35
|
# Any value you wish to use in evaluation, but do not want logged with events, can be stored in this field.
|
49
36
|
attr_accessor :private_attributes
|
50
37
|
|
51
|
-
sig { returns(T.any(T::Hash[String, T.untyped], NilClass)) }
|
52
38
|
def custom
|
53
39
|
@custom
|
54
40
|
end
|
55
41
|
|
56
|
-
sig { params(value: T.any(T::Hash[String, T.untyped], NilClass)).void }
|
57
42
|
# Any custom fields for this user. Evaluated against the Custom criteria. (https://docs.statsig.com/feature-gates/conditions#custom)
|
58
43
|
def custom=(value)
|
59
44
|
@custom = value.is_a?(Hash) ? value : Hash.new
|
60
45
|
end
|
61
46
|
|
62
|
-
sig { params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass)).void }
|
63
47
|
def initialize(user_hash)
|
64
48
|
the_hash = user_hash
|
65
49
|
begin
|
@@ -83,55 +67,56 @@ class StatsigUser
|
|
83
67
|
|
84
68
|
def serialize(for_logging)
|
85
69
|
hash = {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
70
|
+
:userID => @user_id,
|
71
|
+
:email => @email,
|
72
|
+
:ip => @ip,
|
73
|
+
:userAgent => @user_agent,
|
74
|
+
:country => @country,
|
75
|
+
:locale => @locale,
|
76
|
+
:appVersion => @app_version,
|
77
|
+
:custom => @custom,
|
78
|
+
:statsigEnvironment => @statsig_environment,
|
79
|
+
:privateAttributes => @private_attributes,
|
80
|
+
:customIDs => @custom_ids,
|
97
81
|
}
|
98
82
|
if for_logging
|
99
|
-
hash.delete(
|
83
|
+
hash.delete(:privateAttributes)
|
100
84
|
end
|
101
85
|
hash.compact
|
102
86
|
end
|
103
87
|
|
104
|
-
def to_hash_without_stable_id
|
88
|
+
def to_hash_without_stable_id
|
105
89
|
hash = {}
|
90
|
+
|
106
91
|
if @user_id != nil
|
107
|
-
hash[
|
92
|
+
hash[:userID] = @user_id
|
108
93
|
end
|
109
94
|
if @email != nil
|
110
|
-
hash[
|
95
|
+
hash[:email] = @email
|
111
96
|
end
|
112
97
|
if @ip != nil
|
113
|
-
hash[
|
98
|
+
hash[:ip] = @ip
|
114
99
|
end
|
115
100
|
if @user_agent != nil
|
116
|
-
hash[
|
101
|
+
hash[:userAgent] = @user_agent
|
117
102
|
end
|
118
103
|
if @country != nil
|
119
|
-
hash[
|
104
|
+
hash[:country] = @country
|
120
105
|
end
|
121
106
|
if @locale != nil
|
122
|
-
hash[
|
107
|
+
hash[:locale] = @locale
|
123
108
|
end
|
124
109
|
if @app_version != nil
|
125
|
-
hash[
|
110
|
+
hash[:appVersion] = @app_version
|
126
111
|
end
|
127
112
|
if @custom != nil
|
128
|
-
hash[
|
113
|
+
hash[:custom] = Statsig::HashUtils.sortHash(@custom)
|
129
114
|
end
|
130
115
|
if @statsig_environment != nil
|
131
|
-
hash[
|
116
|
+
hash[:statsigEnvironment] = @statsig_environment.clone.sort_by { |key| key }.to_h
|
132
117
|
end
|
133
118
|
if @private_attributes != nil
|
134
|
-
hash[
|
119
|
+
hash[:privateAttributes] = Statsig::HashUtils.sortHash(@private_attributes)
|
135
120
|
end
|
136
121
|
custom_ids = {}
|
137
122
|
if @custom_ids != nil
|
@@ -140,32 +125,12 @@ class StatsigUser
|
|
140
125
|
custom_ids.delete("stableID")
|
141
126
|
end
|
142
127
|
end
|
143
|
-
hash[
|
128
|
+
hash[:customIDs] = custom_ids.sort_by { |key| key }.to_h
|
144
129
|
return Statsig::HashUtils.djb2ForHash(hash.sort_by { |key| key }.to_h)
|
145
130
|
end
|
146
131
|
|
147
|
-
def value_lookup
|
148
|
-
{
|
149
|
-
'userID' => @user_id,
|
150
|
-
'userid' => @user_id,
|
151
|
-
'user_id' => @user_id,
|
152
|
-
'email' => @email,
|
153
|
-
'ip' => @ip,
|
154
|
-
'userAgent' => @user_agent,
|
155
|
-
'useragent' => @user_agent,
|
156
|
-
'user_agent' => @user_agent,
|
157
|
-
'country' => @country,
|
158
|
-
'locale' => @locale,
|
159
|
-
'appVersion' => @app_version,
|
160
|
-
'appversion' => @app_version,
|
161
|
-
'app_version' => @app_version,
|
162
|
-
'custom' => @custom,
|
163
|
-
'privateAttributes' => @private_attributes,
|
164
|
-
}
|
165
|
-
end
|
166
|
-
|
167
132
|
def get_unit_id(id_type)
|
168
|
-
if id_type.is_a?(String) && id_type
|
133
|
+
if id_type.is_a?(String) && id_type != Statsig::Const::CML_USER_ID
|
169
134
|
return nil unless @custom_ids.is_a? Hash
|
170
135
|
|
171
136
|
return @custom_ids[id_type] || @custom_ids[id_type.downcase]
|
@@ -175,12 +140,6 @@ class StatsigUser
|
|
175
140
|
|
176
141
|
private
|
177
142
|
|
178
|
-
sig {
|
179
|
-
params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass),
|
180
|
-
keys: T::Array[Symbol],
|
181
|
-
type: T.untyped)
|
182
|
-
.returns(T.untyped)
|
183
|
-
}
|
184
143
|
# Pulls fields from the user hash via Symbols and Strings
|
185
144
|
def from_hash(user_hash, keys, type)
|
186
145
|
if user_hash.nil?
|
data/lib/ua_parser.rb
CHANGED
data/lib/uri_helper.rb
CHANGED
@@ -1,24 +1,16 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
|
-
|
5
1
|
class URIHelper
|
6
2
|
class URIBuilder
|
7
|
-
extend T::Sig
|
8
3
|
|
9
|
-
sig { returns(StatsigOptions) }
|
10
4
|
attr_accessor :options
|
11
5
|
|
12
|
-
sig { params(options: StatsigOptions).void }
|
13
6
|
def initialize(options)
|
14
7
|
@options = options
|
15
8
|
end
|
16
9
|
|
17
|
-
sig { params(endpoint: String).returns(String) }
|
18
10
|
def build_url(endpoint)
|
19
11
|
api = @options.api_url_base
|
20
12
|
if endpoint.include?('download_config_specs')
|
21
|
-
api =
|
13
|
+
api = @options.api_url_download_config_specs
|
22
14
|
end
|
23
15
|
unless api.end_with?('/')
|
24
16
|
api += '/'
|
@@ -1,27 +1,17 @@
|
|
1
|
-
# typed: false
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require 'statsig_options'
|
5
2
|
|
6
3
|
module Statsig
|
7
|
-
UserPersistedValues = T.type_alias { T::Hash[String, Hash] }
|
8
|
-
|
9
4
|
class UserPersistentStorageUtils
|
10
|
-
extend T::Sig
|
11
5
|
|
12
|
-
sig { returns(T::Hash[String, UserPersistedValues]) }
|
13
6
|
attr_accessor :cache
|
14
7
|
|
15
|
-
sig { returns(T.nilable(Interfaces::IUserPersistentStorage)) }
|
16
8
|
attr_accessor :storage
|
17
9
|
|
18
|
-
sig { params(options: StatsigOptions).void }
|
19
10
|
def initialize(options)
|
20
11
|
@storage = options.user_persistent_storage
|
21
12
|
@cache = {}
|
22
13
|
end
|
23
14
|
|
24
|
-
sig { params(user: StatsigUser, id_type: String).returns(T.nilable(UserPersistedValues)) }
|
25
15
|
def get_user_persisted_values(user, id_type)
|
26
16
|
key = self.class.get_storage_key(user, id_type)
|
27
17
|
return @cache[key] unless @cache[key].nil?
|
@@ -29,7 +19,6 @@ module Statsig
|
|
29
19
|
return load_from_storage(key)
|
30
20
|
end
|
31
21
|
|
32
|
-
sig { params(key: String).returns(T.nilable(UserPersistedValues)) }
|
33
22
|
def load_from_storage(key)
|
34
23
|
return if @storage.nil?
|
35
24
|
|
@@ -50,7 +39,6 @@ module Statsig
|
|
50
39
|
return nil
|
51
40
|
end
|
52
41
|
|
53
|
-
sig { params(user: StatsigUser, id_type: String, user_persisted_values: UserPersistedValues).void }
|
54
42
|
def save_to_storage(user, id_type, user_persisted_values)
|
55
43
|
return if @storage.nil?
|
56
44
|
|
@@ -65,7 +53,6 @@ module Statsig
|
|
65
53
|
end
|
66
54
|
end
|
67
55
|
|
68
|
-
sig { params(user: StatsigUser, id_type: String, config_name: String).void }
|
69
56
|
def remove_experiment_from_storage(user, id_type, config_name)
|
70
57
|
persisted_values = get_user_persisted_values(user, id_type)
|
71
58
|
unless persisted_values.nil?
|
@@ -74,7 +61,6 @@ module Statsig
|
|
74
61
|
end
|
75
62
|
end
|
76
63
|
|
77
|
-
sig { params(user_persisted_values: T.nilable(UserPersistedValues), config_name: String, evaluation: ConfigResult).void }
|
78
64
|
def add_evaluation_to_user_persisted_values(user_persisted_values, config_name, evaluation)
|
79
65
|
if user_persisted_values.nil?
|
80
66
|
user_persisted_values = {}
|
@@ -84,21 +70,18 @@ module Statsig
|
|
84
70
|
|
85
71
|
private
|
86
72
|
|
87
|
-
sig { params(values_string: String).returns(T.nilable(UserPersistedValues)) }
|
88
73
|
def self.parse(values_string)
|
89
74
|
return JSON.parse(values_string)
|
90
75
|
rescue JSON::ParserError
|
91
76
|
return nil
|
92
77
|
end
|
93
78
|
|
94
|
-
sig { params(values_object: UserPersistedValues).returns(T.nilable(String)) }
|
95
79
|
def self.stringify(values_object)
|
96
80
|
return JSON.generate(values_object)
|
97
81
|
rescue StandardError
|
98
82
|
return nil
|
99
83
|
end
|
100
84
|
|
101
|
-
sig { params(user: StatsigUser, id_type: String).returns(String) }
|
102
85
|
def self.get_storage_key(user, id_type)
|
103
86
|
"#{user.get_unit_id(id_type)}:#{id_type}"
|
104
87
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.32.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -322,8 +322,10 @@ executables: []
|
|
322
322
|
extensions: []
|
323
323
|
extra_rdoc_files: []
|
324
324
|
files:
|
325
|
+
- lib/api_config.rb
|
325
326
|
- lib/client_initialize_helpers.rb
|
326
327
|
- lib/config_result.rb
|
328
|
+
- lib/constants.rb
|
327
329
|
- lib/diagnostics.rb
|
328
330
|
- lib/dynamic_config.rb
|
329
331
|
- lib/error_boundary.rb
|
@@ -352,7 +354,7 @@ homepage: https://rubygems.org/gems/statsig
|
|
352
354
|
licenses:
|
353
355
|
- ISC
|
354
356
|
metadata: {}
|
355
|
-
post_install_message:
|
357
|
+
post_install_message:
|
356
358
|
rdoc_options: []
|
357
359
|
require_paths:
|
358
360
|
- lib
|
@@ -367,8 +369,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
367
369
|
- !ruby/object:Gem::Version
|
368
370
|
version: '0'
|
369
371
|
requirements: []
|
370
|
-
rubygems_version: 3.
|
371
|
-
signing_key:
|
372
|
+
rubygems_version: 3.2.33
|
373
|
+
signing_key:
|
372
374
|
specification_version: 4
|
373
375
|
summary: Statsig server SDK for Ruby
|
374
376
|
test_files: []
|