launchdarkly-server-sdk 8.11.1-java → 8.11.3-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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +66 -3
  3. data/lib/ldclient-rb/context.rb +1 -1
  4. data/lib/ldclient-rb/data_system.rb +243 -0
  5. data/lib/ldclient-rb/events.rb +35 -20
  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/null_processor.rb +52 -0
  10. data/lib/ldclient-rb/impl/data_source/polling.rb +108 -0
  11. data/lib/ldclient-rb/impl/data_source/requestor.rb +106 -0
  12. data/lib/ldclient-rb/impl/data_source/status_provider.rb +78 -0
  13. data/lib/ldclient-rb/impl/data_source/stream.rb +198 -0
  14. data/lib/ldclient-rb/impl/data_source.rb +3 -3
  15. data/lib/ldclient-rb/impl/data_store/data_kind.rb +108 -0
  16. data/lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb +187 -0
  17. data/lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb +130 -0
  18. data/lib/ldclient-rb/impl/data_store/status_provider.rb +82 -0
  19. data/lib/ldclient-rb/impl/data_store/store.rb +371 -0
  20. data/lib/ldclient-rb/impl/data_store.rb +11 -97
  21. data/lib/ldclient-rb/impl/data_system/fdv1.rb +178 -0
  22. data/lib/ldclient-rb/impl/data_system/fdv2.rb +471 -0
  23. data/lib/ldclient-rb/impl/data_system/polling.rb +601 -0
  24. data/lib/ldclient-rb/impl/data_system/protocolv2.rb +264 -0
  25. data/lib/ldclient-rb/impl/data_system.rb +298 -0
  26. data/lib/ldclient-rb/impl/dependency_tracker.rb +21 -9
  27. data/lib/ldclient-rb/impl/evaluator.rb +3 -2
  28. data/lib/ldclient-rb/impl/event_sender.rb +4 -3
  29. data/lib/ldclient-rb/impl/expiring_cache.rb +79 -0
  30. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +9 -9
  31. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +0 -1
  32. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb +288 -0
  33. data/lib/ldclient-rb/impl/memoized_value.rb +34 -0
  34. data/lib/ldclient-rb/impl/migrations/migrator.rb +2 -1
  35. data/lib/ldclient-rb/impl/migrations/tracker.rb +2 -1
  36. data/lib/ldclient-rb/impl/model/serialization.rb +6 -6
  37. data/lib/ldclient-rb/impl/non_blocking_thread_pool.rb +48 -0
  38. data/lib/ldclient-rb/impl/repeating_task.rb +2 -2
  39. data/lib/ldclient-rb/impl/simple_lru_cache.rb +27 -0
  40. data/lib/ldclient-rb/impl/util.rb +65 -0
  41. data/lib/ldclient-rb/impl.rb +1 -2
  42. data/lib/ldclient-rb/in_memory_store.rb +1 -18
  43. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +9 -9
  44. data/lib/ldclient-rb/integrations/test_data.rb +11 -11
  45. data/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +582 -0
  46. data/lib/ldclient-rb/integrations/test_data_v2.rb +248 -0
  47. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +3 -2
  48. data/lib/ldclient-rb/interfaces/data_system.rb +755 -0
  49. data/lib/ldclient-rb/interfaces/feature_store.rb +3 -0
  50. data/lib/ldclient-rb/ldclient.rb +55 -149
  51. data/lib/ldclient-rb/util.rb +11 -70
  52. data/lib/ldclient-rb/version.rb +1 -1
  53. data/lib/ldclient-rb.rb +8 -17
  54. metadata +52 -17
  55. data/lib/ldclient-rb/cache_store.rb +0 -45
  56. data/lib/ldclient-rb/expiring_cache.rb +0 -77
  57. data/lib/ldclient-rb/memoized_value.rb +0 -32
  58. data/lib/ldclient-rb/non_blocking_thread_pool.rb +0 -46
  59. data/lib/ldclient-rb/polling.rb +0 -102
  60. data/lib/ldclient-rb/requestor.rb +0 -102
  61. data/lib/ldclient-rb/simple_lru_cache.rb +0 -25
  62. data/lib/ldclient-rb/stream.rb +0 -196
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.1
4
+ version: 8.11.3
5
5
  platform: java
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-10-10 00:00:00.000000000 Z
10
+ date: 2026-01-20 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: aws-sdk-dynamodb
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '1.57'
26
+ - !ruby/object:Gem::Dependency
27
+ name: bigdecimal
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 3.1.1
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 3.1.1
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: bundler
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -283,22 +297,22 @@ dependencies:
283
297
  name: openssl
