splitclient-rb 6.3.0 → 8.11.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/.github/CODEOWNERS +1 -0
- data/.github/pull_request_template.md +9 -0
- data/.github/workflows/ci.yml +90 -0
- data/.github/workflows/update-license-year.yml +45 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +46 -3
- data/CHANGES.txt +158 -11
- data/CONTRIBUTORS-GUIDE.md +49 -0
- data/LICENSE +169 -13
- data/NOTICE.txt +5 -0
- data/README.md +67 -27
- data/Rakefile +1 -8
- data/ext/murmurhash/3_x64_128.c +117 -0
- data/ext/murmurhash/murmurhash.c +5 -1
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +4 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +7 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +12 -4
- data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
- data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
- data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
- data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
- data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
- data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
- data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +26 -14
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +9 -14
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +31 -10
- data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +22 -23
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +15 -22
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +6 -31
- data/lib/splitclient-rb/cache/repositories/repository.rb +6 -5
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +46 -6
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +232 -43
- data/lib/splitclient-rb/cache/routers/impression_router.rb +24 -22
- data/lib/splitclient-rb/cache/senders/events_sender.rb +12 -29
- data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
- data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +27 -13
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +11 -25
- data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
- data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
- data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
- data/lib/splitclient-rb/clients/split_client.rb +385 -138
- data/lib/splitclient-rb/constants.rb +16 -0
- data/lib/splitclient-rb/engine/api/client.rb +38 -43
- data/lib/splitclient-rb/engine/api/events.rb +19 -11
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +49 -14
- data/lib/splitclient-rb/engine/api/segments.rb +31 -24
- data/lib/splitclient-rb/engine/api/splits.rb +108 -33
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
- data/lib/splitclient-rb/engine/auth_api_client.rb +96 -0
- data/lib/splitclient-rb/engine/back_off.rb +26 -0
- data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
- data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
- data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
- data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
- data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
- data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
- data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
- data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
- data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
- data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +10 -8
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +2 -6
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +1 -5
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +6 -5
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +1 -5
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/matcher.rb +22 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +2 -6
- data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
- data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
- data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
- data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
- data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
- data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
- data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
- data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
- data/lib/splitclient-rb/engine/models/label.rb +3 -0
- data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +14 -0
- data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
- data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +81 -20
- data/lib/splitclient-rb/engine/parser/evaluator.rb +40 -51
- data/lib/splitclient-rb/engine/push_manager.rb +66 -0
- data/lib/splitclient-rb/engine/status_manager.rb +39 -0
- data/lib/splitclient-rb/engine/sync_manager.rb +180 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
- data/lib/splitclient-rb/exceptions.rb +20 -1
- data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
- data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
- data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
- data/lib/splitclient-rb/helpers/util.rb +26 -0
- data/lib/splitclient-rb/managers/split_manager.rb +58 -20
- data/lib/splitclient-rb/spec.rb +9 -0
- data/lib/splitclient-rb/split_config.rb +336 -54
- data/lib/splitclient-rb/split_factory.rb +219 -33
- data/lib/splitclient-rb/split_factory_builder.rb +1 -22
- data/lib/splitclient-rb/split_factory_registry.rb +63 -0
- data/lib/splitclient-rb/split_logger.rb +9 -10
- data/lib/splitclient-rb/sse/event_source/client.rb +263 -0
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
- data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
- data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
- data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
- data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +149 -0
- data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
- data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
- data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
- data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
- data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
- data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
- data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
- data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
- data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
- data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
- data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
- data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
- data/lib/splitclient-rb/utilitites.rb +8 -0
- data/lib/splitclient-rb/validators.rb +142 -38
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +101 -16
- data/sonar-project.properties +6 -0
- data/splitclient-rb.gemspec +28 -23
- metadata +262 -82
- data/.travis.yml +0 -11
- data/Appraisals +0 -10
- data/Detailed-README.md +0 -588
- data/NEWS +0 -141
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -127
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -96
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -21
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -56
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +0 -46
- data/lib/splitclient-rb/cache/stores/segment_store.rb +0 -81
- data/lib/splitclient-rb/cache/stores/split_store.rb +0 -102
- data/lib/splitclient-rb/clients/localhost_split_client.rb +0 -183
- data/lib/splitclient-rb/engine/api/faraday_adapter/patched_net_http_persistent.rb +0 -46
- data/lib/splitclient-rb/engine/api/metrics.rb +0 -60
- data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -81
- data/lib/splitclient-rb/localhost_split_factory.rb +0 -13
- data/lib/splitclient-rb/localhost_utils.rb +0 -59
- data/lib/splitclient-rb/managers/localhost_split_manager.rb +0 -60
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Events
|
|
6
|
+
class EventsTask
|
|
7
|
+
attr_accessor :running
|
|
8
|
+
|
|
9
|
+
def initialize(notify_internal_events, internal_events_queue, config)
|
|
10
|
+
@notify_internal_events = notify_internal_events
|
|
11
|
+
@internal_events_queue = internal_events_queue
|
|
12
|
+
@config = config
|
|
13
|
+
@running = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def start
|
|
17
|
+
return if @running
|
|
18
|
+
|
|
19
|
+
@config.logger.info('Starting Internal Events Task.')
|
|
20
|
+
@running = true
|
|
21
|
+
@config.threads[:internal_events_task] = Thread.new do
|
|
22
|
+
worker_thread
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def stop
|
|
27
|
+
return unless @running
|
|
28
|
+
|
|
29
|
+
@config.logger.info('Stopping Internal Events Task.')
|
|
30
|
+
@running = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def worker_thread
|
|
36
|
+
while (event = @internal_events_queue.pop)
|
|
37
|
+
break unless @running
|
|
38
|
+
|
|
39
|
+
@config.logger.debug("Processing sdk internal event: #{event.internal_event}") if @config.debug_enabled
|
|
40
|
+
begin
|
|
41
|
+
@notify_internal_events.call(event.internal_event, event.metadata)
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
@config.log_found_exception(__method__.to_s, e)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
class FallbackTreatmentCalculator
|
|
6
|
+
attr_accessor :fallback_treatments_configuration, :label_prefix
|
|
7
|
+
|
|
8
|
+
def initialize(fallback_treatment_configuration)
|
|
9
|
+
@label_prefix = 'fallback - '
|
|
10
|
+
@fallback_treatments_configuration = fallback_treatment_configuration
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resolve(flag_name, label)
|
|
14
|
+
default_fallback_treatment = Engine::Models::FallbackTreatment.new(
|
|
15
|
+
Engine::Models::Treatment::CONTROL,
|
|
16
|
+
nil,
|
|
17
|
+
label
|
|
18
|
+
)
|
|
19
|
+
return default_fallback_treatment if @fallback_treatments_configuration.nil?
|
|
20
|
+
|
|
21
|
+
if !@fallback_treatments_configuration.by_flag_fallback_treatment.nil? \
|
|
22
|
+
&& !@fallback_treatments_configuration.by_flag_fallback_treatment.fetch(flag_name, nil).nil?
|
|
23
|
+
return copy_with_label(
|
|
24
|
+
@fallback_treatments_configuration.by_flag_fallback_treatment[flag_name],
|
|
25
|
+
resolve_label(label)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
return copy_with_label(@fallback_treatments_configuration.global_fallback_treatment, resolve_label(label)) \
|
|
30
|
+
unless @fallback_treatments_configuration.global_fallback_treatment.nil?
|
|
31
|
+
|
|
32
|
+
default_fallback_treatment
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def resolve_label(label)
|
|
38
|
+
return nil if label.nil?
|
|
39
|
+
|
|
40
|
+
@label_prefix + label
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def copy_with_label(fallback_treatment, label)
|
|
44
|
+
Engine::Models::FallbackTreatment.new(fallback_treatment.treatment, fallback_treatment.config, label)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Impressions
|
|
6
|
+
class UniqueKeysTracker
|
|
7
|
+
INTERVAL_TO_CLEAR_LONG_TERM_CACHE = 86_400 # 24 hours
|
|
8
|
+
|
|
9
|
+
def initialize(config,
|
|
10
|
+
filter_adapter,
|
|
11
|
+
sender_adapter,
|
|
12
|
+
cache)
|
|
13
|
+
@config = config
|
|
14
|
+
@filter_adapter = filter_adapter
|
|
15
|
+
@sender_adapter = sender_adapter
|
|
16
|
+
@cache = cache
|
|
17
|
+
@max_bulk_size = config.unique_keys_bulk_size
|
|
18
|
+
@semaphore = Mutex.new
|
|
19
|
+
@keys_size = 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def call
|
|
23
|
+
@config.threads[:unique_keys_sender] = Thread.new { send_bulk_data_thread }
|
|
24
|
+
@config.threads[:clear_filter] = Thread.new { clear_filter_thread }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def track(feature_name, key)
|
|
28
|
+
return false if @filter_adapter.contains?(feature_name, key)
|
|
29
|
+
|
|
30
|
+
@filter_adapter.add(feature_name, key)
|
|
31
|
+
|
|
32
|
+
add_or_update(feature_name, key)
|
|
33
|
+
@keys_size += 1
|
|
34
|
+
|
|
35
|
+
send_bulk_data if @keys_size >= @max_bulk_size
|
|
36
|
+
|
|
37
|
+
true
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
@config.log_found_exception(__method__.to_s, e)
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def send_bulk_data_thread
|
|
46
|
+
@config.logger.info('Starting Unique Keys Tracker.') if @config.debug_enabled
|
|
47
|
+
loop do
|
|
48
|
+
sleep(@config.unique_keys_refresh_rate)
|
|
49
|
+
send_bulk_data
|
|
50
|
+
end
|
|
51
|
+
rescue SplitIoClient::SDKShutdownException
|
|
52
|
+
send_bulk_data
|
|
53
|
+
@config.logger.info('Posting unique keys due to shutdown')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def clear_filter_thread
|
|
57
|
+
loop do
|
|
58
|
+
sleep(INTERVAL_TO_CLEAR_LONG_TERM_CACHE)
|
|
59
|
+
@config.logger.debug('Starting task to clean the filter cache.') if @config.debug_enabled
|
|
60
|
+
@filter_adapter.clear
|
|
61
|
+
end
|
|
62
|
+
rescue SplitIoClient::SDKShutdownException
|
|
63
|
+
@filter_adapter.clear
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def add_or_update(feature_name, key)
|
|
67
|
+
if @cache[feature_name].nil?
|
|
68
|
+
@cache[feature_name] = Set.new([key])
|
|
69
|
+
else
|
|
70
|
+
@cache[feature_name].add(key)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def clear_cache
|
|
75
|
+
uniques = @cache.clone
|
|
76
|
+
keys_size = @keys_size
|
|
77
|
+
@cache.clear
|
|
78
|
+
@keys_size = 0
|
|
79
|
+
|
|
80
|
+
[uniques, keys_size]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def send_bulk_data
|
|
84
|
+
@semaphore.synchronize do
|
|
85
|
+
return if @cache.empty?
|
|
86
|
+
|
|
87
|
+
uniques, keys_size = clear_cache
|
|
88
|
+
if keys_size <= @max_bulk_size
|
|
89
|
+
@sender_adapter.record_uniques_key(uniques)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
bulks = flatten_bulks(uniques)
|
|
94
|
+
bulks_to_post = group_bulks_by_max_size(bulks)
|
|
95
|
+
@sender_adapter.record_uniques_key(bulks_to_post)
|
|
96
|
+
end
|
|
97
|
+
rescue StandardError => e
|
|
98
|
+
@config.log_found_exception(__method__.to_s, e)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def group_bulks_by_max_size(bulks)
|
|
102
|
+
current_size = 0
|
|
103
|
+
bulks_to_post = Concurrent::Hash.new
|
|
104
|
+
bulks.each do |bulk|
|
|
105
|
+
key, value = bulk.first
|
|
106
|
+
if (value.size + current_size) > @max_bulk_size
|
|
107
|
+
@sender_adapter.record_uniques_key(bulks_to_post)
|
|
108
|
+
bulks_to_post = Concurrent::Hash.new
|
|
109
|
+
current_size = 0
|
|
110
|
+
end
|
|
111
|
+
bulks_to_post[key] = value
|
|
112
|
+
current_size += value.size
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
bulks_to_post
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def flatten_bulks(uniques)
|
|
119
|
+
bulks = []
|
|
120
|
+
uniques.each_key do |unique_key|
|
|
121
|
+
bulks += check_keys_and_split_to_bulks(uniques[unique_key], unique_key)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
bulks
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def check_keys_and_split_to_bulks(value, key)
|
|
128
|
+
unique_updated = []
|
|
129
|
+
if value.size > @max_bulk_size
|
|
130
|
+
sub_bulks = SplitIoClient::Utilities.split_bulk_to_send(value, @max_bulk_size)
|
|
131
|
+
sub_bulks.each do |sub_bulk|
|
|
132
|
+
unique_updated << { key => sub_bulk.to_set }
|
|
133
|
+
end
|
|
134
|
+
return unique_updated
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
unique_updated << { key => value }
|
|
138
|
+
|
|
139
|
+
unique_updated
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -6,7 +6,9 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute_hash)
|
|
9
|
+
def initialize(attribute_hash, logger, validator)
|
|
10
|
+
super(logger)
|
|
11
|
+
@validator = validator
|
|
10
12
|
@attribute = attribute_hash[:attribute]
|
|
11
13
|
@data_type = attribute_hash[:data_type]
|
|
12
14
|
@start_value = formatted_value(attribute_hash[:start_value], true)
|
|
@@ -14,16 +16,16 @@ module SplitIoClient
|
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def match?(args)
|
|
17
|
-
|
|
19
|
+
@logger.log_if_debug('[BetweenMatcher] evaluating value and attributes.')
|
|
18
20
|
|
|
19
|
-
return false unless
|
|
21
|
+
return false unless @validator.valid_matcher_arguments(args)
|
|
20
22
|
|
|
21
23
|
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
|
22
|
-
|
|
24
|
+
@logger.log_if_debug("[BetweenMatcher] Value from parameters: #{value}.")
|
|
23
25
|
return false unless value.is_a?(Integer)
|
|
24
26
|
|
|
25
27
|
matches = (@start_value..@end_value).cover? value
|
|
26
|
-
|
|
28
|
+
@logger.log_if_debug("[BetweenMatcher] is #{value} between #{@start_value} and #{@end_value} -> #{matches} .")
|
|
27
29
|
matches
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
class BetweenSemverMatcher < Matcher
|
|
5
|
+
MATCHER_TYPE = 'BETWEEN_SEMVER'
|
|
6
|
+
|
|
7
|
+
attr_reader :attribute
|
|
8
|
+
|
|
9
|
+
def initialize(attribute, start_value, end_value, logger, validator)
|
|
10
|
+
super(logger)
|
|
11
|
+
@validator = validator
|
|
12
|
+
@attribute = attribute
|
|
13
|
+
@semver_start = SplitIoClient::Semver.build(start_value, logger)
|
|
14
|
+
@semver_end = SplitIoClient::Semver.build(end_value, logger)
|
|
15
|
+
@logger = logger
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def match?(args)
|
|
19
|
+
return false unless verify_semver_arg?(args, 'BetweenSemverMatcher')
|
|
20
|
+
|
|
21
|
+
value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
|
|
22
|
+
if value_to_match.nil? || @semver_start.nil? || @semver_end.nil?
|
|
23
|
+
@logger.error('betweenStringMatcherData is required for BETWEEN_SEMVER matcher type')
|
|
24
|
+
return false
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
matches = ([0, -1].include?(@semver_start.compare(value_to_match)) &&
|
|
28
|
+
[0, 1].include?(@semver_end.compare(value_to_match)))
|
|
29
|
+
@logger.debug("[BetweenMatcher] #{value_to_match} matches -> #{matches}")
|
|
30
|
+
matches
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -7,7 +7,8 @@ module SplitIoClient
|
|
|
7
7
|
class CombiningMatcher < Matcher
|
|
8
8
|
MATCHER_TYPE = 'COMBINING_MATCHER'
|
|
9
9
|
|
|
10
|
-
def initialize(combiner = '', matchers = [])
|
|
10
|
+
def initialize(logger, combiner = '', matchers = [])
|
|
11
|
+
super(logger)
|
|
11
12
|
@combiner = combiner
|
|
12
13
|
@matchers = matchers
|
|
13
14
|
end
|
|
@@ -23,17 +24,17 @@ module SplitIoClient
|
|
|
23
24
|
# @return [boolean]
|
|
24
25
|
def match?(args)
|
|
25
26
|
if @matchers.empty?
|
|
26
|
-
|
|
27
|
+
@logger.log_if_debug('[CombiningMatcher] Matchers Empty')
|
|
27
28
|
return false
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
case @combiner
|
|
31
32
|
when Combiners::AND
|
|
32
33
|
matches = eval_and(args)
|
|
33
|
-
|
|
34
|
+
@logger.log_if_debug("[CombiningMatcher] Combiner AND result -> #{matches}")
|
|
34
35
|
return matches
|
|
35
36
|
else
|
|
36
|
-
|
|
37
|
+
@logger.log_if_debug("[CombiningMatcher] Invalid Combiner Type - Combiner -> #{@combiner}")
|
|
37
38
|
@logger.error('Invalid combiner type')
|
|
38
39
|
end
|
|
39
40
|
|
|
@@ -51,12 +52,13 @@ module SplitIoClient
|
|
|
51
52
|
# @return [boolean] match value for combiner delegates
|
|
52
53
|
def eval_and(args)
|
|
53
54
|
# Convert all keys to symbols
|
|
54
|
-
if args && args[:attributes]
|
|
55
|
-
|
|
56
|
-
end
|
|
55
|
+
args[:attributes] = args[:attributes].each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v } if args && args[:attributes]
|
|
56
|
+
|
|
57
57
|
@matchers.all? do |matcher|
|
|
58
58
|
if match_with_key?(matcher)
|
|
59
|
-
|
|
59
|
+
key = args[:value]
|
|
60
|
+
key = args[:matching_key] unless args[:matching_key].nil?
|
|
61
|
+
matcher.match?(value: key)
|
|
60
62
|
else
|
|
61
63
|
matcher.match?(args)
|
|
62
64
|
end
|
|
@@ -6,18 +6,14 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, remote_array)
|
|
10
|
-
super(attribute, remote_array)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
9
|
def match?(args)
|
|
14
10
|
if @remote_set.empty?
|
|
15
|
-
|
|
11
|
+
@logger.log_if_debug('[ContainsAllMatcher] Remote Set Empty')
|
|
16
12
|
return false
|
|
17
13
|
end
|
|
18
14
|
|
|
19
15
|
matches = @remote_set.subset? local_set(args[:attributes], @attribute)
|
|
20
|
-
|
|
16
|
+
@logger.log_if_debug("[ContainsAllMatcher] Remote Set #{@remote_set} contains #{@attribute} -> #{matches}")
|
|
21
17
|
matches
|
|
22
18
|
end
|
|
23
19
|
end
|
|
@@ -6,13 +6,9 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, remote_array)
|
|
10
|
-
super(attribute, remote_array)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
9
|
def match?(args)
|
|
14
10
|
matches = local_set(args[:attributes], @attribute).intersect? @remote_set
|
|
15
|
-
|
|
11
|
+
@logger.log_if_debug("[ContainsAnyMatcher] Remote Set #{@remote_set} contains any \
|
|
16
12
|
#{@attribute} or #{args[:attributes]}-> #{matches}")
|
|
17
13
|
matches
|
|
18
14
|
end
|
|
@@ -6,23 +6,25 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, substr_list)
|
|
9
|
+
def initialize(attribute, substr_list, logger, validator)
|
|
10
10
|
@attribute = attribute
|
|
11
11
|
@substr_list = substr_list
|
|
12
|
+
@logger = logger
|
|
13
|
+
@validator = validator
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def match?(args)
|
|
15
|
-
|
|
17
|
+
@logger.log_if_debug('[ContainsMatcher] evaluating value and attributes.')
|
|
16
18
|
|
|
17
|
-
return false unless
|
|
19
|
+
return false unless @validator.valid_matcher_arguments(args)
|
|
18
20
|
|
|
19
21
|
value = get_value(args)
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
@logger.log_if_debug("[ContainsMatcher] Value from parameters: #{value}.")
|
|
22
24
|
return false if @substr_list.empty?
|
|
23
25
|
|
|
24
26
|
matches = @substr_list.any? { |substr| value.to_s.include? substr }
|
|
25
|
-
|
|
27
|
+
@logger.log_if_debug("[ContainsMatcher] #{@value} contains any of #{@substr_list} -> #{matches} .")
|
|
26
28
|
matches
|
|
27
29
|
end
|
|
28
30
|
|
|
@@ -4,17 +4,18 @@ module SplitIoClient
|
|
|
4
4
|
class DependencyMatcher
|
|
5
5
|
MATCHER_TYPE = 'IN_SPLIT_TREATMENT'
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@
|
|
7
|
+
def initialize(feature_flag, treatments, logger)
|
|
8
|
+
@feature_flag = feature_flag
|
|
9
9
|
@treatments = treatments
|
|
10
|
+
@logger = logger
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def match?(args)
|
|
13
14
|
keys = { matching_key: args[:matching_key], bucketing_key: args[:bucketing_key] }
|
|
14
|
-
evaluate = args[:evaluator].
|
|
15
|
+
evaluate = args[:evaluator].evaluate_feature_flag(keys, @feature_flag, args[:attributes])
|
|
15
16
|
matches = @treatments.include?(evaluate[:treatment])
|
|
16
|
-
|
|
17
|
-
with label #{evaluate[:label]}. #{@
|
|
17
|
+
@logger.log_if_debug("[dependencyMatcher] Parent feature flag #{@feature_flag} evaluated to #{evaluate[:treatment]} \
|
|
18
|
+
with label #{evaluate[:label]}. #{@feature_flag} evaluated treatment is part of [#{@treatments}] ? #{matches}.")
|
|
18
19
|
matches
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -6,23 +6,24 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, suffix_list)
|
|
9
|
+
def initialize(attribute, suffix_list, logger)
|
|
10
10
|
@attribute = attribute
|
|
11
11
|
@suffix_list = suffix_list
|
|
12
|
+
@logger = logger
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def match?(args)
|
|
15
16
|
value = get_value(args)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
@logger.log_if_debug("[EndsWithMatcher] Value from parameters: #{value}.")
|
|
18
19
|
|
|
19
20
|
if @suffix_list.empty?
|
|
20
|
-
|
|
21
|
+
@logger.log_if_debug('[EndsWithMatcher] Sufix List empty.')
|
|
21
22
|
return false
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
matches = @suffix_list.any? { |suffix| value.to_s.end_with? suffix }
|
|
25
|
-
|
|
26
|
+
@logger.log_if_debug("[EndsWithMatcher] #{value} ends with any #{@suffix_list}")
|
|
26
27
|
matches
|
|
27
28
|
end
|
|
28
29
|
|
|
@@ -6,9 +6,10 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, boolean)
|
|
9
|
+
def initialize(attribute, boolean, logger)
|
|
10
10
|
@attribute = attribute
|
|
11
11
|
@boolean = boolean
|
|
12
|
+
@logger = logger
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def match?(args)
|
|
@@ -17,7 +18,7 @@ module SplitIoClient
|
|
|
17
18
|
value = true if value.to_s.casecmp('true').zero?
|
|
18
19
|
|
|
19
20
|
matches = value == @boolean
|
|
20
|
-
|
|
21
|
+
@logger.log_if_debug("[EqualToBooleanMatcher] #{value} equals to #{@boolean} -> #{matches}")
|
|
21
22
|
matches
|
|
22
23
|
end
|
|
23
24
|
|
|
@@ -6,21 +6,23 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute_hash)
|
|
9
|
+
def initialize(attribute_hash, logger, validator)
|
|
10
|
+
super(logger)
|
|
11
|
+
@validator = validator
|
|
10
12
|
@attribute = attribute_hash[:attribute]
|
|
11
13
|
@data_type = attribute_hash[:data_type]
|
|
12
14
|
@value = formatted_value(attribute_hash[:value], true)
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def match?(args)
|
|
16
|
-
|
|
18
|
+
@logger.log_if_debug('[EqualsToMatcher] evaluating value and attributes.')
|
|
17
19
|
|
|
18
|
-
return false unless
|
|
20
|
+
return false unless @validator.valid_matcher_arguments(args)
|
|
19
21
|
|
|
20
22
|
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
|
21
23
|
|
|
22
24
|
matches = value.is_a?(Integer) ? (value == @value) : false
|
|
23
|
-
|
|
25
|
+
@logger.log_if_debug("[EqualsToMatcher] #{value} equals to #{@value} -> #{matches}")
|
|
24
26
|
matches
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
class EqualToSemverMatcher < Matcher
|
|
5
|
+
MATCHER_TYPE = 'EQUAL_TO_SEMVER'
|
|
6
|
+
|
|
7
|
+
attr_reader :attribute
|
|
8
|
+
|
|
9
|
+
def initialize(attribute, string_value, logger, validator)
|
|
10
|
+
super(logger)
|
|
11
|
+
@validator = validator
|
|
12
|
+
@attribute = attribute
|
|
13
|
+
@semver = SplitIoClient::Semver.build(string_value, logger)
|
|
14
|
+
@logger = logger
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def match?(args)
|
|
18
|
+
return false unless verify_semver_arg?(args, 'EqualsToSemverMatcher')
|
|
19
|
+
|
|
20
|
+
value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
|
|
21
|
+
return false unless check_semver_value_to_match(value_to_match, MATCHER_TYPE)
|
|
22
|
+
|
|
23
|
+
matches = (@semver.version == value_to_match.version)
|
|
24
|
+
@logger.debug("[EqualsToSemverMatcher] #{value_to_match} matches -> #{matches}")
|
|
25
|
+
matches
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -6,14 +6,10 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute, remote_array)
|
|
10
|
-
super(attribute, remote_array)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
9
|
def match?(args)
|
|
14
10
|
set = local_set(args[:attributes], @attribute)
|
|
15
11
|
matches = set == @remote_set
|
|
16
|
-
|
|
12
|
+
@logger.log_if_debug("[EqualsToSetMatcher] #{set} equals to #{@remote_set} -> #{matches}")
|
|
17
13
|
matches
|
|
18
14
|
end
|
|
19
15
|
end
|
|
@@ -6,21 +6,23 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :attribute
|
|
8
8
|
|
|
9
|
-
def initialize(attribute_hash)
|
|
9
|
+
def initialize(attribute_hash, logger, validator)
|
|
10
|
+
super(logger)
|
|
11
|
+
@validator = validator
|
|
10
12
|
@attribute = attribute_hash[:attribute]
|
|
11
13
|
@data_type = attribute_hash[:data_type]
|
|
12
14
|
@value = formatted_value(attribute_hash[:value], true)
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def match?(args)
|
|
16
|
-
|
|
18
|
+
@logger.log_if_debug('[GreaterThanOrEqualToMatcher] evaluating value and attributes.')
|
|
17
19
|
|
|
18
|
-
return false unless
|
|
20
|
+
return false unless @validator.valid_matcher_arguments(args)
|
|
19
21
|
|
|
20
22
|
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
|
21
23
|
|
|
22
24
|
matches = value.is_a?(Integer) ? (value >= @value) : false
|
|
23
|
-
|
|
25
|
+
@logger.log_if_debug("[GreaterThanOrEqualToMatcher] #{value} greater than or equal to #{@value} -> #{matches}")
|
|
24
26
|
matches
|
|
25
27
|
end
|
|
26
28
|
|