splitclient-rb 7.0.4.pre.rc3 → 7.1.0.pre.rc1

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -3
  3. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +4 -0
  4. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +4 -1
  5. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +1 -1
  6. data/lib/splitclient-rb/clients/split_client.rb +4 -7
  7. data/lib/splitclient-rb/constants.rb +9 -0
  8. data/lib/splitclient-rb/engine/api/splits.rb +0 -1
  9. data/lib/splitclient-rb/engine/auth_api_client.rb +78 -0
  10. data/lib/splitclient-rb/engine/push_manager.rb +46 -0
  11. data/lib/splitclient-rb/engine/sync_manager.rb +112 -0
  12. data/lib/splitclient-rb/engine/synchronizer.rb +80 -0
  13. data/lib/splitclient-rb/exceptions.rb +8 -0
  14. data/lib/splitclient-rb/helpers/thread_helper.rb +19 -0
  15. data/lib/splitclient-rb/split_config.rb +42 -4
  16. data/lib/splitclient-rb/split_factory.rb +25 -15
  17. data/lib/splitclient-rb/sse/event_source/back_off.rb +25 -0
  18. data/lib/splitclient-rb/sse/event_source/client.rb +73 -50
  19. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  20. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +45 -0
  21. data/lib/splitclient-rb/sse/notification_processor.rb +50 -0
  22. data/lib/splitclient-rb/sse/sse_handler.rb +46 -50
  23. data/lib/splitclient-rb/sse/workers/control_worker.rb +10 -5
  24. data/lib/splitclient-rb/sse/workers/segments_worker.rb +14 -4
  25. data/lib/splitclient-rb/sse/workers/splits_worker.rb +16 -4
  26. data/lib/splitclient-rb/version.rb +1 -1
  27. data/lib/splitclient-rb.rb +10 -2
  28. data/splitclient-rb.gemspec +1 -0
  29. metadata +26 -4
  30. data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -105
  31. data/lib/splitclient-rb/sse/event_source/status.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eafdd083c1f0790ba57e473a7b6fad62f9e142ecfbf7ec07f83a000ab9323756
4
- data.tar.gz: d25fdfe6d2b57d85f3b0a6fd9886fd72c3fe4695193a378c17116a5e26d79eae
3
+ metadata.gz: faa0e8b87fc65523dcfa6611ddb9e672fbd213487aea472455435aa080c29f60
4
+ data.tar.gz: 69b8a67b002dadd9b92e20d04bf18f4a05756ded1822039c48e47ff12a4e20e8
5
5
  SHA512:
6
- metadata.gz: f8e1ac7930d9afc93715329075c4853c5949b8f7cfcaeefb72658b5e02c3c89fdf46ebcde689d7b8071daeb25e5dd9939d7e457c7587f18c8e9f2c1185b342d0
7
- data.tar.gz: 6c9f61e424c8aba6b9c2da31ee7df64fb64b0cb7ad99ff9c4e5c84b9ccaa57e040aa644e1c680a6720247236f3fdf96c6584100f928262ed9ea96d46cb571910
6
+ metadata.gz: b95e354b732d3377dc4d4bd5daf1b20d05b31e68478cb9e045f9f89b60a04c6834995a1522e7db43e450beeeec0bfb96547408f4f82032c80ad9117b7ac911be
7
+ data.tar.gz: 573ac96c29360b36f0091992604e3acd970732ca609377f1895776b1750dfc59d5627025c10ad8472c066a5b551fae0df87ff0db17ed3afe817bdfb12f1d42b7
data/.rubocop.yml CHANGED
@@ -2,16 +2,16 @@ Documentation:
2
2
  Enabled: false
3
3
 
4
4
  Metrics/AbcSize:
5
- Max: 25
5
+ Max: 26
6
6
 
7
7
  Metrics/MethodLength:
8
8
  Max: 20
9
9
 
10
10
  Metrics/ClassLength:
11
- Max: 120
11
+ Max: 140
12
12
 
13
13
  Metrics/LineLength:
14
- Max: 121
14
+ Max: 130
15
15
  Exclude:
16
16
  - spec/sse/**/*
17
17
 
@@ -40,6 +40,10 @@ module SplitIoClient
40
40
  @config.log_found_exception(__method__.to_s, error)
41
41
  end
42
42
 