284
298
  requirement: !ruby/object:Gem::Requirement
285
299
  requirements:
286
- - - "~>"
287
- - !ruby/object:Gem::Version
288
- version: '3.1'
289
300
  - - ">="
290
301
  - !ruby/object:Gem::Version
291
302
  version: 3.1.2
303
+ - - "<"
304
+ - !ruby/object:Gem::Version
305
+ version: '5.0'
292
306
  type: :runtime
293
307
  prerelease: false
294
308
  version_requirements: !ruby/object:Gem::Requirement
295
309
  requirements:
296
- - - "~>"
297
- - !ruby/object:Gem::Version
298
- version: '3.1'
299
310
  - - ">="
300
311
  - !ruby/object:Gem::Version
301
312
  version: 3.1.2
313
+ - - "<"
314
+ - !ruby/object:Gem::Version
315
+ version: '5.0'
302
316
  - !ruby/object:Gem::Dependency
303
317
  name: semantic
304
318
  requirement: !ruby/object:Gem::Requirement
@@ -358,20 +372,35 @@ files:
358
372
  - README.md
359
373
  - lib/launchdarkly-server-sdk.rb
360
374
  - lib/ldclient-rb.rb
361
- - lib/ldclient-rb/cache_store.rb
362
375
  - lib/ldclient-rb/config.rb
363
376
  - lib/ldclient-rb/context.rb
377
+ - lib/ldclient-rb/data_system.rb
364
378
  - lib/ldclient-rb/evaluation_detail.rb
365
379
  - lib/ldclient-rb/events.rb
366
- - lib/ldclient-rb/expiring_cache.rb
367
380
  - lib/ldclient-rb/flags_state.rb
368
381
  - lib/ldclient-rb/impl.rb
369
382
  - lib/ldclient-rb/impl/big_segments.rb
370
383
  - lib/ldclient-rb/impl/broadcaster.rb
384
+ - lib/ldclient-rb/impl/cache_store.rb
371
385
  - lib/ldclient-rb/impl/context.rb
372
386
  - lib/ldclient-rb/impl/context_filter.rb
373
387
  - lib/ldclient-rb/impl/data_source.rb
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
374
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
399
+ - lib/ldclient-rb/impl/data_system.rb
400
+ - lib/ldclient-rb/impl/data_system/fdv1.rb
401
+ - lib/ldclient-rb/impl/data_system/fdv2.rb
402
+ - lib/ldclient-rb/impl/data_system/polling.rb
403
+ - lib/ldclient-rb/impl/data_system/protocolv2.rb
375
404
  - lib/ldclient-rb/impl/dependency_tracker.rb
376
405
  - lib/ldclient-rb/impl/diagnostic_events.rb
377
406
  - lib/ldclient-rb/impl/evaluation_with_hook_result.rb
@@ -382,12 +411,15 @@ files:
382
411
  - lib/ldclient-rb/impl/event_sender.rb
383
412
  - lib/ldclient-rb/impl/event_summarizer.rb
384
413
  - lib/ldclient-rb/impl/event_types.rb
414
+ - lib/ldclient-rb/impl/expiring_cache.rb
385
415
  - lib/ldclient-rb/impl/flag_tracker.rb
386
416
  - lib/ldclient-rb/impl/integrations/consul_impl.rb
