launchdarkly-server-sdk 8.11.2-java → 8.12.0-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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +69 -9
  3. data/lib/ldclient-rb/context.rb +1 -1
  4. data/lib/ldclient-rb/data_system.rb +227 -0
  5. data/lib/ldclient-rb/events.rb +34 -19
  6. data/lib/ldclient-rb/flags_state.rb +1 -1
  7. data/lib/ldclient-rb/impl/big_segments.rb +4 -4
  8. data/lib/ldclient-rb/impl/cache_store.rb +44 -0
  9. data/lib/ldclient-rb/impl/data_source/polling.rb +108 -0
  10. data/lib/ldclient-rb/impl/data_source/requestor.rb +113 -0
  11. data/lib/ldclient-rb/impl/data_source/status_provider.rb +83 -0
  12. data/lib/ldclient-rb/impl/data_source/stream.rb +198 -0
  13. data/lib/ldclient-rb/impl/data_source.rb +3 -3
  14. data/lib/ldclient-rb/impl/data_store/data_kind.rb +108 -0
  15. data/lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb +187 -0
  16. data/lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb +130 -0
  17. data/lib/ldclient-rb/impl/data_store/status_provider.rb +76 -0
  18. data/lib/ldclient-rb/impl/data_store/store.rb +371 -0
  19. data/lib/ldclient-rb/impl/data_store.rb +11 -97
  20. data/lib/ldclient-rb/impl/data_system/data_source_builder_common.rb +77 -0
  21. data/lib/ldclient-rb/impl/data_system/fdv1.rb +20 -7
  22. data/lib/ldclient-rb/impl/data_system/fdv2.rb +472 -0
  23. data/lib/ldclient-rb/impl/data_system/http_config_options.rb +32 -0
  24. data/lib/ldclient-rb/impl/data_system/polling.rb +628 -0
  25. data/lib/ldclient-rb/impl/data_system/protocolv2.rb +264 -0
  26. data/lib/ldclient-rb/impl/data_system/streaming.rb +401 -0
  27. data/lib/ldclient-rb/impl/dependency_tracker.rb +21 -9
  28. data/lib/ldclient-rb/impl/evaluator.rb +3 -2
  29. data/lib/ldclient-rb/impl/event_sender.rb +14 -6
  30. data/lib/ldclient-rb/impl/expiring_cache.rb +79 -0
  31. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
  32. data/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb +460 -0
  33. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb +290 -0
  34. data/lib/ldclient-rb/impl/memoized_value.rb +34 -0
  35. data/lib/ldclient-rb/impl/migrations/migrator.rb +2 -1
  36. data/lib/ldclient-rb/impl/migrations/tracker.rb +2 -1
  37. data/lib/ldclient-rb/impl/model/serialization.rb +6 -6
  38. data/lib/ldclient-rb/impl/non_blocking_thread_pool.rb +48 -0
  39. data/lib/ldclient-rb/impl/repeating_task.rb +2 -2
  40. data/lib/ldclient-rb/impl/simple_lru_cache.rb +27 -0
  41. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +1 -1
  42. data/lib/ldclient-rb/impl/util.rb +71 -0
  43. data/lib/ldclient-rb/impl.rb +1 -2
  44. data/lib/ldclient-rb/in_memory_store.rb +1 -18
  45. data/lib/ldclient-rb/integrations/file_data.rb +67 -0
  46. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +9 -9
  47. data/lib/ldclient-rb/integrations/test_data.rb +11 -11
  48. data/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +582 -0
  49. data/lib/ldclient-rb/integrations/test_data_v2.rb +254 -0
  50. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +3 -2
  51. data/lib/ldclient-rb/interfaces/data_system.rb +704 -0
  52. data/lib/ldclient-rb/interfaces/feature_store.rb +5 -2
  53. data/lib/ldclient-rb/ldclient.rb +66 -132
  54. data/lib/ldclient-rb/util.rb +11 -70
  55. data/lib/ldclient-rb/version.rb +1 -1
  56. data/lib/ldclient-rb.rb +9 -17
  57. metadata +41 -19
  58. data/lib/ldclient-rb/cache_store.rb +0 -45
  59. data/lib/ldclient-rb/expiring_cache.rb +0 -77
  60. data/lib/ldclient-rb/memoized_value.rb +0 -32
  61. data/lib/ldclient-rb/non_blocking_thread_pool.rb +0 -46
  62. data/lib/ldclient-rb/polling.rb +0 -102
  63. data/lib/ldclient-rb/requestor.rb +0 -102
  64. data/lib/ldclient-rb/simple_lru_cache.rb +0 -25
  65. data/lib/ldclient-rb/stream.rb +0 -197
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: launchdarkly-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.11.2
4
+ version: 8.12.0
5
5
  platform: java
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-12-05 00:00:00.000000000 Z
10
+ date: 2026-01-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: aws-sdk-dynamodb
@@ -271,14 +271,14 @@ dependencies:
271
271
  requirements:
272
272
  - - '='
273
273
  - !ruby/object:Gem::Version
274
- version: 2.2.6
274
+ version: 2.5.0
275
275
  type: :runtime
276
276
  prerelease: false
277
277
  version_requirements: !ruby/object:Gem::Requirement
278
278
  requirements:
279
279
  - - '='
280
280
  - !ruby/object:Gem::Version
281
- version: 2.2.6
281
+ version: 2.5.0
282
282
  - !ruby/object:Gem::Dependency
283
283
  name: observer
284
284
  requirement: !ruby/object:Gem::Requirement
@@ -297,22 +297,22 @@ dependencies:
297
297
  name: openssl
298
298
  requirement: !ruby/object:Gem::Requirement
299
299
  requirements:
300
- - - "~>"
301
- - !ruby/object:Gem::Version
302
- version: '3.1'
303
300
  - - ">="
304
301
  - !ruby/object:Gem::Version
305
302
  version: 3.1.2
303
+ - - "<"
304
+ - !ruby/object:Gem::Version
305
+ version: '5.0'
306
306
  type: :runtime
307
307
  prerelease: false
308
308
  version_requirements: !ruby/object:Gem::Requirement
309
309
  requirements:
310
- - - "~>"
311
- - !ruby/object:Gem::Version
312
- version: '3.1'
313
310
  - - ">="
314
311
  - !ruby/object:Gem::Version
315
312
  version: 3.1.2
313
+ - - "<"
314
+ - !ruby/object:Gem::Version
315
+ version: '5.0'
316
316
  - !ruby/object:Gem::Dependency
317
317
  name: semantic
318
318
  requirement: !ruby/object:Gem::Requirement
@@ -372,23 +372,38 @@ files:
372
372
  - README.md
373
373
  - lib/launchdarkly-server-sdk.rb
374
374
  - lib/ldclient-rb.rb
375
- - lib/ldclient-rb/cache_store.rb
376
375
  - lib/ldclient-rb/config.rb
377
376
  - lib/ldclient-rb/context.rb
377
+ - lib/ldclient-rb/data_system.rb
378
378
  - lib/ldclient-rb/evaluation_detail.rb
379
379
  - lib/ldclient-rb/events.rb
380
- - lib/ldclient-rb/expiring_cache.rb
381
380
  - lib/ldclient-rb/flags_state.rb
382
381
  - lib/ldclient-rb/impl.rb
383
382
  - lib/ldclient-rb/impl/big_segments.rb
384
383
  - lib/ldclient-rb/impl/broadcaster.rb
384
+ - lib/ldclient-rb/impl/cache_store.rb
385
385
  - lib/ldclient-rb/impl/context.rb
386
386
  - lib/ldclient-rb/impl/context_filter.rb
387
387
  - lib/ldclient-rb/impl/data_source.rb
388
388
  - lib/ldclient-rb/impl/data_source/null_processor.rb