43
+ def stop_segments_thread
44
+ SplitIoClient::Helpers::ThreadHelper.stop(:segment_fetcher, @config)
45
+ end
46
+
43
47
  private
44
48
 
45
49
  def segments_thread
@@ -39,11 +39,14 @@ module SplitIoClient
39
39
  @config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
40
40
 
41
41
  @sdk_blocker.splits_ready!
42
-
43
42
  rescue StandardError => error
44
43
  @config.log_found_exception(__method__.to_s, error)
45
44
  end
46
45
 
46
+ def stop_splits_thread
47
+ SplitIoClient::Helpers::ThreadHelper.stop(:split_fetcher, @config)
48
+ end
49
+
47
50
  private
48
51
 
49
52
  def splits_thread
@@ -133,7 +133,7 @@ module SplitIoClient
133
133
 
134
134
  return if split.nil?
135
135
 
136
- split[:label] = Engine::Models::Label::KILLED
136
+ split[:killed] = true
137
137
  split[:defaultTreatment] = default_treatment
138
138
  split[:changeNumber] = change_number
139
139
 
@@ -9,8 +9,9 @@ module SplitIoClient
9
9
  # @param api_key [String] the API key for your split account
10
10
  #
11
11
  # @return [SplitIoClient] split.io client instance
12
- def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config, sse_handler)
12
+ def initialize(api_key, metrics, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config)
13
13
  @api_key = api_key
14
+ @metrics = metrics
14
15
  @splits_repository = splits_repository
15
16
  @segments_repository = segments_repository
16
17
  @impressions_repository = impressions_repository
@@ -19,8 +20,6 @@ module SplitIoClient
19
20
  @sdk_blocker = sdk_blocker
20
21
  @destroyed = false
21
22
  @config = config
22
- @adapter = adapter
23
- @sse_handler = sse_handler
24
23
  end
25
24
 