387
417
  - lib/ldclient-rb/impl/integrations/dynamodb_impl.rb
388
418
  - lib/ldclient-rb/impl/integrations/file_data_source.rb
389
419
  - lib/ldclient-rb/impl/integrations/redis_impl.rb
390
420
  - lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb
421
+ - lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb
422
+ - lib/ldclient-rb/impl/memoized_value.rb
391
423
  - lib/ldclient-rb/impl/migrations/migrator.rb
392
424
  - lib/ldclient-rb/impl/migrations/tracker.rb
393
425
  - lib/ldclient-rb/impl/model/clause.rb
@@ -395,8 +427,10 @@ files:
395
427
  - lib/ldclient-rb/impl/model/preprocessed_data.rb
396
428
  - lib/ldclient-rb/impl/model/segment.rb
397
429
  - lib/ldclient-rb/impl/model/serialization.rb
430
+ - lib/ldclient-rb/impl/non_blocking_thread_pool.rb
398
431
  - lib/ldclient-rb/impl/repeating_task.rb
399
432
  - lib/ldclient-rb/impl/sampler.rb
433
+ - lib/ldclient-rb/impl/simple_lru_cache.rb
400
434
  - lib/ldclient-rb/impl/store_client_wrapper.rb
401
435
  - lib/ldclient-rb/impl/store_data_set_sorter.rb
402
436
  - lib/ldclient-rb/impl/unbounded_pool.rb
@@ -409,31 +443,32 @@ files:
409
443
  - lib/ldclient-rb/integrations/redis.rb
410
444
  - lib/ldclient-rb/integrations/test_data.rb
411
445
  - lib/ldclient-rb/integrations/test_data/flag_builder.rb
446
+ - lib/ldclient-rb/integrations/test_data_v2.rb
447
+ - lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb
412
448
  - lib/ldclient-rb/integrations/util/store_wrapper.rb
413
449
  - lib/ldclient-rb/interfaces.rb
414
450
  - lib/ldclient-rb/interfaces/big_segment_store.rb
415
451
  - lib/ldclient-rb/interfaces/data_source.rb
416
452
  - lib/ldclient-rb/interfaces/data_store.rb
453
+ - lib/ldclient-rb/interfaces/data_system.rb
417
454
  - lib/ldclient-rb/interfaces/feature_store.rb
418
455
  - lib/ldclient-rb/interfaces/flag_tracker.rb
419
456
  - lib/ldclient-rb/interfaces/hooks.rb
420
457
  - lib/ldclient-rb/interfaces/migrations.rb
421
458
  - lib/ldclient-rb/interfaces/plugins.rb
422
459
  - lib/ldclient-rb/ldclient.rb
423
- - lib/ldclient-rb/memoized_value.rb
424
460
  - lib/ldclient-rb/migrations.rb
425
- - lib/ldclient-rb/non_blocking_thread_pool.rb
426
- - lib/ldclient-rb/polling.rb
427
461
  - lib/ldclient-rb/reference.rb
428
- - lib/ldclient-rb/requestor.rb
429
- - lib/ldclient-rb/simple_lru_cache.rb
430
- - lib/ldclient-rb/stream.rb
431
462
  - lib/ldclient-rb/util.rb
432
463
  - lib/ldclient-rb/version.rb
433
464
  homepage: https://github.com/launchdarkly/ruby-server-sdk
434
465
  licenses:
435
466
  - Apache-2.0
436
- metadata: {}
467
+ metadata:
468
+ bug_tracker_uri: https://github.com/launchdarkly/ruby-server-sdk/issues
469
+ changelog_uri: https://github.com/launchdarkly/ruby-server-sdk/blob/main/CHANGELOG.md
470
+ homepage_uri: https://github.com/launchdarkly/ruby-server-sdk
471
+ source_code_uri: https://github.com/launchdarkly/ruby-server-sdk
437
472
  rdoc_options: []
438
473
  require_paths:
439
474
  - 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