389
+ - lib/ldclient-rb/impl/data_source/polling.rb
390
+ - lib/ldclient-rb/impl/data_source/requestor.rb
391
+ - lib/ldclient-rb/impl/data_source/status_provider.rb
392
+ - lib/ldclient-rb/impl/data_source/stream.rb
389
393
  - lib/ldclient-rb/impl/data_store.rb
394
+ - lib/ldclient-rb/impl/data_store/data_kind.rb
395
+ - lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb
396
+ - lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb
397
+ - lib/ldclient-rb/impl/data_store/status_provider.rb
398
+ - lib/ldclient-rb/impl/data_store/store.rb
390
399
  - lib/ldclient-rb/impl/data_system.rb
400
+ - lib/ldclient-rb/impl/data_system/data_source_builder_common.rb
391
401
  - lib/ldclient-rb/impl/data_system/fdv1.rb
402
+ - lib/ldclient-rb/impl/data_system/fdv2.rb
403
+ - lib/ldclient-rb/impl/data_system/http_config_options.rb
404
+ - lib/ldclient-rb/impl/data_system/polling.rb
405
+ - lib/ldclient-rb/impl/data_system/protocolv2.rb
406
+ - lib/ldclient-rb/impl/data_system/streaming.rb
392
407
  - lib/ldclient-rb/impl/dependency_tracker.rb
393
408
  - lib/ldclient-rb/impl/diagnostic_events.rb
394
409
  - lib/ldclient-rb/impl/evaluation_with_hook_result.rb
@@ -399,12 +414,16 @@ files:
399
414
  - lib/ldclient-rb/impl/event_sender.rb
400
415
  - lib/ldclient-rb/impl/event_summarizer.rb
401
416
  - lib/ldclient-rb/impl/event_types.rb
417
+ - lib/ldclient-rb/impl/expiring_cache.rb
402
418
  - lib/ldclient-rb/impl/flag_tracker.rb
403
419
  - lib/ldclient-rb/impl/integrations/consul_impl.rb
404
420
  - lib/ldclient-rb/impl/integrations/dynamodb_impl.rb
405
421
  - lib/ldclient-rb/impl/integrations/file_data_source.rb
422
+ - lib/ldclient-rb/impl/integrations/file_data_source_v2.rb
406
423
  - lib/ldclient-rb/impl/integrations/redis_impl.rb
407
424
  - lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb
425
+ - lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb
426
+ - lib/ldclient-rb/impl/memoized_value.rb
408
427
  - lib/ldclient-rb/impl/migrations/migrator.rb
409
428
  - lib/ldclient-rb/impl/migrations/tracker.rb
410
429
  - lib/ldclient-rb/impl/model/clause.rb
@@ -412,8 +431,10 @@ files:
412
431
  - lib/ldclient-rb/impl/model/preprocessed_data.rb
413
432
  - lib/ldclient-rb/impl/model/segment.rb
414
433
  - lib/ldclient-rb/impl/model/serialization.rb
434
+ - lib/ldclient-rb/impl/non_blocking_thread_pool.rb
415
435
  - lib/ldclient-rb/impl/repeating_task.rb
416
436
  - lib/ldclient-rb/impl/sampler.rb
437
+ - lib/ldclient-rb/impl/simple_lru_cache.rb
417
438
  - lib/ldclient-rb/impl/store_client_wrapper.rb
418
439
  - lib/ldclient-rb/impl/store_data_set_sorter.rb
419
440
  - lib/ldclient-rb/impl/unbounded_pool.rb
@@ -426,31 +447,32 @@ files:
426
447
  - lib/ldclient-rb/integrations/redis.rb
427
448
  - lib/ldclient-rb/integrations/test_data.rb
428
449
  - lib/ldclient-rb/integrations/test_data/flag_builder.rb
450
+ - lib/ldclient-rb/integrations/test_data_v2.rb
451
+ - lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb
429
452
  - lib/ldclient-rb/integrations/util/store_wrapper.rb