26
25
  def get_treatment(
@@ -62,8 +61,6 @@ module SplitIoClient
62
61
  thread.join
63
62
  end
64
63
 
65
- @sse_handler.sse_client.close if @config.push_notification_enabled
66
-
67
64
  @config.threads.values.each { |thread| Thread.kill(thread) }
68
65
 
69
66
  @splits_repository.clear
@@ -252,7 +249,7 @@ module SplitIoClient
252
249
  end
253
250
  latency = (Time.now - start) * 1000.0
254
251
  # Measure
255
- @adapter.metrics.time('sdk.' + calling_method, latency)
252
+ @metrics.time('sdk.' + calling_method, latency)
256
253
 
257
254
  treatments_for_impressions = get_treatment_for_impressions(treatments_labels_change_numbers)
258
255
 
@@ -336,7 +333,7 @@ module SplitIoClient
336
333
  store_impression(split_name, matching_key, bucketing_key, treatment_data, attributes) if store_impressions
337
334
 
338
335
  # Measure
339
- @adapter.metrics.time('sdk.' + calling_method, latency) unless multiple
336
+ @metrics.time('sdk.' + calling_method, latency) unless multiple
340
337
  rescue StandardError => error
341
338
  @config.log_found_exception(__method__.to_s, error)
342
339
 
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SplitIoClient::Constants
4
+ EXPIRATION_RATE = 600
5
+ CONTROL_PRI = 'control_pri'
6
+ CONTROL_SEC = 'control_sec'
7
+ OCCUPANCY_CHANNEL_PREFIX = '[?occupancy=metrics.publishers]'
8
+ end
9
+
@@ -16,7 +16,6 @@ module SplitIoClient
16
16
  start = Time.now
17
17
 
18
18
  response = get_api("#{@config.base_uri}/splitChanges", @api_key, since: since)
19
-
20
19
  if response.success?
21
20
  result = splits_with_segment_names(response.body)
22
21
 
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jwt'
4
+ require 'cgi'
5
+
6
+ module SplitIoClient
7
+ module Engine
8
+ class AuthApiClient
9
+ def initialize(config)
10
+ @config = config
11
+ @api_client = SplitIoClient::Api::Client.new(@config)
12
+ end
13
+
14
+ def authenticate(api_key)
15
+ response = @api_client.get_api(@config.auth_service_url, api_key)
16
+
17
+ return process_success(response) if response.success?
18
+
19
+ if response.status >= 400 && response.status < 500
20
+ @config.logger.debug("Problem to connect to: #{@config.auth_service_url}. Response status: #{response.status}")
21
+
22
+ return { push_enabled: false, retry: false }
23
+ end
24
+
25
+ @config.logger.debug("Problem to connect to: #{@config.auth_service_url}. Response status: #{response.status}")
26
+ { push_enabled: false, retry: true }
27
+ end
28
+
29
+ private
30
+
31
+ def expiration(token_decoded)
32
+ exp = token_decoded[0]['exp']
33
+
34
+ (exp - SplitIoClient::Constants::EXPIRATION_RATE) - Time.now.getutc.to_i unless exp.nil?
35
+ rescue StandardError => e
36
+ @config.logger.error("Error getting token expiration: #{e.inspect}")
37
+ end
38
+
39
+ def channels(token_decoded)
40
+ capability = token_decoded[0]['x-ably-capability']
41
+ channels_hash = JSON.parse(capability)
42
+ channels_string = channels_hash.keys.join(',')
43
+ channels_string = control_channels(channels_string)
44
+ @config.logger.debug("Channels #{channels_string}")
45
+ CGI.escape(channels_string)
46
+ end
47
+
48
+ def decode_token(token)
49
+ JWT.decode token, nil, false
50
+ end
51
+
52
+ def process_success(response)
53
+ @config.logger.debug("Success connection to: #{@config.auth_service_url}")
54
+
55
+ body_json = JSON.parse(response.body, symbolize_names: true)
56
+ push_enabled = body_json[:pushEnabled]
57
+ token = body_json[:token]
58
+
59
+ if push_enabled
60
+ decoded_token = decode_token(token)
61
+ channels = channels(decoded_token)
62
+ exp = expiration(decoded_token)
63
+ end
64
+
65
+ { push_enabled: push_enabled, token: token, channels: channels, exp: exp, retry: false }
66
+ end
67
+
68
+ def control_channels(channels_string)
69
+ prefix = SplitIoClient::Constants::OCCUPANCY_CHANNEL_PREFIX
70
+ control_pri = SplitIoClient::Constants::CONTROL_PRI
71
+ control_sec = SplitIoClient::Constants::CONTROL_SEC
72
+ channels_string = channels_string.gsub(control_pri, "#{prefix}#{control_pri}")
73
+ channels_string = channels_string.gsub(control_sec, "#{prefix}#{control_sec}")
74
+ channels_string
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Engine
5
+ class PushManager
6
+ def initialize(config, sse_handler, api_key)
7
+ @config = config
8
+ @sse_handler = sse_handler
9
+ @auth_api_client = AuthApiClient.new(@config)
10
+ @api_key = api_key
11
+ @back_off = SplitIoClient::SSE::EventSource::BackOff.new(@config.auth_retry_back_off_base)
12
+ end
13
+
14
+ def start_sse
15
+ response = @auth_api_client.authenticate(@api_key)
16
+
17
+ if response[:push_enabled]
18
+ @sse_handler.start(response[:token], response[:channels])
19
+ schedule_next_token_refresh(response[:exp])
20
+ @back_off.reset
21
+ else
22
+ stop_sse
23
+ end
24
+
25
+ schedule_next_token_refresh(@back_off.interval) if response[:retry]
26
+ rescue StandardError => e
27
+ @config.logger.error("start_sse: #{e.inspect}")
28
+ end
29
+
30
+ def stop_sse
31
+ @sse_handler.process_disconnect if @sse_handler.sse_client.nil?
32
+ @sse_handler.stop
33
+ end
34
+
35
+ private
36
+
37
+ def schedule_next_token_refresh(time)
38
+ @config.threads[:schedule_next_token_refresh] = Thread.new do
39
+ sleep(time)
40
+ stop_sse
41
+ start_sse
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Engine
5
+ class SyncManager
6
+ include SplitIoClient::Cache::Fetchers
7
+
8
+ def initialize(
9
+ repositories,
10
+ api_key,
11
+ config,
12
+ sdk_blocker,
13
+ metrics
14
+ )
15
+ split_fetcher = SplitFetcher.new(repositories[:splits], api_key, metrics, config, sdk_blocker)
16
+ segment_fetcher = SegmentFetcher.new(repositories[:segments], api_key, metrics, config, sdk_blocker)
17
+ sync_params = { split_fetcher: split_fetcher, segment_fetcher: segment_fetcher }
18
+
19
+ @synchronizer = Synchronizer.new(repositories, api_key, config, sdk_blocker, sync_params)
20
+ notification_manager_keeper = SplitIoClient::SSE::NotificationManagerKeeper.new(config) do |manager|
21
+ manager.on_occupancy { |publisher_available| process_occupancy(publisher_available) }
22
+ end
23
+ @sse_handler = SplitIoClient::SSE::SSEHandler.new(
24
+ config,
25
+ @synchronizer,
26
+ repositories[:splits],
27
+ repositories[:segments],
28
+ notification_manager_keeper
29
+ ) do |handler|
30
+ handler.on_connected { process_connected }
31
+ handler.on_disconnect { process_disconnect }
32
+ end
33
+
34
+ @push_manager = PushManager.new(config, @sse_handler, api_key)
35
+ @config = config
36
+ end
37
+
38
+ def start
39
+ if @config.streaming_enabled
40
+ start_stream
41
+ elsif @config.standalone?
42
+ start_poll
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # Starts tasks if stream is enabled.
49
+ def start_stream
50
+ stream_start_thread
51
+ stream_start_thread_forked if defined?(PhusionPassenger)
52
+
53
+ stream_start_sse_thread
54
+ stream_start_sse_thread_forked if defined?(PhusionPassenger)
55
+ end
56
+
57
+ def start_poll
58
+ @synchronizer.start_periodic_fetch
59
+ @synchronizer.start_periodic_data_recording
60
+ rescue StandardError => error
61
+ @config.logger.error(error)
62
+ end
63
+
64
+ # Starts thread which fetch splits and segments once and trigger task to periodic data recording.
65
+ def stream_start_thread
66
+ @config.threads[:sync_manager_start_stream] = Thread.new do
67
+ begin
68
+ @synchronizer.sync_all
69
+ @synchronizer.start_periodic_data_recording
70
+ rescue StandardError => error
71
+ @config.logger.error(error)
72
+ end
73
+ end
74
+ end
75
+
76
+ # Starts thread which connect to sse and after that fetch splits and segments once.
77
+ def stream_start_sse_thread
78
+ @config.threads[:sync_manager_start_sse] = Thread.new do
79
+ begin
80
+ @push_manager.start_sse
81
+ rescue StandardError => error
82
+ @config.logger.error(error)
83
+ end
84
+ end
85
+ end
86
+
87
+ def stream_start_thread_forked
88
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| stream_start_thread if forked }
89
+ end
90
+
91
+ def stream_start_sse_thread_forked
92
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| stream_start_sse_thread if forked }
93
+ end
94
+
95
+ def process_connected
96
+ @synchronizer.stop_periodic_fetch
97
+ @synchronizer.sync_all
98
+ @sse_handler.start_workers
99
+ end
100
+
101
+ def process_disconnect
102
+ @sse_handler.stop_workers
103
+ @synchronizer.start_periodic_fetch
104
+ end
105
+
106
+ def process_occupancy(publisher_available)
107
+ process_disconnect unless publisher_available
108
+ process_connected if publisher_available
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Engine
5
+ class Synchronizer
6
+ include SplitIoClient::Cache::Fetchers
7
+ include SplitIoClient::Cache::Senders
8
+
9
+ def initialize(
10
+ repositories,
11
+ api_key,
12
+ config,
13
+ sdk_blocker,
14
+ params
15
+ )
16
+ @splits_repository = repositories[:splits]
17
+ @segments_repository = repositories[:segments]
18
+ @impressions_repository = repositories[:impressions]
19
+ @metrics_repository = repositories[:metrics]
20
+ @events_repository = repositories[:events]
21
+ @api_key = api_key
22
+ @config = config
23
+ @sdk_blocker = sdk_blocker
24
+ @split_fetcher = params[:split_fetcher]
25
+ @segment_fetcher = params[:segment_fetcher]
26
+ end
27
+
28
+ def sync_all
29
+ @config.logger.debug('Synchronizing Splits and Segments ...')
30
+ fetch_splits
31
+ fetch_segments
32
+ end
33
+
34
+ def start_periodic_data_recording
35
+ @metrics_sender = metrics_sender
36
+ @impressions_sender = impressions_sender
37
+ @events_sender = events_sender
38
+ end
39
+
40
+ def start_periodic_fetch
41
+ @split_fetcher.call
42
+ @segment_fetcher.call
43
+ end
44
+
45
+ def stop_periodic_fetch
46
+ @split_fetcher.stop_splits_thread
47
+ @segment_fetcher.stop_segments_thread
48
+ end
49
+
50
+ def fetch_splits
51
+ @split_fetcher.fetch_splits
52
+ end
53
+
54
+ def fetch_segment(name)
55
+ @segment_fetcher.fetch_segment(name)
56
+ end
57
+
58
+ private
59
+
60
+ def fetch_segments
61
+ @segment_fetcher.fetch_segments
62
+ end
63
+
64
+ # Starts thread which loops constantly and sends impressions to the Split API
65
+ def impressions_sender
66
+ ImpressionsSender.new(@impressions_repository, @api_key, @config).call
67
+ end
68
+
69
+ # Starts thread which loops constantly and sends metrics to the Split API
70
+ def metrics_sender
71
+ MetricsSender.new(@metrics_repository, @api_key, @config).call
72
+ end
73
+
74
+ # Starts thread which loops constantly and sends events to the Split API
75
+ def events_sender
76
+ EventsSender.new(@events_repository, @config).call
77
+ end
78
+ end
79
+ end
80
+ end
@@ -4,4 +4,12 @@ module SplitIoClient
4
4
  class SDKShutdownException < SplitIoError; end
