amplitude-experiment 1.0.1 → 1.1.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 +4 -4
- data/amplitude-experiment.gemspec +32 -0
- data/lib/amplitude-experiment.rb +0 -2
- data/lib/experiment/local/client.rb +39 -34
- data/lib/experiment/local/config.rb +1 -5
- data/lib/experiment/local/evaluation/evaluation.rb +17 -0
- data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop.so +0 -0
- data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop_api.h +28 -0
- data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop.so +0 -0
- data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop_api.h +28 -0
- data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop.dylib +0 -0
- data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop_api.h +28 -0
- data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop.dylib +0 -0
- data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop_api.h +28 -0
- data/lib/experiment/local/fetcher.rb +22 -3
- data/lib/experiment/version.rb +1 -1
- metadata +3 -4
- data/lib/experiment/local/cache.rb +0 -53
- data/lib/experiment/local/poller.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff36301b51f9c519b85c5361aa6e50e45d0e55738ee6d36e10b3599e6b91b98b
|
4
|
+
data.tar.gz: 6e03119d4dd2b6f33c4f0ba312043aac2eb688f211cf827a046d90457a40dcdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf4ab1ee2bdc9dc1d40c0b95cbb2a6f4559a7473fa64997045bbb7b0bc9ac3a5c05cc5826a3f411198e3807f41e57de9c491cf44bbe2409c02fd368174d425a5
|
7
|
+
data.tar.gz: 9fb0b7f55cde6e6e51774b5dc434c8f9ec4707b94a03576636a5bec115c23f4e60d09a93fb855595f41be65b8a9ef0b912c671587df16bbe5587950b267e3a5a
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path('lib/experiment/version', __dir__)
|
2
|
+
Gem::Specification.new do |spec|
|
3
|
+
spec.name = 'amplitude-experiment'
|
4
|
+
spec.version = AmplitudeExperiment::VERSION
|
5
|
+
spec.authors = ['Amplitude']
|
6
|
+
spec.email = ['sdk@amplitude.com']
|
7
|
+
spec.summary = 'Amplitude Experiment Ruby Server SDK'
|
8
|
+
spec.description = 'Amplitude Experiment Ruby Server SDK'
|
9
|
+
spec.homepage = 'https://github.com/amplitude/experiment-ruby-server'
|
10
|
+
spec.license = 'MIT'
|
11
|
+
spec.platform = Gem::Platform::RUBY
|
12
|
+
spec.required_ruby_version = '>= 2.0'
|
13
|
+
|
14
|
+
spec.files = Dir['README.md',
|
15
|
+
'lib/**/*.rb',
|
16
|
+
'amplitude-experiment.gemspec',
|
17
|
+
'Gemfile',
|
18
|
+
'lib/experiment/local/evaluation/lib/**/*']
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.extra_rdoc_files = ['README.md']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
23
|
+
spec.add_development_dependency 'rdoc', '= 6.4'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.6'
|
25
|
+
spec.add_development_dependency 'rubocop', '= 1.21'
|
26
|
+
spec.add_development_dependency 'simplecov', '~> 0.21'
|
27
|
+
spec.add_development_dependency 'webmock', '~> 3.14'
|
28
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
29
|
+
spec.add_development_dependency 'psych', '~> 4.0'
|
30
|
+
spec.metadata['rubygems_mfa_required'] = 'false'
|
31
|
+
spec.add_runtime_dependency 'ffi', '~> 1.15.5'
|
32
|
+
end
|
data/lib/amplitude-experiment.rb
CHANGED
@@ -8,9 +8,7 @@ require 'experiment/factory'
|
|
8
8
|
require 'experiment/remote/client'
|
9
9
|
require 'experiment/local/client'
|
10
10
|
require 'experiment/local/config'
|
11
|
-
require 'experiment/local/cache'
|
12
11
|
require 'experiment/local/fetcher'
|
13
|
-
require 'experiment/local/poller'
|
14
12
|
|
15
13
|
# Amplitude Experiment Module
|
16
14
|
module AmplitudeExperiment
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'logger'
|
3
|
-
require 'experiment/local/evaluation/evaluation'
|
4
3
|
|
5
4
|
module AmplitudeExperiment
|
6
5
|
# Main client for fetching variant data.
|
@@ -10,9 +9,11 @@ module AmplitudeExperiment
|
|
10
9
|
# @param [String] api_key The environment API Key
|
11
10
|
# @param [LocalEvaluationConfig] config The config object
|
12
11
|
def initialize(api_key, config = nil)
|
12
|
+
require 'experiment/local/evaluation/evaluation'
|
13
13
|
@api_key = api_key
|
14
14
|
@config = config || LocalEvaluationConfig.new
|
15
|
-
@
|
15
|
+
@flags = nil
|
16
|
+
@flags_mutex = Mutex.new
|
16
17
|
@logger = Logger.new($stdout)
|
17
18
|
@logger.level = if @config.debug
|
18
19
|
Logger::DEBUG
|
@@ -20,8 +21,6 @@ module AmplitudeExperiment
|
|
20
21
|
Logger::INFO
|
21
22
|
end
|
22
23
|
@fetcher = LocalEvaluationFetcher.new(api_key, @config.debug, @config.server_url)
|
23
|
-
@poller = FlagConfigPoller.new(@fetcher, @cache, @config.debug, @config.flag_config_polling_interval_millis)
|
24
|
-
|
25
24
|
raise ArgumentError, 'Experiment API key is empty' if @api_key.nil? || @api_key.empty?
|
26
25
|
end
|
27
26
|
|
@@ -32,53 +31,59 @@ module AmplitudeExperiment
|
|
32
31
|
#
|
33
32
|
# @return [Hash[String, Variant]] The evaluated variants
|
34
33
|
def evaluate(user, flag_keys = [])
|
35
|
-
|
36
|
-
|
37
|
-
@cache.cache.each do |_, value|
|
38
|
-
flag_configs.push(value)
|
39
|
-
end
|
40
|
-
else
|
41
|
-
flag_configs = get_flag_configs(flag_keys)
|
34
|
+
flags = @flags_mutex.synchronize do
|
35
|
+
@flags
|
42
36
|
end
|
43
|
-
|
44
|
-
user_str = user.to_json
|
45
|
-
@logger.debug("[Experiment] Evaluate: User: #{user_str} - Rules: #{flag_configs_str}") if @config.debug
|
46
|
-
result_json = evaluation(flag_configs_str, user_str)
|
47
|
-
@logger.debug("[Experiment] evaluate - result: #{variants}") if @config.debug
|
48
|
-
result = JSON.parse(result_json)
|
49
|
-
variants = {}
|
50
|
-
result.each do |key, value|
|
51
|
-
next if value['isDefaultVariant']
|
37
|
+
return {} if flags.nil?
|
52
38
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
39
|
+
user_str = user.to_json
|
40
|
+
@logger.debug("[Experiment] Evaluate: User: #{user_str} - Rules: #{flags}") if @config.debug
|
41
|
+
results_json = evaluation(flags, user_str)
|
42
|
+
@logger.debug("[Experiment] evaluate - result: #{results_json}") if @config.debug
|
43
|
+
parse_results_json(results_json, flag_keys)
|
58
44
|
end
|
59
45
|
|
60
46
|
# Fetch initial flag configurations and start polling for updates.
|
61
47
|
# You must call this function to begin polling for flag config updates.
|
62
48
|
def start
|
63
|
-
@
|
49
|
+
return if @is_running
|
50
|
+
|
51
|
+
@logger.debug('[Experiment] poller - start') if @debug
|
52
|
+
run
|
64
53
|
end
|
65
54
|
|
66
55
|
# Stop polling for flag configurations. Close resource like connection pool with client
|
67
56
|
def stop
|
68
|
-
@
|
57
|
+
@poller_thread&.exit
|
58
|
+
@is_running = false
|
59
|
+
@poller_thread = nil
|
69
60
|
end
|
70
61
|
|
71
62
|
private
|
72
63
|
|
73
|
-
def
|
74
|
-
|
64
|
+
def parse_results_json(results_json, flag_keys)
|
65
|
+
result = JSON.parse(results_json)
|
66
|
+
variants = {}
|
67
|
+
result.each do |key, value|
|
68
|
+
next if value['isDefaultVariant'] || (flag_keys.empty? && flag_keys.include?(key))
|
69
|
+
|
70
|
+
variant_key = value['variant']['key']
|
71
|
+
variant_payload = value['variant']['payload']
|
72
|
+
variants.store(key, Variant.new(variant_key, variant_payload))
|
73
|
+
end
|
74
|
+
variants
|
75
|
+
end
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
def run
|
78
|
+
@is_running = true
|
79
|
+
flags = @fetcher.fetch_v1
|
80
|
+
@flags_mutex.synchronize do
|
81
|
+
@flags = flags
|
82
|
+
end
|
83
|
+
@poller_thread = Thread.new do
|
84
|
+
sleep(@config.flag_config_polling_interval_millis / 1000.to_f)
|
85
|
+
run
|
80
86
|
end
|
81
|
-
flag_configs
|
82
87
|
end
|
83
88
|
end
|
84
89
|
end
|
@@ -12,11 +12,7 @@ module AmplitudeExperiment
|
|
12
12
|
# @return [String] the value of server url
|
13
13
|
attr_accessor :server_url
|
14
14
|
|
15
|
-
# The
|
16
|
-
# @return [Hash] the value of bootstrap
|
17
|
-
attr_accessor :bootstrap
|
18
|
-
|
19
|
-
# The server endpoint from which to request variants.
|
15
|
+
# The polling interval for flag configs.
|
20
16
|
# @return [long] the value of flag config polling interval in million seconds
|
21
17
|
attr_accessor :flag_config_polling_interval_millis
|
22
18
|
|
@@ -25,14 +25,31 @@ module EvaluationInterop
|
|
25
25
|
:DisposeString, callback([:string], :void),
|
26
26
|
:IsInstance, callback([:pointer, :string], :pointer),
|
27
27
|
:createNullableByte, callback([:string], :pointer),
|
28
|
+
:getNonNullValueOfByte, callback([:pointer], :pointer),
|
28
29
|
:createNullableShort, callback([:pointer], :pointer),
|
30
|
+
:getNonNullValueOfShort, callback([:pointer], :pointer),
|
29
31
|
:createNullableInt, callback([:pointer], :pointer),
|
32
|
+
:getNonNullValueOfInt, callback([:pointer], :pointer),
|
30
33
|
:createNullableLong, callback([:pointer], :pointer),
|
34
|
+
:getNonNullValueOfLong, callback([:pointer], :pointer),
|
31
35
|
:createNullableFloat, callback([:pointer], :pointer),
|
36
|
+
:getNonNullValueOfFloat, callback([:pointer], :pointer),
|
32
37
|
:createNullableDouble, callback([:pointer], :pointer),
|
38
|
+
:getNonNullValueOfDouble, callback([:pointer], :pointer),
|
33
39
|
:createNullableChar, callback([:pointer], :pointer),
|
40
|
+
:getNonNullValueOfChar, callback([:pointer], :pointer),
|
34
41
|
:createNullableBoolean, callback([:pointer], :pointer),
|
42
|
+
:getNonNullValueOfBoolean, callback([:pointer], :pointer),
|
35
43
|
:createNullableUnit, callback([], :pointer),
|
44
|
+
:createNullableUByte, callback([:pointer], :pointer),
|
45
|
+
:getNonNullValueOfUByte, callback([:pointer], :pointer),
|
46
|
+
:createNullableUShort, callback([:pointer], :pointer),
|
47
|
+
:getNonNullValueOfUShort, callback([:pointer], :pointer),
|
48
|
+
:createNullableUInt, callback([:pointer], :pointer),
|
49
|
+
:getNonNullValueOfUInt, callback([:pointer], :pointer),
|
50
|
+
:createNullableULong, callback([:pointer], :pointer),
|
51
|
+
:getNonNullValueOfULong, callback([:pointer], :pointer),
|
52
|
+
|
36
53
|
:kotlin, Kotlin
|
37
54
|
end
|
38
55
|
|
Binary file
|
@@ -51,6 +51,18 @@ typedef struct {
|
|
51
51
|
typedef struct {
|
52
52
|
libevaluation_interop_KNativePtr pinned;
|
53
53
|
} libevaluation_interop_kref_kotlin_Unit;
|
54
|
+
typedef struct {
|
55
|
+
libevaluation_interop_KNativePtr pinned;
|
56
|
+
} libevaluation_interop_kref_kotlin_UByte;
|
57
|
+
typedef struct {
|
58
|
+
libevaluation_interop_KNativePtr pinned;
|
59
|
+
} libevaluation_interop_kref_kotlin_UShort;
|
60
|
+
typedef struct {
|
61
|
+
libevaluation_interop_KNativePtr pinned;
|
62
|
+
} libevaluation_interop_kref_kotlin_UInt;
|
63
|
+
typedef struct {
|
64
|
+
libevaluation_interop_KNativePtr pinned;
|
65
|
+
} libevaluation_interop_kref_kotlin_ULong;
|
54
66
|
|
55
67
|
|
56
68
|
typedef struct {
|
@@ -59,14 +71,30 @@ typedef struct {
|
|
59
71
|
void (*DisposeString)(const char* string);
|
60
72
|
libevaluation_interop_KBoolean (*IsInstance)(libevaluation_interop_KNativePtr ref, const libevaluation_interop_KType* type);
|
61
73
|
libevaluation_interop_kref_kotlin_Byte (*createNullableByte)(libevaluation_interop_KByte);
|
74
|
+
libevaluation_interop_KByte (*getNonNullValueOfByte)(libevaluation_interop_kref_kotlin_Byte);
|
62
75
|
libevaluation_interop_kref_kotlin_Short (*createNullableShort)(libevaluation_interop_KShort);
|
76
|
+
libevaluation_interop_KShort (*getNonNullValueOfShort)(libevaluation_interop_kref_kotlin_Short);
|
63
77
|
libevaluation_interop_kref_kotlin_Int (*createNullableInt)(libevaluation_interop_KInt);
|
78
|
+
libevaluation_interop_KInt (*getNonNullValueOfInt)(libevaluation_interop_kref_kotlin_Int);
|
64
79
|
libevaluation_interop_kref_kotlin_Long (*createNullableLong)(libevaluation_interop_KLong);
|
80
|
+
libevaluation_interop_KLong (*getNonNullValueOfLong)(libevaluation_interop_kref_kotlin_Long);
|
65
81
|
libevaluation_interop_kref_kotlin_Float (*createNullableFloat)(libevaluation_interop_KFloat);
|
82
|
+
libevaluation_interop_KFloat (*getNonNullValueOfFloat)(libevaluation_interop_kref_kotlin_Float);
|
66
83
|
libevaluation_interop_kref_kotlin_Double (*createNullableDouble)(libevaluation_interop_KDouble);
|
84
|
+
libevaluation_interop_KDouble (*getNonNullValueOfDouble)(libevaluation_interop_kref_kotlin_Double);
|
67
85
|
libevaluation_interop_kref_kotlin_Char (*createNullableChar)(libevaluation_interop_KChar);
|
86
|
+
libevaluation_interop_KChar (*getNonNullValueOfChar)(libevaluation_interop_kref_kotlin_Char);
|
68
87
|
libevaluation_interop_kref_kotlin_Boolean (*createNullableBoolean)(libevaluation_interop_KBoolean);
|
88
|
+
libevaluation_interop_KBoolean (*getNonNullValueOfBoolean)(libevaluation_interop_kref_kotlin_Boolean);
|
69
89
|
libevaluation_interop_kref_kotlin_Unit (*createNullableUnit)(void);
|
90
|
+
libevaluation_interop_kref_kotlin_UByte (*createNullableUByte)(libevaluation_interop_KUByte);
|
91
|
+
libevaluation_interop_KUByte (*getNonNullValueOfUByte)(libevaluation_interop_kref_kotlin_UByte);
|
92
|
+
libevaluation_interop_kref_kotlin_UShort (*createNullableUShort)(libevaluation_interop_KUShort);
|
93
|
+
libevaluation_interop_KUShort (*getNonNullValueOfUShort)(libevaluation_interop_kref_kotlin_UShort);
|
94
|
+
libevaluation_interop_kref_kotlin_UInt (*createNullableUInt)(libevaluation_interop_KUInt);
|
95
|
+
libevaluation_interop_KUInt (*getNonNullValueOfUInt)(libevaluation_interop_kref_kotlin_UInt);
|
96
|
+
libevaluation_interop_kref_kotlin_ULong (*createNullableULong)(libevaluation_interop_KULong);
|
97
|
+
libevaluation_interop_KULong (*getNonNullValueOfULong)(libevaluation_interop_kref_kotlin_ULong);
|
70
98
|
|
71
99
|
/* User functions. */
|
72
100
|
struct {
|
Binary file
|
@@ -51,6 +51,18 @@ typedef struct {
|
|
51
51
|
typedef struct {
|
52
52
|
libevaluation_interop_KNativePtr pinned;
|
53
53
|
} libevaluation_interop_kref_kotlin_Unit;
|
54
|
+
typedef struct {
|
55
|
+
libevaluation_interop_KNativePtr pinned;
|
56
|
+
} libevaluation_interop_kref_kotlin_UByte;
|
57
|
+
typedef struct {
|
58
|
+
libevaluation_interop_KNativePtr pinned;
|
59
|
+
} libevaluation_interop_kref_kotlin_UShort;
|
60
|
+
typedef struct {
|
61
|
+
libevaluation_interop_KNativePtr pinned;
|
62
|
+
} libevaluation_interop_kref_kotlin_UInt;
|
63
|
+
typedef struct {
|
64
|
+
libevaluation_interop_KNativePtr pinned;
|
65
|
+
} libevaluation_interop_kref_kotlin_ULong;
|
54
66
|
|
55
67
|
|
56
68
|
typedef struct {
|
@@ -59,14 +71,30 @@ typedef struct {
|
|
59
71
|
void (*DisposeString)(const char* string);
|
60
72
|
libevaluation_interop_KBoolean (*IsInstance)(libevaluation_interop_KNativePtr ref, const libevaluation_interop_KType* type);
|
61
73
|
libevaluation_interop_kref_kotlin_Byte (*createNullableByte)(libevaluation_interop_KByte);
|
74
|
+
libevaluation_interop_KByte (*getNonNullValueOfByte)(libevaluation_interop_kref_kotlin_Byte);
|
62
75
|
libevaluation_interop_kref_kotlin_Short (*createNullableShort)(libevaluation_interop_KShort);
|
76
|
+
libevaluation_interop_KShort (*getNonNullValueOfShort)(libevaluation_interop_kref_kotlin_Short);
|
63
77
|
libevaluation_interop_kref_kotlin_Int (*createNullableInt)(libevaluation_interop_KInt);
|
78
|
+
libevaluation_interop_KInt (*getNonNullValueOfInt)(libevaluation_interop_kref_kotlin_Int);
|
64
79
|
libevaluation_interop_kref_kotlin_Long (*createNullableLong)(libevaluation_interop_KLong);
|
80
|
+
libevaluation_interop_KLong (*getNonNullValueOfLong)(libevaluation_interop_kref_kotlin_Long);
|
65
81
|
libevaluation_interop_kref_kotlin_Float (*createNullableFloat)(libevaluation_interop_KFloat);
|
82
|
+
libevaluation_interop_KFloat (*getNonNullValueOfFloat)(libevaluation_interop_kref_kotlin_Float);
|
66
83
|
libevaluation_interop_kref_kotlin_Double (*createNullableDouble)(libevaluation_interop_KDouble);
|
84
|
+
libevaluation_interop_KDouble (*getNonNullValueOfDouble)(libevaluation_interop_kref_kotlin_Double);
|
67
85
|
libevaluation_interop_kref_kotlin_Char (*createNullableChar)(libevaluation_interop_KChar);
|
86
|
+
libevaluation_interop_KChar (*getNonNullValueOfChar)(libevaluation_interop_kref_kotlin_Char);
|
68
87
|
libevaluation_interop_kref_kotlin_Boolean (*createNullableBoolean)(libevaluation_interop_KBoolean);
|
88
|
+
libevaluation_interop_KBoolean (*getNonNullValueOfBoolean)(libevaluation_interop_kref_kotlin_Boolean);
|
69
89
|
libevaluation_interop_kref_kotlin_Unit (*createNullableUnit)(void);
|
90
|
+
libevaluation_interop_kref_kotlin_UByte (*createNullableUByte)(libevaluation_interop_KUByte);
|
91
|
+
libevaluation_interop_KUByte (*getNonNullValueOfUByte)(libevaluation_interop_kref_kotlin_UByte);
|
92
|
+
libevaluation_interop_kref_kotlin_UShort (*createNullableUShort)(libevaluation_interop_KUShort);
|
93
|
+
libevaluation_interop_KUShort (*getNonNullValueOfUShort)(libevaluation_interop_kref_kotlin_UShort);
|
94
|
+
libevaluation_interop_kref_kotlin_UInt (*createNullableUInt)(libevaluation_interop_KUInt);
|
95
|
+
libevaluation_interop_KUInt (*getNonNullValueOfUInt)(libevaluation_interop_kref_kotlin_UInt);
|
96
|
+
libevaluation_interop_kref_kotlin_ULong (*createNullableULong)(libevaluation_interop_KULong);
|
97
|
+
libevaluation_interop_KULong (*getNonNullValueOfULong)(libevaluation_interop_kref_kotlin_ULong);
|
70
98
|
|
71
99
|
/* User functions. */
|
72
100
|
struct {
|
Binary file
|
@@ -51,6 +51,18 @@ typedef struct {
|
|
51
51
|
typedef struct {
|
52
52
|
libevaluation_interop_KNativePtr pinned;
|
53
53
|
} libevaluation_interop_kref_kotlin_Unit;
|
54
|
+
typedef struct {
|
55
|
+
libevaluation_interop_KNativePtr pinned;
|
56
|
+
} libevaluation_interop_kref_kotlin_UByte;
|
57
|
+
typedef struct {
|
58
|
+
libevaluation_interop_KNativePtr pinned;
|
59
|
+
} libevaluation_interop_kref_kotlin_UShort;
|
60
|
+
typedef struct {
|
61
|
+
libevaluation_interop_KNativePtr pinned;
|
62
|
+
} libevaluation_interop_kref_kotlin_UInt;
|
63
|
+
typedef struct {
|
64
|
+
libevaluation_interop_KNativePtr pinned;
|
65
|
+
} libevaluation_interop_kref_kotlin_ULong;
|
54
66
|
|
55
67
|
|
56
68
|
typedef struct {
|
@@ -59,14 +71,30 @@ typedef struct {
|
|
59
71
|
void (*DisposeString)(const char* string);
|
60
72
|
libevaluation_interop_KBoolean (*IsInstance)(libevaluation_interop_KNativePtr ref, const libevaluation_interop_KType* type);
|
61
73
|
libevaluation_interop_kref_kotlin_Byte (*createNullableByte)(libevaluation_interop_KByte);
|
74
|
+
libevaluation_interop_KByte (*getNonNullValueOfByte)(libevaluation_interop_kref_kotlin_Byte);
|
62
75
|
libevaluation_interop_kref_kotlin_Short (*createNullableShort)(libevaluation_interop_KShort);
|
76
|
+
libevaluation_interop_KShort (*getNonNullValueOfShort)(libevaluation_interop_kref_kotlin_Short);
|
63
77
|
libevaluation_interop_kref_kotlin_Int (*createNullableInt)(libevaluation_interop_KInt);
|
78
|
+
libevaluation_interop_KInt (*getNonNullValueOfInt)(libevaluation_interop_kref_kotlin_Int);
|
64
79
|
libevaluation_interop_kref_kotlin_Long (*createNullableLong)(libevaluation_interop_KLong);
|
80
|
+
libevaluation_interop_KLong (*getNonNullValueOfLong)(libevaluation_interop_kref_kotlin_Long);
|
65
81
|
libevaluation_interop_kref_kotlin_Float (*createNullableFloat)(libevaluation_interop_KFloat);
|
82
|
+
libevaluation_interop_KFloat (*getNonNullValueOfFloat)(libevaluation_interop_kref_kotlin_Float);
|
66
83
|
libevaluation_interop_kref_kotlin_Double (*createNullableDouble)(libevaluation_interop_KDouble);
|
84
|
+
libevaluation_interop_KDouble (*getNonNullValueOfDouble)(libevaluation_interop_kref_kotlin_Double);
|
67
85
|
libevaluation_interop_kref_kotlin_Char (*createNullableChar)(libevaluation_interop_KChar);
|
86
|
+
libevaluation_interop_KChar (*getNonNullValueOfChar)(libevaluation_interop_kref_kotlin_Char);
|
68
87
|
libevaluation_interop_kref_kotlin_Boolean (*createNullableBoolean)(libevaluation_interop_KBoolean);
|
88
|
+
libevaluation_interop_KBoolean (*getNonNullValueOfBoolean)(libevaluation_interop_kref_kotlin_Boolean);
|
69
89
|
libevaluation_interop_kref_kotlin_Unit (*createNullableUnit)(void);
|
90
|
+
libevaluation_interop_kref_kotlin_UByte (*createNullableUByte)(libevaluation_interop_KUByte);
|
91
|
+
libevaluation_interop_KUByte (*getNonNullValueOfUByte)(libevaluation_interop_kref_kotlin_UByte);
|
92
|
+
libevaluation_interop_kref_kotlin_UShort (*createNullableUShort)(libevaluation_interop_KUShort);
|
93
|
+
libevaluation_interop_KUShort (*getNonNullValueOfUShort)(libevaluation_interop_kref_kotlin_UShort);
|
94
|
+
libevaluation_interop_kref_kotlin_UInt (*createNullableUInt)(libevaluation_interop_KUInt);
|
95
|
+
libevaluation_interop_KUInt (*getNonNullValueOfUInt)(libevaluation_interop_kref_kotlin_UInt);
|
96
|
+
libevaluation_interop_kref_kotlin_ULong (*createNullableULong)(libevaluation_interop_KULong);
|
97
|
+
libevaluation_interop_KULong (*getNonNullValueOfULong)(libevaluation_interop_kref_kotlin_ULong);
|
70
98
|
|
71
99
|
/* User functions. */
|
72
100
|
struct {
|
Binary file
|
@@ -51,6 +51,18 @@ typedef struct {
|
|
51
51
|
typedef struct {
|
52
52
|
libevaluation_interop_KNativePtr pinned;
|
53
53
|
} libevaluation_interop_kref_kotlin_Unit;
|
54
|
+
typedef struct {
|
55
|
+
libevaluation_interop_KNativePtr pinned;
|
56
|
+
} libevaluation_interop_kref_kotlin_UByte;
|
57
|
+
typedef struct {
|
58
|
+
libevaluation_interop_KNativePtr pinned;
|
59
|
+
} libevaluation_interop_kref_kotlin_UShort;
|
60
|
+
typedef struct {
|
61
|
+
libevaluation_interop_KNativePtr pinned;
|
62
|
+
} libevaluation_interop_kref_kotlin_UInt;
|
63
|
+
typedef struct {
|
64
|
+
libevaluation_interop_KNativePtr pinned;
|
65
|
+
} libevaluation_interop_kref_kotlin_ULong;
|
54
66
|
|
55
67
|
|
56
68
|
typedef struct {
|
@@ -59,14 +71,30 @@ typedef struct {
|
|
59
71
|
void (*DisposeString)(const char* string);
|
60
72
|
libevaluation_interop_KBoolean (*IsInstance)(libevaluation_interop_KNativePtr ref, const libevaluation_interop_KType* type);
|
61
73
|
libevaluation_interop_kref_kotlin_Byte (*createNullableByte)(libevaluation_interop_KByte);
|
74
|
+
libevaluation_interop_KByte (*getNonNullValueOfByte)(libevaluation_interop_kref_kotlin_Byte);
|
62
75
|
libevaluation_interop_kref_kotlin_Short (*createNullableShort)(libevaluation_interop_KShort);
|
76
|
+
libevaluation_interop_KShort (*getNonNullValueOfShort)(libevaluation_interop_kref_kotlin_Short);
|
63
77
|
libevaluation_interop_kref_kotlin_Int (*createNullableInt)(libevaluation_interop_KInt);
|
78
|
+
libevaluation_interop_KInt (*getNonNullValueOfInt)(libevaluation_interop_kref_kotlin_Int);
|
64
79
|
libevaluation_interop_kref_kotlin_Long (*createNullableLong)(libevaluation_interop_KLong);
|
80
|
+
libevaluation_interop_KLong (*getNonNullValueOfLong)(libevaluation_interop_kref_kotlin_Long);
|
65
81
|
libevaluation_interop_kref_kotlin_Float (*createNullableFloat)(libevaluation_interop_KFloat);
|
82
|
+
libevaluation_interop_KFloat (*getNonNullValueOfFloat)(libevaluation_interop_kref_kotlin_Float);
|
66
83
|
libevaluation_interop_kref_kotlin_Double (*createNullableDouble)(libevaluation_interop_KDouble);
|
84
|
+
libevaluation_interop_KDouble (*getNonNullValueOfDouble)(libevaluation_interop_kref_kotlin_Double);
|
67
85
|
libevaluation_interop_kref_kotlin_Char (*createNullableChar)(libevaluation_interop_KChar);
|
86
|
+
libevaluation_interop_KChar (*getNonNullValueOfChar)(libevaluation_interop_kref_kotlin_Char);
|
68
87
|
libevaluation_interop_kref_kotlin_Boolean (*createNullableBoolean)(libevaluation_interop_KBoolean);
|
88
|
+
libevaluation_interop_KBoolean (*getNonNullValueOfBoolean)(libevaluation_interop_kref_kotlin_Boolean);
|
69
89
|
libevaluation_interop_kref_kotlin_Unit (*createNullableUnit)(void);
|
90
|
+
libevaluation_interop_kref_kotlin_UByte (*createNullableUByte)(libevaluation_interop_KUByte);
|
91
|
+
libevaluation_interop_KUByte (*getNonNullValueOfUByte)(libevaluation_interop_kref_kotlin_UByte);
|
92
|
+
libevaluation_interop_kref_kotlin_UShort (*createNullableUShort)(libevaluation_interop_KUShort);
|
93
|
+
libevaluation_interop_KUShort (*getNonNullValueOfUShort)(libevaluation_interop_kref_kotlin_UShort);
|
94
|
+
libevaluation_interop_kref_kotlin_UInt (*createNullableUInt)(libevaluation_interop_KUInt);
|
95
|
+
libevaluation_interop_KUInt (*getNonNullValueOfUInt)(libevaluation_interop_kref_kotlin_UInt);
|
96
|
+
libevaluation_interop_kref_kotlin_ULong (*createNullableULong)(libevaluation_interop_KULong);
|
97
|
+
libevaluation_interop_KULong (*getNonNullValueOfULong)(libevaluation_interop_kref_kotlin_ULong);
|
70
98
|
|
71
99
|
/* User functions. */
|
72
100
|
struct {
|
@@ -7,9 +7,28 @@ module AmplitudeExperiment
|
|
7
7
|
|
8
8
|
def initialize(api_key, debug, server_url = 'https://api.lab.amplitude.com')
|
9
9
|
@api_key = api_key
|
10
|
-
@
|
10
|
+
@server_url = server_url
|
11
11
|
@debug = debug
|
12
|
-
@http = PersistentHttpClient.get(
|
12
|
+
@http = PersistentHttpClient.get(server_url, { read_timeout: FLAG_CONFIG_TIMEOUT })
|
13
|
+
end
|
14
|
+
|
15
|
+
# Fetch local evaluation mode flag configs from the Experiment API server.
|
16
|
+
# These flag configs can be used to perform local evaluation.
|
17
|
+
#
|
18
|
+
# @return [String] The flag configs
|
19
|
+
def fetch_v1
|
20
|
+
# fetch flag_configs
|
21
|
+
headers = {
|
22
|
+
'Authorization' => "Api-Key #{@api_key}",
|
23
|
+
'Content-Type' => 'application/json;charset=utf-8',
|
24
|
+
'X-Amp-Exp-Library' => "experiment-ruby-server/#{VERSION}"
|
25
|
+
}
|
26
|
+
request = Net::HTTP::Get.new("#{@server_url}/sdk/v1/flags", headers)
|
27
|
+
response = @http.request(request)
|
28
|
+
raise "flagConfigs - received error response: #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPOK)
|
29
|
+
|
30
|
+
@logger.debug("[Experiment] Fetch flag configs: #{response.body}") if @debug
|
31
|
+
response.body
|
13
32
|
end
|
14
33
|
|
15
34
|
# Fetch local evaluation mode flag configs from the Experiment API server.
|
@@ -23,7 +42,7 @@ module AmplitudeExperiment
|
|
23
42
|
'Content-Type' => 'application/json;charset=utf-8',
|
24
43
|
'X-Amp-Exp-Library' => "experiment-ruby-server/#{VERSION}"
|
25
44
|
}
|
26
|
-
request = Net::HTTP::Get.new(@
|
45
|
+
request = Net::HTTP::Get.new("#{@server_url}/sdk/rules?eval_mode=local", headers)
|
27
46
|
response = @http.request(request)
|
28
47
|
raise "flagConfigs - received error response: #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPOK)
|
29
48
|
|
data/lib/experiment/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amplitude-experiment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amplitude
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -146,10 +146,10 @@ extra_rdoc_files:
|
|
146
146
|
files:
|
147
147
|
- Gemfile
|
148
148
|
- README.md
|
149
|
+
- amplitude-experiment.gemspec
|
149
150
|
- lib/amplitude-experiment.rb
|
150
151
|
- lib/experiment/cookie.rb
|
151
152
|
- lib/experiment/factory.rb
|
152
|
-
- lib/experiment/local/cache.rb
|
153
153
|
- lib/experiment/local/client.rb
|
154
154
|
- lib/experiment/local/config.rb
|
155
155
|
- lib/experiment/local/evaluation/evaluation.rb
|
@@ -162,7 +162,6 @@ files:
|
|
162
162
|
- lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop.dylib
|
163
163
|
- lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop_api.h
|
164
164
|
- lib/experiment/local/fetcher.rb
|
165
|
-
- lib/experiment/local/poller.rb
|
166
165
|
- lib/experiment/persistent_http_client.rb
|
167
166
|
- lib/experiment/remote/client.rb
|
168
167
|
- lib/experiment/remote/config.rb
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'logger'
|
3
|
-
|
4
|
-
module AmplitudeExperiment
|
5
|
-
# InMemoryFlagConfigCache
|
6
|
-
# The place to store the flag configs fetched from the server
|
7
|
-
class InMemoryFlagConfigCache
|
8
|
-
attr_accessor :cache
|
9
|
-
|
10
|
-
def initialize(flag_configs = {})
|
11
|
-
@semaphore = Mutex.new
|
12
|
-
@cache = flag_configs
|
13
|
-
end
|
14
|
-
|
15
|
-
def get(flag_key)
|
16
|
-
@semaphore.synchronize do
|
17
|
-
@cache.fetch(flag_key, nil)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def caches
|
22
|
-
@semaphore.synchronize do
|
23
|
-
@cache
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def put(flag_key, flag_config)
|
28
|
-
@semaphore.synchronize do
|
29
|
-
@cache.store(flag_key, flag_config.clone)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def put_all(flag_configs)
|
34
|
-
@semaphore.synchronize do
|
35
|
-
flag_configs.each do |key, value|
|
36
|
-
@cache.store(key, value.clone) if value
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def delete(flag_key)
|
42
|
-
@semaphore.synchronize do
|
43
|
-
@cache.delete(flag_key)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def clear
|
48
|
-
@semaphore.synchronize do
|
49
|
-
@cache = {}
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module AmplitudeExperiment
|
2
|
-
# FlagConfigPoller
|
3
|
-
# update the flag_config cache value
|
4
|
-
class FlagConfigPoller
|
5
|
-
FLAG_CONFIG_POLLING_INTERVAL_MILLIS = 30_000
|
6
|
-
|
7
|
-
def initialize(fetcher, cache, debug, poll_interval_millis = FLAG_CONFIG_POLLING_INTERVAL_MILLIS)
|
8
|
-
@fetcher = fetcher
|
9
|
-
@cache = cache
|
10
|
-
@poll_interval_millis = poll_interval_millis
|
11
|
-
@logger = Logger.new($stdout)
|
12
|
-
@debug = debug
|
13
|
-
@poller_thread = nil
|
14
|
-
@is_running = false
|
15
|
-
end
|
16
|
-
|
17
|
-
# Fetch initial flag configurations and start polling for updates.
|
18
|
-
# You must call this function to begin polling for flag config updates.
|
19
|
-
# Calling this function while the poller is already running does nothing.
|
20
|
-
def start
|
21
|
-
return if @is_running
|
22
|
-
|
23
|
-
@logger.debug('[Experiment] poller - start') if @debug
|
24
|
-
run
|
25
|
-
end
|
26
|
-
|
27
|
-
# Stop polling for flag configurations.
|
28
|
-
# Calling this function while the poller is not running will do nothing.
|
29
|
-
def stop
|
30
|
-
@poller_thread&.exit
|
31
|
-
@is_running = false
|
32
|
-
@poller_thread = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def run
|
38
|
-
@is_running = true
|
39
|
-
flag_configs = @fetcher.fetch
|
40
|
-
@cache.clear
|
41
|
-
@cache.put_all(flag_configs)
|
42
|
-
@poller_thread = Thread.new do
|
43
|
-
sleep(@poll_interval_millis / 1000.to_f)
|
44
|
-
run
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|