430
453
  - lib/ldclient-rb/interfaces.rb
431
454
  - lib/ldclient-rb/interfaces/big_segment_store.rb
432
455
  - lib/ldclient-rb/interfaces/data_source.rb
433
456
  - lib/ldclient-rb/interfaces/data_store.rb
457
+ - lib/ldclient-rb/interfaces/data_system.rb
434
458
  - lib/ldclient-rb/interfaces/feature_store.rb
435
459
  - lib/ldclient-rb/interfaces/flag_tracker.rb
436
460
  - lib/ldclient-rb/interfaces/hooks.rb
437
461
  - lib/ldclient-rb/interfaces/migrations.rb
438
462
  - lib/ldclient-rb/interfaces/plugins.rb
439
463
  - lib/ldclient-rb/ldclient.rb
440
- - lib/ldclient-rb/memoized_value.rb
441
464
  - lib/ldclient-rb/migrations.rb
442
- - lib/ldclient-rb/non_blocking_thread_pool.rb
443
- - lib/ldclient-rb/polling.rb
444
465
  - lib/ldclient-rb/reference.rb
445
- - lib/ldclient-rb/requestor.rb
446
- - lib/ldclient-rb/simple_lru_cache.rb
447
- - lib/ldclient-rb/stream.rb
448
466
  - lib/ldclient-rb/util.rb
449
467
  - lib/ldclient-rb/version.rb
450
468
  homepage: https://github.com/launchdarkly/ruby-server-sdk
451
469
  licenses:
452
470
  - Apache-2.0
453
- metadata: {}
471
+ metadata:
472
+ bug_tracker_uri: https://github.com/launchdarkly/ruby-server-sdk/issues
473
+ changelog_uri: https://github.com/launchdarkly/ruby-server-sdk/blob/main/CHANGELOG.md
474
+ homepage_uri: https://github.com/launchdarkly/ruby-server-sdk
475
+ source_code_uri: https://github.com/launchdarkly/ruby-server-sdk
454
476
  rdoc_options: []
455
477
  require_paths:
456
478
  - lib