5
5
 
6
6
  class SDKBlockerTimeoutExpiredException < SplitIoError; end
7
+
8
+ class SSEClientException < SplitIoError
9
+ attr_reader :event
10
+
11
+ def initialize(event)
12
+ @event = event
13
+ end
14
+ end
7
15
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Helpers
5
+ class ThreadHelper
6
+ def self.stop(thread_sym, config)
7
+ thread = config.threads[thread_sym]
8
+
9
+ unless thread.nil?
10
+ config.logger.debug("Stopping #{thread_sym} ...")
11
+ sleep(0.1) while thread.status == 'run'
12
+ Thread.kill(thread)
13
+ end
14
+ rescue StandardError => error
15
+ config.logger.error(error.inspect)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -102,7 +102,11 @@ module SplitIoClient
102
102
  @split_validator = SplitIoClient::Validators.new(self)
103
103
  @localhost_mode = opts[:localhost_mode]
104
104
 
105
- @push_notification_enabled = opts[:push_notification_enabled].nil? ? true : false
105
+ @streaming_enabled = consumer? ? false : (opts[:streaming_enabled].nil? ? SplitConfig.default_streaming_enabled : opts[:streaming_enabled])
106
+ @streaming_service_url = opts[:streaming_service_url] || SplitConfig.default_streaming_service_url
107
+ @auth_service_url = opts[:auth_service_url] || SplitConfig.default_auth_service_url
108
+ @auth_retry_back_off_base = SplitConfig.init_auth_retry_back_off(opts[:auth_retry_back_off_base] || SplitConfig.default_auth_retry_back_off_base)
109
+ @streaming_reconnect_back_off_base = SplitConfig.init_streaming_reconnect_back_off(opts[:streaming_reconnect_back_off_base] || SplitConfig.default_streaming_reconnect_back_off_base)
106
110
 
