splitclient-rb 1.0.2.wip → 8.11.1.pre.rc1-java
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 +5 -5
- 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 +20 -0
- data/.rubocop.yml +76 -0
- data/.simplecov +1 -0
- data/CHANGES.txt +361 -2
- data/CONTRIBUTORS-GUIDE.md +49 -0
- data/Gemfile +2 -0
- data/LICENSE +3 -36
- data/NOTICE.txt +5 -0
- data/README.md +59 -127
- data/Rakefile +27 -3
- data/ext/murmurhash/MurmurHash3.java +302 -0
- data/gemfiles/faraday_after_0.13.gemfile +7 -0
- data/gemfiles/faraday_before_0.13.gemfile +8 -0
- data/lib/murmurhash/base.rb +58 -0
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/murmurhash/murmurhash_mri.rb +3 -0
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +130 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +137 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +53 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +178 -0
- 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 +45 -0
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +35 -0
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +61 -0
- 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 +56 -0
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +57 -0
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +23 -0
- data/lib/splitclient-rb/cache/repositories/repository.rb +24 -0
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +124 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +296 -0
- data/lib/splitclient-rb/cache/routers/impression_router.rb +60 -0
- data/lib/splitclient-rb/cache/senders/events_sender.rb +42 -0
- 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 +95 -0
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +52 -0
- 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 +530 -0
- data/lib/splitclient-rb/constants.rb +16 -0
- data/lib/splitclient-rb/engine/api/client.rb +87 -0
- data/lib/splitclient-rb/engine/api/events.rb +57 -0
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +58 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +79 -0
- data/lib/splitclient-rb/engine/api/segments.rb +78 -0
- data/lib/splitclient-rb/engine/api/splits.rb +139 -0
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
- data/lib/splitclient-rb/engine/auth_api_client.rb +100 -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-engine → splitclient-rb/engine}/evaluator/splitter.rb +35 -22
- 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-engine → splitclient-rb/engine}/matchers/all_keys_matcher.rb +10 -21
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +47 -0
- data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/combiners.rb +4 -6
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +80 -0
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +16 -0
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +43 -0
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +42 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +37 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +44 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +16 -0
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +43 -0
- 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 +43 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/matcher.rb +52 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +29 -0
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +47 -0
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +22 -0
- 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 +27 -0
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +40 -0
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +66 -0
- 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 +10 -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 +16 -0
- data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/split.rb +17 -0
- data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
- data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
- data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +271 -0
- data/lib/splitclient-rb/engine/parser/evaluator.rb +112 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/parser/partition.rb +2 -4
- 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 +183 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
- data/lib/splitclient-rb/exceptions.rb +26 -0
- 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 +121 -0
- data/lib/splitclient-rb/spec.rb +9 -0
- data/lib/splitclient-rb/split_config.rb +591 -47
- data/lib/splitclient-rb/split_factory.rb +284 -0
- data/lib/splitclient-rb/split_factory_builder.rb +7 -0
- data/lib/splitclient-rb/split_factory_registry.rb +63 -0
- data/lib/splitclient-rb/split_logger.rb +23 -0
- data/lib/splitclient-rb/sse/event_source/client.rb +264 -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 +153 -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 +49 -0
- data/lib/splitclient-rb/validators.rb +361 -0
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +177 -25
- data/sonar-project.properties +6 -0
- data/splitclient-rb.gemspec +53 -26
- data/tasks/benchmark_get_treatment.rake +31 -17
- data/tasks/irb.rake +6 -0
- metadata +411 -86
- data/NEWS +0 -9
- data/lib/splitclient-cache/local_store.rb +0 -45
- data/lib/splitclient-engine/impressions/impressions.rb +0 -79
- data/lib/splitclient-engine/matchers/between_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/combining_matcher.rb +0 -94
- data/lib/splitclient-engine/matchers/equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/greater_than_or_equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/less_than_or_equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/negation_matcher.rb +0 -54
- data/lib/splitclient-engine/matchers/user_defined_segment_matcher.rb +0 -61
- data/lib/splitclient-engine/matchers/whitelist_matcher.rb +0 -64
- data/lib/splitclient-engine/metrics/binary_search_latency_tracker.rb +0 -122
- data/lib/splitclient-engine/metrics/metrics.rb +0 -158
- data/lib/splitclient-engine/parser/condition.rb +0 -143
- data/lib/splitclient-engine/parser/segment.rb +0 -84
- data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
- data/lib/splitclient-engine/parser/split.rb +0 -68
- data/lib/splitclient-engine/parser/split_adapter.rb +0 -433
- data/lib/splitclient-engine/parser/split_parser.rb +0 -139
- data/lib/splitclient-engine/partitions/treatments.rb +0 -40
- data/lib/splitclient-rb/split_client.rb +0 -156
- data/lib/splitclient-rb_utilitites.rb +0 -26
- data/tasks/console.rake +0 -4
- data/tasks/rspec.rake +0 -3
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
class SplitFactory
|
|
5
|
+
ROOT_PROCESS_ID = Process.pid
|
|
6
|
+
SINGLETON_WARN = 'We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'
|
|
7
|
+
LOCALHOST_API_KEY = 'localhost'
|
|
8
|
+
|
|
9
|
+
include SplitIoClient::Cache::Repositories
|
|
10
|
+
include SplitIoClient::Cache::Stores
|
|
11
|
+
include SplitIoClient::Cache::Senders
|
|
12
|
+
include SplitIoClient::Cache::Fetchers
|
|
13
|
+
|
|
14
|
+
attr_reader :adapter, :client, :manager, :config
|
|
15
|
+
|
|
16
|
+
def initialize(api_key, config_hash = {})
|
|
17
|
+
at_exit do
|
|
18
|
+
unless ENV['SPLITCLIENT_ENV'] == 'test'
|
|
19
|
+
if (Process.pid == ROOT_PROCESS_ID)
|
|
20
|
+
@config.logger.info('Split SDK shutdown started...')
|
|
21
|
+
@client.destroy if @client
|
|
22
|
+
stop!
|
|
23
|
+
@config.logger.info('Split SDK shutdown complete')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@api_key = api_key
|
|
29
|
+
|
|
30
|
+
store_flag_sets = config_hash.key?(:flag_sets_filter) ? config_hash[:flag_sets_filter] : []
|
|
31
|
+
store_flag_sets = [] if !store_flag_sets.is_a?(Array)
|
|
32
|
+
flag_sets_count = 0
|
|
33
|
+
flag_sets_invalid = 0
|
|
34
|
+
|
|
35
|
+
@config = SplitConfig.new(config_hash.merge(localhost_mode: @api_key == LOCALHOST_API_KEY ))
|
|
36
|
+
|
|
37
|
+
if config_hash.key?(:flag_sets_filter)
|
|
38
|
+
flag_sets_count = store_flag_sets.length()
|
|
39
|
+
flag_sets_invalid = flag_sets_count - @config.flag_sets_filter.length()
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
raise 'Invalid SDK mode' unless valid_mode
|
|
43
|
+
|
|
44
|
+
validate_api_key
|
|
45
|
+
|
|
46
|
+
register_factory
|
|
47
|
+
|
|
48
|
+
build_events_manager
|
|
49
|
+
build_telemetry_components
|
|
50
|
+
build_flag_sets_filter
|
|
51
|
+
build_repositories
|
|
52
|
+
build_telemetry_synchronizer(flag_sets_count, flag_sets_invalid)
|
|
53
|
+
build_impressions_sender_adapter
|
|
54
|
+
build_unique_keys_tracker
|
|
55
|
+
build_impressions_components
|
|
56
|
+
|
|
57
|
+
@status_manager = Engine::StatusManager.new(@config, @internal_events_queue)
|
|
58
|
+
@split_validator = SplitIoClient::Validators.new(@config)
|
|
59
|
+
@evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @rule_based_segment_repository, @config)
|
|
60
|
+
|
|
61
|
+
start!
|
|
62
|
+
fallback_treatment_calculator = SplitIoClient::Engine::FallbackTreatmentCalculator.new(@config.fallback_treatments_configuration)
|
|
63
|
+
@client = SplitClient.new(@api_key, repositories, @status_manager, @config, @impressions_manager, @evaluation_producer, @evaluator, @split_validator, fallback_treatment_calculator, @events_manager)
|
|
64
|
+
@manager = SplitManager.new(@splits_repository, @status_manager, @config)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def start!
|
|
68
|
+
return start_localhost_components if @config.localhost_mode
|
|
69
|
+
|
|
70
|
+
if @config.consumer?
|
|
71
|
+
build_synchronizer
|
|
72
|
+
build_sync_manager
|
|
73
|
+
|
|
74
|
+
@sync_manager.start_consumer
|
|
75
|
+
return
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
build_fetchers
|
|
79
|
+
build_synchronizer
|
|
80
|
+
build_streaming_components
|
|
81
|
+
build_sync_manager
|
|
82
|
+
|
|
83
|
+
@sync_manager.start
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def stop!
|
|
87
|
+
@config.threads.each { |_, t| t.exit }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def register_factory
|
|
91
|
+
SplitIoClient.load_factory_registry
|
|
92
|
+
|
|
93
|
+
number_of_factories = SplitIoClient.split_factory_registry.number_of_factories_for(@api_key)
|
|
94
|
+
|
|
95
|
+
if(number_of_factories > 0)
|
|
96
|
+
@config.logger.warn("Factory instantiation: You already have #{number_of_factories} factories with this API Key. #{SINGLETON_WARN}")
|
|
97
|
+
elsif(SplitIoClient.split_factory_registry.other_factories)
|
|
98
|
+
@config.logger.warn('Factory instantiation: You already have an instance of the Split factory.' \
|
|
99
|
+
" Make sure you definitely want this additional instance. #{SINGLETON_WARN}")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
SplitIoClient.split_factory_registry.add(@api_key)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def valid_mode
|
|
106
|
+
valid_startup_mode = false
|
|
107
|
+
case @config.mode
|
|
108
|
+
when :consumer
|
|
109
|
+
if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::RedisAdapter
|
|
110
|
+
if !@config.localhost_mode
|
|
111
|
+
valid_startup_mode = true
|
|
112
|
+
else
|
|
113
|
+
@config.logger.error('Localhost mode cannot be used with Redis. ' \
|
|
114
|
+
'Use standalone mode and Memory adapter instead.')
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
@config.logger.error('Consumer mode cannot be used with Memory adapter. ' \
|
|
118
|
+
'Use Redis adapter instead.')
|
|
119
|
+
end
|
|
120
|
+
when :standalone
|
|
121
|
+
if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::MemoryAdapter
|
|
122
|
+
valid_startup_mode = true
|
|
123
|
+
else
|
|
124
|
+
@config.logger.error('Standalone mode cannot be used with Redis adapter. ' \
|
|
125
|
+
'Use Memory adapter instead.')
|
|
126
|
+
end
|
|
127
|
+
when :producer
|
|
128
|
+
@config.logger.error('Producer mode is no longer supported. Use Split Synchronizer. ' \
|
|
129
|
+
'See: https://github.com/splitio/split-synchronizer')
|
|
130
|
+
else
|
|
131
|
+
@config.logger.error('Invalid SDK mode selected. ' \
|
|
132
|
+
"Valid modes are 'standalone with memory adapter' and 'consumer with redis adapter'")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
valid_startup_mode
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
alias resume! start!
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def validate_api_key
|
|
143
|
+
if(@api_key.nil?)
|
|
144
|
+
@config.logger.error('Factory Instantiation: you passed a nil api_key, api_key must be a non-empty String')
|
|
145
|
+
@config.valid_mode = false
|
|
146
|
+
elsif (@api_key.empty?)
|
|
147
|
+
@config.logger.error('Factory Instantiation: you passed and empty api_key, api_key must be a non-empty String')
|
|
148
|
+
@config.valid_mode = false
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def repositories
|
|
153
|
+
{
|
|
154
|
+
splits: @splits_repository,
|
|
155
|
+
segments: @segments_repository,
|
|
156
|
+
impressions: @impressions_repository,
|
|
157
|
+
events: @events_repository,
|
|
158
|
+
rule_based_segments: @rule_based_segment_repository
|
|
159
|
+
}
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def start_localhost_components
|
|
163
|
+
LocalhostSplitStore.new(@splits_repository, @config, @status_manager).call
|
|
164
|
+
|
|
165
|
+
# Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
|
|
166
|
+
LocalhostRepoCleaner.new(@impressions_repository, @events_repository, @config).call
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def build_telemetry_components
|
|
170
|
+
@evaluation_consumer = Telemetry::EvaluationConsumer.new(@config)
|
|
171
|
+
@evaluation_producer = Telemetry::EvaluationProducer.new(@config)
|
|
172
|
+
|
|
173
|
+
@init_consumer = Telemetry::InitConsumer.new(@config)
|
|
174
|
+
@init_producer = Telemetry::InitProducer.new(@config)
|
|
175
|
+
|
|
176
|
+
@runtime_consumer = Telemetry::RuntimeConsumer.new(@config)
|
|
177
|
+
@runtime_producer = Telemetry::RuntimeProducer.new(@config)
|
|
178
|
+
|
|
179
|
+
@telemetry_consumers = { init: @init_consumer, evaluation: @evaluation_consumer, runtime: @runtime_consumer }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def build_fetchers
|
|
183
|
+
@split_fetcher = SplitFetcher.new(@splits_repository, @rule_based_segment_repository, @api_key, @config, @runtime_producer)
|
|
184
|
+
@segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @config, @runtime_producer)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def build_synchronizer
|
|
188
|
+
params = {
|
|
189
|
+
split_fetcher: @split_fetcher,
|
|
190
|
+
segment_fetcher: @segment_fetcher,
|
|
191
|
+
imp_counter: @impression_counter,
|
|
192
|
+
telemetry_synchronizer: @telemetry_synchronizer,
|
|
193
|
+
impressions_sender_adapter: @impressions_sender_adapter,
|
|
194
|
+
impressions_api: @impressions_api,
|
|
195
|
+
unique_keys_tracker: @unique_keys_tracker
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@synchronizer = Engine::Synchronizer.new(repositories, @config, params)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def build_streaming_components
|
|
202
|
+
@push_status_queue = Queue.new
|
|
203
|
+
splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher, @rule_based_segment_repository)
|
|
204
|
+
segments_worker = SSE::Workers::SegmentsWorker.new(@synchronizer, @config, @segments_repository)
|
|
205
|
+
notification_manager_keeper = SSE::NotificationManagerKeeper.new(@config, @runtime_producer, @push_status_queue)
|
|
206
|
+
notification_processor = SSE::NotificationProcessor.new(@config, splits_worker, segments_worker)
|
|
207
|
+
event_parser = SSE::EventSource::EventParser.new(config)
|
|
208
|
+
sse_client = SSE::EventSource::Client.new(@config, @api_key, @runtime_producer, event_parser, notification_manager_keeper, notification_processor, @push_status_queue)
|
|
209
|
+
@sse_handler = SSE::SSEHandler.new(@config, splits_worker, segments_worker, sse_client)
|
|
210
|
+
@push_manager = Engine::PushManager.new(@config, @sse_handler, @api_key, @runtime_producer)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def build_sync_manager
|
|
214
|
+
@sync_manager = Engine::SyncManager.new(@config, @synchronizer, @runtime_producer, @telemetry_synchronizer, @status_manager, @sse_handler, @push_manager, @push_status_queue)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def build_repositories
|
|
218
|
+
if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::RedisAdapter
|
|
219
|
+
@flag_sets_repository = SplitIoClient::Cache::Repositories::RedisFlagSetsRepository.new(@config)
|
|
220
|
+
else
|
|
221
|
+
@flag_sets_repository = SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new(@config.flag_sets_filter)
|
|
222
|
+
end
|
|
223
|
+
@splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter, @internal_events_queue)
|
|
224
|
+
@segments_repository = SegmentsRepository.new(@config, @internal_events_queue)
|
|
225
|
+
@rule_based_segment_repository = RuleBasedSegmentsRepository.new(@config, @internal_events_queue)
|
|
226
|
+
@impressions_repository = ImpressionsRepository.new(@config)
|
|
227
|
+
@events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def build_telemetry_synchronizer(flag_sets, flag_sets_invalid)
|
|
231
|
+
@telemetry_api = Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
|
|
232
|
+
@telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, @telemetry_api, flag_sets, flag_sets_invalid)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def build_unique_keys_tracker
|
|
236
|
+
bf = Cache::Filter::BloomFilter.new(30_000_000)
|
|
237
|
+
filter_adapter = Cache::Filter::FilterAdapter.new(@config, bf)
|
|
238
|
+
cache = Concurrent::Hash.new
|
|
239
|
+
@unique_keys_tracker = Engine::Impressions::UniqueKeysTracker.new(@config, filter_adapter, @impressions_sender_adapter, cache)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def build_impressions_observer
|
|
243
|
+
if (@config.cache_adapter == :redis && @config.impressions_mode != :optimized)
|
|
244
|
+
@impression_observer = Observers::NoopImpressionObserver.new
|
|
245
|
+
else
|
|
246
|
+
@impression_observer = Observers::ImpressionObserver.new
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def build_impression_counter
|
|
251
|
+
@impression_counter = Engine::Common::ImpressionCounter.new
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def build_impressions_sender_adapter
|
|
255
|
+
@impressions_api = Api::Impressions.new(@api_key, @config, @runtime_producer)
|
|
256
|
+
@impressions_sender_adapter = Cache::Senders::ImpressionsSenderAdapter.new(@config, @telemetry_api, @impressions_api)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def build_impressions_components
|
|
260
|
+
build_impressions_observer
|
|
261
|
+
build_impression_counter
|
|
262
|
+
|
|
263
|
+
@impressions_manager = Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter, @runtime_producer, @impression_observer, @unique_keys_tracker)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def build_flag_sets_filter
|
|
267
|
+
@flag_sets_filter = SplitIoClient::Cache::Filter::FlagSetsFilter.new(@config.flag_sets_filter)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def build_events_manager
|
|
271
|
+
@events_manager = Engine::Events::EventsManager.new(Engine::Events::EventsManagerConfig.new,
|
|
272
|
+
Engine::Events::EventsDelivery.new(@config),
|
|
273
|
+
@config)
|
|
274
|
+
if @config.consumer?
|
|
275
|
+
@internal_events_queue = Engine::Events::NoOpEventsQueue.new
|
|
276
|
+
return
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
@internal_events_queue = Queue.new
|
|
280
|
+
@events_task = Engine::Events::EventsTask.new(@events_manager.method(:notify_internal_event), @internal_events_queue, @config)
|
|
281
|
+
@events_task.start
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'socket'
|
|
3
|
+
|
|
4
|
+
module SplitIoClient
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :split_factory_registry
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.load_factory_registry
|
|
11
|
+
self.split_factory_registry ||= SplitFactoryRegistry.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# This class manages configuration options for the split client library.
|
|
16
|
+
# If not custom configuration is required the default configuration values will be used
|
|
17
|
+
#
|
|
18
|
+
class SplitFactoryRegistry
|
|
19
|
+
|
|
20
|
+
attr_accessor :api_keys_hash
|
|
21
|
+
|
|
22
|
+
def initialize
|
|
23
|
+
@api_keys_hash = Hash.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add(api_key)
|
|
27
|
+
return unless api_key
|
|
28
|
+
|
|
29
|
+
@api_keys_hash[api_key] = 0 unless @api_keys_hash[api_key]
|
|
30
|
+
@api_keys_hash[api_key] += 1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def remove(api_key)
|
|
34
|
+
return unless api_key
|
|
35
|
+
|
|
36
|
+
@api_keys_hash[api_key] -= 1 if @api_keys_hash[api_key]
|
|
37
|
+
@api_keys_hash.delete(api_key) if @api_keys_hash[api_key] == 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def number_of_factories_for(api_key)
|
|
41
|
+
return 0 unless api_key
|
|
42
|
+
return 0 unless @api_keys_hash.key?(api_key)
|
|
43
|
+
|
|
44
|
+
@api_keys_hash[api_key]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def other_factories
|
|
48
|
+
return !@api_keys_hash.empty?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def active_factories
|
|
52
|
+
@api_keys_hash.length
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def redundant_active_factories
|
|
56
|
+
to_return = 0
|
|
57
|
+
|
|
58
|
+
@api_keys_hash.each { |key| to_return += (key[1]-1) }
|
|
59
|
+
|
|
60
|
+
to_return
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
class SplitLogger
|
|
3
|
+
def initialize(config)
|
|
4
|
+
@config = config
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def log_if_debug(message)
|
|
8
|
+
@config.logger.debug(message) if @config.debug_enabled
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def log_if_transport(message)
|
|
12
|
+
@config.logger.debug(message) if @config.transport_debug_enabled
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def error(message)
|
|
16
|
+
@config.logger.error(message)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def debug(message)
|
|
20
|
+
@config.logger.debug(message) if @config.debug_enabled
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'timeout'
|
|
7
|
+
|
|
8
|
+
module SplitIoClient
|
|
9
|
+
module SSE
|
|
10
|
+
module EventSource
|
|
11
|
+
class Client
|
|
12
|
+
DEFAULT_READ_TIMEOUT = 70
|
|
13
|
+
CONNECT_TIMEOUT = 30
|
|
14
|
+
OK_CODE = 200
|
|
15
|
+
KEEP_ALIVE_RESPONSE = "c\r\n:keepalive\n\n\r\n".freeze
|
|
16
|
+
ERROR_EVENT_TYPE = 'error'.freeze
|
|
17
|
+
|
|
18
|
+
def initialize(config,
|
|
19
|
+
api_key,
|
|
20
|
+
telemetry_runtime_producer,
|
|
21
|
+
event_parser,
|
|
22
|
+
notification_manager_keeper,
|
|
23
|
+
notification_processor,
|
|
24
|
+
status_queue,
|
|
25
|
+
read_timeout: DEFAULT_READ_TIMEOUT)
|
|
26
|
+
@config = config
|
|
27
|
+
@api_key = api_key
|
|
28
|
+
@telemetry_runtime_producer = telemetry_runtime_producer
|
|
29
|
+
@event_parser = event_parser
|
|
30
|
+
@notification_manager_keeper = notification_manager_keeper
|
|
31
|
+
@notification_processor = notification_processor
|
|
32
|
+
@status_queue = status_queue
|
|
33
|
+
@read_timeout = read_timeout
|
|
34
|
+
@connected = Concurrent::AtomicBoolean.new(false)
|
|
35
|
+
@first_event = Concurrent::AtomicBoolean.new(true)
|
|
36
|
+
@socket = nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def close(status = nil)
|
|
40
|
+
unless connected?
|
|
41
|
+
@config.logger.debug('SSEClient already disconected.') if @config.debug_enabled
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
@config.logger.debug("Closing SSEClient socket") if @config.debug_enabled
|
|
45
|
+
|
|
46
|
+
push_status(status)
|
|
47
|
+
@connected.make_false
|
|
48
|
+
@socket.sync_close = true if @socket.is_a? OpenSSL::SSL::SSLSocket
|
|
49
|
+
@socket.close
|
|
50
|
+
@config.logger.debug("SSEClient socket state #{@socket.state}") if @socket.is_a?(OpenSSL::SSL::SSLSocket) && @config.debug_enabled
|
|
51
|
+
rescue StandardError => e
|
|
52
|
+
@config.logger.error("SSEClient close Error: #{e.inspect}")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def start(url)
|
|
56
|
+
if connected?
|
|
57
|
+
@config.logger.debug('SSEClient already running.') if @config.debug_enabled
|
|
58
|
+
return true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@uri = URI(url)
|
|
62
|
+
latch = Concurrent::CountDownLatch.new(1)
|
|
63
|
+
connect_thread(latch)
|
|
64
|
+
|
|
65
|
+
return false unless latch.wait(CONNECT_TIMEOUT)
|
|
66
|
+
|
|
67
|
+
connected?
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
@config.logger.error("SSEClient start Error: #{e.inspect}")
|
|
70
|
+
connected?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def connected?
|
|
74
|
+
@connected.value
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def connect_thread(latch)
|
|
80
|
+
@config.threads[:connect_stream] = Thread.new do
|
|
81
|
+
@config.logger.info('Starting connect_stream thread ...')
|
|
82
|
+
new_status = connect_stream(latch)
|
|
83
|
+
push_status(new_status)
|
|
84
|
+
@config.logger.info('connect_stream thread finished.')
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def connect_stream(latch)
|
|
89
|
+
return Constants::PUSH_RETRYABLE_ERROR unless socket_write(latch)
|
|
90
|
+
while connected? || @first_event.value
|
|
91
|
+
begin
|
|
92
|
+
if IO.select([@socket], nil, nil, @read_timeout)
|
|
93
|
+
begin
|
|
94
|
+
partial_data = @socket.readpartial(10_000)
|
|
95
|
+
read_first_event(partial_data, latch)
|
|
96
|
+
|
|
97
|
+
if partial_data == :eof
|
|
98
|
+
@config.logger.error("SSE recived EOF unexpectedly")
|
|
99
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
100
|
+
end
|
|
101
|
+
rescue IO::WaitReadable => e
|
|
102
|
+
@config.logger.debug("SSE client IO::WaitReadable transient error: #{e.inspect}") if @config.debug_enabled
|
|
103
|
+
IO.select([@socket], nil, nil, @read_timeout)
|
|
104
|
+
retry
|
|
105
|
+
rescue Errno::EAGAIN => e
|
|
106
|
+
@config.logger.debug("SSE client transient error: #{e.inspect}") if @config.debug_enabled
|
|
107
|
+
IO.select([@socket], nil, nil, @read_timeout)
|
|
108
|
+
retry
|
|
109
|
+
rescue Errno::ETIMEDOUT => e
|
|
110
|
+
@config.logger.error("SSE read operation timed out!: #{e.inspect}")
|
|
111
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
112
|
+
rescue EOFError => e
|
|
113
|
+
@config.logger.error("SSE read operation EOF Exception!: #{e.inspect}")
|
|
114
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
115
|
+
rescue Errno::EBADF, IOError => e
|
|
116
|
+
@config.logger.error("SSE read operation EBADF or IOError: #{e.inspect}")
|
|
117
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
118
|
+
rescue StandardError => e
|
|
119
|
+
@config.logger.error("SSE read operation StandardError: #{e.inspect}")
|
|
120
|
+
return nil if ENV['SPLITCLIENT_ENV'] == 'test'
|
|
121
|
+
|
|
122
|
+
@config.logger.error("Error reading partial data: #{e.inspect}")
|
|
123
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
@config.logger.error("SSE read operation timed out, no data available.")
|
|
127
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
128
|
+
end
|
|
129
|
+
rescue Errno::EBADF
|
|
130
|
+
@config.logger.debug("SSE socket is not connected (Errno::EBADF)") if @config.debug_enabled
|
|
131
|
+
break
|
|
132
|
+
rescue Exception => e
|
|
133
|
+
@config.logger.debug("SSE socket is not connected: #{e.inspect}") if @config.debug_enabled
|
|
134
|
+
break
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
process_data(partial_data)
|
|
138
|
+
end
|
|
139
|
+
@config.logger.info("SSE read operation exited: #{connected?}")
|
|
140
|
+
|
|
141
|
+
nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def socket_write(latch)
|
|
145
|
+
@first_event.make_true
|
|
146
|
+
@socket = socket_connect
|
|
147
|
+
@socket.puts(build_request(@uri))
|
|
148
|
+
true
|
|
149
|
+
rescue StandardError => e
|
|
150
|
+
@config.logger.error("Error during connecting to #{@uri.host}. Error: #{e.inspect}")
|
|
151
|
+
latch.count_down
|
|
152
|
+
false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def read_first_event(data, latch)
|
|
156
|
+
return unless @first_event.value
|
|
157
|
+
|
|
158
|
+
response_code = @event_parser.first_event(data)
|
|
159
|
+
@config.logger.debug("SSE client first event code: #{response_code}") if @config.debug_enabled
|
|
160
|
+
|
|
161
|
+
error_event = false
|
|
162
|
+
events = @event_parser.parse(data)
|
|
163
|
+
events.each { |e| error_event = true if e.event_type == ERROR_EVENT_TYPE }
|
|
164
|
+
@first_event.make_false
|
|
165
|
+
|
|
166
|
+
if response_code == OK_CODE && !error_event
|
|
167
|
+
@connected.make_true
|
|
168
|
+
@config.logger.debug("SSE client first event Connected is true") if @config.debug_enabled
|
|
169
|
+
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::SSE_CONNECTION_ESTABLISHED, nil)
|
|
170
|
+
push_status(Constants::PUSH_CONNECTED)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
latch.count_down
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def socket_connect
|
|
177
|
+
tcp_socket = TCPSocket.new(@uri.host, @uri.port)
|
|
178
|
+
if @uri.scheme.casecmp('https').zero?
|
|
179
|
+
begin
|
|
180
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
|
181
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
|
182
|
+
ssl_socket.hostname = @uri.host
|
|
183
|
+
|
|
184
|
+
begin
|
|
185
|
+
ssl_socket.connect_nonblock
|
|
186
|
+
rescue IO::WaitReadable
|
|
187
|
+
IO.select([ssl_socket])
|
|
188
|
+
retry
|
|
189
|
+
rescue IO::WaitWritable
|
|
190
|
+
IO.select(nil, [ssl_socket])
|
|
191
|
+
retry
|
|
192
|
+
end
|
|
193
|
+
return ssl_socket
|
|
194
|
+
|
|
195
|
+
rescue Exception => e
|
|
196
|
+
@config.logger.error("socket connect error: #{e.inspect}")
|
|
197
|
+
return nil
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
tcp_socket
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def process_data(partial_data)
|
|
205
|
+
@config.logger.debug("Event partial data: #{partial_data}") if @config.debug_enabled
|
|
206
|
+
return if partial_data.nil? || partial_data == KEEP_ALIVE_RESPONSE
|
|
207
|
+
|
|
208
|
+
events = @event_parser.parse(partial_data)
|
|
209
|
+
events.each { |event| process_event(event) }
|
|
210
|
+
rescue StandardError => e
|
|
211
|
+
@config.logger.error("process_data error: #{e.inspect}")
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def build_request(uri)
|
|
215
|
+
req = "GET #{uri.request_uri} HTTP/1.1\r\n"
|
|
216
|
+
req << "Host: #{uri.host}\r\n"
|
|
217
|
+
req << "Accept: text/event-stream\r\n"
|
|
218
|
+
req << "SplitSDKVersion: #{@config.language}-#{@config.version}\r\n"
|
|
219
|
+
req << "SplitSDKMachineIP: #{@config.machine_ip}\r\n"
|
|
220
|
+
req << "SplitSDKMachineName: #{@config.machine_name}\r\n"
|
|
221
|
+
req << "SplitSDKClientKey: #{@api_key.split(//).last(4).join}\r\n" unless @api_key.nil?
|
|
222
|
+
req << "Cache-Control: no-cache\r\n\r\n"
|
|
223
|
+
@config.logger.debug("Request info: #{req}") if @config.debug_enabled
|
|
224
|
+
req
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def process_event(event)
|
|
228
|
+
case event.event_type
|
|
229
|
+
when ERROR_EVENT_TYPE
|
|
230
|
+
dispatch_error(event)
|
|
231
|
+
else
|
|
232
|
+
dispatch_event(event)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def dispatch_error(event)
|
|
237
|
+
@config.logger.error("Event error: #{event.event_type}, #{event.data}")
|
|
238
|
+
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::ABLY_ERROR, event.data['code'])
|
|
239
|
+
|
|
240
|
+
if event.data['code'] >= 40_140 && event.data['code'] <= 40_149
|
|
241
|
+
close(Constants::PUSH_RETRYABLE_ERROR)
|
|
242
|
+
elsif event.data['code'] >= 40_000 && event.data['code'] <= 49_999
|
|
243
|
+
close(Constants::PUSH_NONRETRYABLE_ERROR)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def dispatch_event(event)
|
|
248
|
+
if event.occupancy?
|
|
249
|
+
@notification_manager_keeper.handle_incoming_occupancy_event(event)
|
|
250
|
+
else
|
|
251
|
+
@notification_processor.process(event)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def push_status(status)
|
|
256
|
+
return if status.nil?
|
|
257
|
+
|
|
258
|
+
@config.logger.debug("Pushing new sse status: #{status}") if @config.debug_enabled
|
|
259
|
+
@status_queue.push(status)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|