@@ -1,45 +0,0 @@
1
- require "concurrent/map"
2
-
3
- module LaunchDarkly
4
- #
5
- # A thread-safe in-memory store that uses the same semantics that Faraday would expect, although we
6
- # no longer use Faraday. This is used by Requestor, when we are not in a Rails environment.
7
- #
8
- # @private
9
- #
10
- class ThreadSafeMemoryStore
11
- #
12
- # Default constructor
13
- #
14
- # @return [ThreadSafeMemoryStore] a new store
15
- def initialize
16
- @cache = Concurrent::Map.new
17
- end
18
-
19
- #
20
- # Read a value from the cache
21
- # @param key [Object] the cache key
22
- #
23
- # @return [Object] the cache value
24
- def read(key)
25
- @cache[key]
26
- end
27
-
28
- #
29
- # Store a value in the cache
30
- # @param key [Object] the cache key
31
- # @param value [Object] the value to associate with the key
32
- #
33
- # @return [Object] the value
34
- def write(key, value)
35
- @cache[key] = value
36
- end
37
-
38
- #
39
- # Delete a value in the cache
40
- # @param key [Object] the cache key
41
- def delete(key)
42
- @cache.delete(key)
43
- end
44
- end
45
- end
@@ -1,77 +0,0 @@
1
-
2
- module LaunchDarkly
3
- # A thread-safe cache with maximum number of entries and TTL.
4
- # Adapted from https://github.com/SamSaffron/lru_redux/blob/master/lib/lru_redux/ttl/cache.rb
5
- # under MIT license with the following changes:
6
- # * made thread-safe
7
- # * removed many unused methods
8
- # * reading a key does not reset its expiration time, only writing
9
- # @private
10
- class ExpiringCache
11
- def initialize(max_size, ttl)
12
- @max_size = max_size
13
- @ttl = ttl
14
- @data_lru = {}
15
- @data_ttl = {}
16
- @lock = Mutex.new
17
- end
18
-
19
- def [](key)
20
- @lock.synchronize do
21
- ttl_evict
22
- @data_lru[key]
23
- end
24
- end
25
-
26
- def []=(key, val)
27
- @lock.synchronize do
28
- ttl_evict
29
-
30
- @data_lru.delete(key)
31
- @data_ttl.delete(key)
32
-
33
- @data_lru[key] = val
34
- @data_ttl[key] = Time.now.to_f
35
-
36
- if @data_lru.size > @max_size
37
- key, _ = @data_lru.first # hashes have a FIFO ordering in Ruby
38
-
39
- @data_ttl.delete(key)
40
- @data_lru.delete(key)
41
- end
42
-
43
- val
44
- end
45
- end
46
-
47
- def delete(key)
48
- @lock.synchronize do
49
- ttl_evict
50
-
51
- @data_lru.delete(key)
52
- @data_ttl.delete(key)
53
- end
54
- end
55
-
56
- def clear
57
- @lock.synchronize do
58
- @data_lru.clear
59
- @data_ttl.clear
60
- end
61
- end
62
-
63
- private
64
-
65
- def ttl_evict
66
- ttl_horizon = Time.now.to_f - @ttl
67
- key, time = @data_ttl.first
68
-
69
- until time.nil? || time > ttl_horizon
70
- @data_ttl.delete(key)
71
- @data_lru.delete(key)
72
-
73
- key, time = @data_ttl.first
74
- end
75
- end
76
- end
77
- end
@@ -1,32 +0,0 @@
1
-
2
- module LaunchDarkly
3
- # Simple implementation of a thread-safe memoized value whose generator function will never be
4
- # run more than once, and whose value can be overridden by explicit assignment.
5
- # Note that we no longer use this class and it will be removed in a future version.
6
- # @private
7
- class MemoizedValue
8
- def initialize(&generator)
9
- @generator = generator
10
- @mutex = Mutex.new
11
- @inited = false
12
- @value = nil
13
- end
14
-
15
- def get
16
- @mutex.synchronize do
17
- unless @inited
18
- @value = @generator.call
19
- @inited = true
20
- end
21
- end
22
- @value
23
- end
24
-
25
- def set(value)
26
- @mutex.synchronize do
27
- @value = value
28
- @inited = true
29
- end
30
- end
31
- end
32
- end
@@ -1,46 +0,0 @@
1
- require "concurrent"
2
- require "concurrent/atomics"
3
- require "concurrent/executors"
4
- require "thread"
5
-
6
- module LaunchDarkly
7
- # Simple wrapper for a FixedThreadPool that rejects new jobs if all the threads are busy, rather
8
- # than blocking. Also provides a way to wait for all jobs to finish without shutting down.
9
- # @private
10
- class NonBlockingThreadPool
11
- def initialize(capacity, name = 'LD/NonBlockingThreadPool')
12
- @capacity = capacity
13
- @pool = Concurrent::FixedThreadPool.new(capacity, name: name)
14
- @semaphore = Concurrent::Semaphore.new(capacity)
15
- end
16
-
17
- # Attempts to submit a job, but only if a worker is available. Unlike the regular post method,
18
- # this returns a value: true if the job was submitted, false if all workers are busy.
19
- def post
20
- unless @semaphore.try_acquire(1)
21
- return
22
- end
23
- @pool.post do
24
- begin
25
- yield
26
- ensure
27
- @semaphore.release(1)
28
- end
29
- end
30
- end
31
-
32
- # Waits until no jobs are executing, without shutting down the pool.
33
- def wait_all
34
- @semaphore.acquire(@capacity)
35
- @semaphore.release(@capacity)
36
- end
37
-
38
- def shutdown
39
- @pool.shutdown
40
- end
41
-
42
- def wait_for_termination
43
- @pool.wait_for_termination
44
- end
45
- end
46
- end
@@ -1,102 +0,0 @@
1
- require "ldclient-rb/impl/repeating_task"
2
-
3
- require "concurrent/atomics"
4
- require "json"
5
- require "thread"
6
-
7
- module LaunchDarkly
8
- # @private
9
- class PollingProcessor
10
- def initialize(config, requestor)
11
- @config = config
12
- @requestor = requestor
13
- @initialized = Concurrent::AtomicBoolean.new(false)
14
- @started = Concurrent::AtomicBoolean.new(false)
15
- @ready = Concurrent::Event.new
16
- @task = Impl::RepeatingTask.new(@config.poll_interval, 0, -> { self.poll }, @config.logger, 'LD/PollingDataSource')
17
- end
18
-
19
- def initialized?
20
- @initialized.value
21
- end
22
-
23
- def start
24
- return @ready unless @started.make_true
25
- @config.logger.info { "[LDClient] Initializing polling connection" }
26
- @task.start
27
- @ready
28
- end
29
-
30
- def stop
31
- stop_with_error_info
32
- end
33
-
34
- def poll
35
- begin
36
- all_data = @requestor.request_all_data
37
- if all_data
38
- update_sink_or_data_store.init(all_data)
39
- if @initialized.make_true
40
- @config.logger.info { "[LDClient] Polling connection initialized" }
41
- @ready.set
42
- end
43
- end
44
- @config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::VALID, nil)
45
- rescue JSON::ParserError => e
46
- @config.logger.error { "[LDClient] JSON parsing failed for polling response." }
47
- error_info = LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
48
- LaunchDarkly::Interfaces::DataSource::ErrorInfo::INVALID_DATA,
49
- 0,
50
- e.to_s,
51
- Time.now
52
- )
53
- @config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED, error_info)
54
- rescue UnexpectedResponseError => e
55
- error_info = LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
56
- LaunchDarkly::Interfaces::DataSource::ErrorInfo::ERROR_RESPONSE, e.status, nil, Time.now)
57
- message = Util.http_error_message(e.status, "polling request", "will retry")
58
- @config.logger.error { "[LDClient] #{message}" }
59
-
60
- if Util.http_error_recoverable?(e.status)
61
- @config.data_source_update_sink&.update_status(
62
- LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED,
63
- error_info
64
- )
65
- else
66
- @ready.set # if client was waiting on us, make it stop waiting - has no effect if already set
67
- stop_with_error_info error_info
68
- end
69
- rescue StandardError => e
70
- Util.log_exception(@config.logger, "Exception while polling", e)
71
- @config.data_source_update_sink&.update_status(
72
- LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED,
73
- LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(LaunchDarkly::Interfaces::DataSource::ErrorInfo::UNKNOWN, 0, e.to_s, Time.now)
74
- )
75
- end
76
- end
77
-
78
- #
79
- # The original implementation of this class relied on the feature store
80
- # directly, which we are trying to move away from. Customers who might have
81
- # instantiated this directly for some reason wouldn't know they have to set
82
- # the config's sink manually, so we have to fall back to the store if the
83
- # sink isn't present.
84
- #
85
- # The next major release should be able to simplify this structure and
86
- # remove the need for fall back to the data store because the update sink
87
- # should always be present.
88
- #
89
- private def update_sink_or_data_store
90
- @config.data_source_update_sink || @config.feature_store
91
- end
92
-
93
- #
94
- # @param [LaunchDarkly::Interfaces::DataSource::ErrorInfo, nil] error_info
95
- #
96
- private def stop_with_error_info(error_info = nil)
97
- @task.stop
98
- @config.logger.info { "[LDClient] Polling connection stopped" }
99
- @config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::OFF, error_info)
100
- end
101
- end
102
- end
@@ -1,102 +0,0 @@
1
- require "ldclient-rb/impl/model/serialization"
2
-
3
- require "concurrent/atomics"
4
- require "json"
5
- require "uri"
6
- require "http"
7
-
8
- module LaunchDarkly
9
- # @private
10
- class UnexpectedResponseError < StandardError
11
- def initialize(status)
12
- @status = status
13
- super("HTTP error #{status}")
14
- end
15
-
16
- def status
17
- @status
18
- end
19
- end
20
-
21
- # @private
22
- class Requestor
23
- CacheEntry = Struct.new(:etag, :body)
24
-
25
- def initialize(sdk_key, config)
26
- @sdk_key = sdk_key
27
- @config = config
28
- @http_client = LaunchDarkly::Util.new_http_client(config.base_uri, config)
29
- .use(:auto_inflate)
30
- .headers("Accept-Encoding" => "gzip")
31
- @cache = @config.cache_store
32
- end
33
-
34
- def request_all_data()
35
- all_data = JSON.parse(make_request("/sdk/latest-all"), symbolize_names: true)
36
- Impl::Model.make_all_store_data(all_data, @config.logger)
37
- end
38
-
39
- def stop
40
- begin
41
- @http_client.close
42
- rescue
43
- end
44
- end
45
-
46
- private
47
-
48
- def make_request(path)
49
- uri = URI(
50
- Util.add_payload_filter_key(@config.base_uri + path, @config)
51
- )
52
- headers = {}
53
- Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| headers[k] = v }
54
- headers["Connection"] = "keep-alive"
55
- cached = @cache.read(uri)
56
- unless cached.nil?
57
- headers["If-None-Match"] = cached.etag
58
- end
59
- response = @http_client.request("GET", uri, {
60
- headers: headers,
61
- })
62
- status = response.status.code
63
- # must fully read body for persistent connections
64
- body = response.to_s
65
- @config.logger.debug { "[LDClient] Got response from uri: #{uri}\n\tstatus code: #{status}\n\theaders: #{response.headers.to_h}\n\tbody: #{body}" }
66
- if status == 304 && !cached.nil?
67
- body = cached.body
68
- else
69
- @cache.delete(uri)
70
- if status < 200 || status >= 300
71
- raise UnexpectedResponseError.new(status)
72
- end
73
- body = fix_encoding(body, response.headers["content-type"])
74
- etag = response.headers["etag"]
75
- @cache.write(uri, CacheEntry.new(etag, body)) unless etag.nil?
76
- end
77
- body
78
- end
79
-
80
- def fix_encoding(body, content_type)
81
- return body if content_type.nil?
82
- media_type, charset = parse_content_type(content_type)
83
- return body if charset.nil?
84
- body.force_encoding(Encoding::find(charset)).encode(Encoding::UTF_8)
85
- end
86
-
87
- def parse_content_type(value)
88
- return [nil, nil] if value.nil? || value == ''
89
- parts = value.split(/; */)
90
- return [value, nil] if parts.count < 2
91
- charset = nil
92
- parts.each do |part|
93
- fields = part.split('=')
94
- if fields.count >= 2 && fields[0] == 'charset'
95
- charset = fields[1]
96
- break
97
- end
98
- end
99
- [parts[0], charset]
100
- end
101
- end
102
- end
@@ -1,25 +0,0 @@
1
-
2
- module LaunchDarkly
3
- # A non-thread-safe implementation of a LRU cache set with only add and reset methods.
4
- # Based on https://github.com/SamSaffron/lru_redux/blob/master/lib/lru_redux/cache.rb
5
- # @private
6
- class SimpleLRUCacheSet
7
- def initialize(capacity)
8
- @values = {}
9
- @capacity = capacity
10
- end
11
-
12
- # Adds a value to the cache or marks it recent if it was already there. Returns true if already there.
13
- def add(value)
14
- found = true
15
- @values.delete(value) { found = false }
16
- @values[value] = true
17
- @values.shift if @values.length > @capacity
18
- found
19
- end
20
-
21
- def clear
22
- @values = {}
23
- end
24
- end
25
- end