107
111
  startup_log
108
112
  end
@@ -256,7 +260,43 @@ module SplitIoClient
256
260
 
257
261
  attr_accessor :ip_addresses_enabled
258
262
 
259
- attr_accessor :push_notification_enabled
263
+ attr_accessor :auth_service_url
264
+
265
+ attr_accessor :auth_retry_back_off_base
266
+
267
+ attr_accessor :streaming_service_url
268
+
269
+ attr_accessor :streaming_reconnect_back_off_base
270
+
271
+ attr_accessor :streaming_enabled
272
+
273
+ def self.default_streaming_enabled
274
+ true
275
+ end
276
+
277
+ def self.default_streaming_service_url
278
+ 'https://realtime.ably.io/event-stream'
279
+ end
280
+
281
+ def self.default_auth_service_url
282
+ 'https://auth.split-stage.io/api/auth'
283
+ end
284
+
285
+ def self.default_auth_retry_back_off_base
286
+ 1
287
+ end
288
+
289
+ def self.default_streaming_reconnect_back_off_base
290
+ 1
291
+ end
292
+
293
+ def self.init_auth_retry_back_off(auth_retry_back_off)
294
+ auth_retry_back_off < 1 ? SplitConfig.default_auth_retry_back_off_base : auth_retry_back_off
295
+ end
296
+
297
+ def self.init_streaming_reconnect_back_off(streaming_reconnect_back_off)
298
+ streaming_reconnect_back_off < 1 ? SplitConfig.default_streaming_reconnect_back_off_base : streaming_reconnect_back_off
299
+ end
260
300
 
261
301
  #
262
302
  # The default split client configuration
@@ -385,8 +425,6 @@ module SplitIoClient
385
425
  end
386
426
  end
387
427
 
388
-
389
-
390
428
  #
391
429
  # The default debug value
392
430
  #
@@ -6,6 +6,7 @@ module SplitIoClient
6
6
 
7
7
  include SplitIoClient::Cache::Repositories
8
8
  include SplitIoClient::Cache::Stores
9
+ include SplitIoClient::Cache::Senders
9
10
 
10
11
  attr_reader :adapter, :client, :manager, :config
11
12
 
@@ -29,16 +30,14 @@ module SplitIoClient
29
30
  @splits_repository = SplitsRepository.new(@config)
30
31
  @segments_repository = SegmentsRepository.new(@config)
31
32
  @impressions_repository = ImpressionsRepository.new(@config)
32
- @metrics_repository = MetricsRepository.new(@config)
33
33
  @events_repository = EventsRepository.new(@config, @api_key)
34
-
34
+ @metrics_repository = MetricsRepository.new(@config)
35
35
  @sdk_blocker = SDKBlocker.new(@splits_repository, @segments_repository, @config)
36
+ @metrics = Metrics.new(100, @metrics_repository)
36
37
 
37
- @adapter = start!
38
+ start!
38
39
 
39
- start_sse!
40
-
41
- @client = SplitClient.new(@api_key, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config, @sse_handler)
40
+ @client = SplitClient.new(@api_key, @metrics, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config)
42
41
  @manager = SplitManager.new(@splits_repository, @sdk_blocker, @config)
43
42
 
44
43
  validate_api_key
@@ -49,7 +48,11 @@ module SplitIoClient
49
48
  end
50
49
 
51
50
  def start!
52
- SplitAdapter.new(@api_key, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config)
51
+ if @config.localhost_mode
52
+ start_localhost_components
53
+ else
54
+ SplitIoClient::Engine::SyncManager.new(repositories, @api_key, @config, @sdk_blocker, @metrics).start
55
+ end
53
56
  end
54
57
 
55
58
  def stop!
@@ -118,15 +121,22 @@ module SplitIoClient
118
121
  end
119
122
  end
120
123
 
121
- def start_sse!
122
- if @config.push_notification_enabled
123
- @splits_worker = SSE::Workers::SplitsWorker.new(@adapter, @config, @splits_repository)
124
- @segments_worker = SSE::Workers::SegmentsWorker.new(@adapter, @config, @segments_repository)
125
- @control_worker = SSE::Workers::ControlWorker.new(@adapter, @config)
124
+ def repositories
125
+ repos = {}
126
+ repos[:splits] = @splits_repository
127
+ repos[:segments] = @segments_repository
128
+ repos[:impressions] = @impressions_repository
129
+ repos[:events] = @events_repository
130
+ repos[:metrics] = @metrics_repository
126
131
 
127
- options = { channels: 'mauro-c', key: 'fake_key', url_host: 'fake-url' }
128
- @sse_handler = SSE::SSEHandler.new(@config, options, @splits_worker, @segments_worker, @control_worker)
129
- end
132
+ repos
133
+ end
134
+
135
+ def start_localhost_components
136
+ LocalhostSplitStore.new(@splits_repository, @config, @sdk_blocker).call
137
+
138
+ # Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
139
+ LocalhostRepoCleaner.new(@impressions_repository, @metrics_repository, @events_repository, @config).call
130
140
  end
131
141
  end
132
142
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: false
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module EventSource
6
+ class BackOff
7
+ def initialize(back_off_base)
8
+ @attempt = 0
9
+ @back_off_base = back_off_base
10
+ end
11
+
12
+ def interval
13
+ interval = (@back_off_base * (2**@attempt)) if @attempt.positive?
14
+ @attempt += 1
15
+
16
+ interval || 0
17
+ end
18
+
19
+ def reset
20
+ @attempt = 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end