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.
Files changed (210) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/pull_request_template.md +9 -0
  4. data/.github/workflows/ci.yml +90 -0
  5. data/.github/workflows/update-license-year.yml +45 -0
  6. data/.gitignore +20 -0
  7. data/.rubocop.yml +76 -0
  8. data/.simplecov +1 -0
  9. data/CHANGES.txt +361 -2
  10. data/CONTRIBUTORS-GUIDE.md +49 -0
  11. data/Gemfile +2 -0
  12. data/LICENSE +3 -36
  13. data/NOTICE.txt +5 -0
  14. data/README.md +59 -127
  15. data/Rakefile +27 -3
  16. data/ext/murmurhash/MurmurHash3.java +302 -0
  17. data/gemfiles/faraday_after_0.13.gemfile +7 -0
  18. data/gemfiles/faraday_before_0.13.gemfile +8 -0
  19. data/lib/murmurhash/base.rb +58 -0
  20. data/lib/murmurhash/murmurhash.jar +0 -0
  21. data/lib/murmurhash/murmurhash_mri.rb +3 -0
  22. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +130 -0
  23. data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
  24. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +137 -0
  25. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +53 -0
  26. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +178 -0
  27. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  28. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  29. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  30. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  31. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  32. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  33. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  34. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  35. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +45 -0
  36. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +35 -0
  37. data/lib/splitclient-rb/cache/repositories/events_repository.rb +61 -0
  38. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  39. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  40. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +56 -0
  41. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +57 -0
  42. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +23 -0
  43. data/lib/splitclient-rb/cache/repositories/repository.rb +24 -0
  44. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  45. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +124 -0
  46. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +296 -0
  47. data/lib/splitclient-rb/cache/routers/impression_router.rb +60 -0
  48. data/lib/splitclient-rb/cache/senders/events_sender.rb +42 -0
  49. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  50. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  51. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  52. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +95 -0
  53. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +52 -0
  54. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  55. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  56. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  57. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  58. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  59. data/lib/splitclient-rb/clients/split_client.rb +530 -0
  60. data/lib/splitclient-rb/constants.rb +16 -0
  61. data/lib/splitclient-rb/engine/api/client.rb +87 -0
  62. data/lib/splitclient-rb/engine/api/events.rb +57 -0
  63. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +58 -0
  64. data/lib/splitclient-rb/engine/api/impressions.rb +79 -0
  65. data/lib/splitclient-rb/engine/api/segments.rb +78 -0
  66. data/lib/splitclient-rb/engine/api/splits.rb +139 -0
  67. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  68. data/lib/splitclient-rb/engine/auth_api_client.rb +100 -0
  69. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  70. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  71. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  72. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  73. data/lib/{splitclient-engine → splitclient-rb/engine}/evaluator/splitter.rb +35 -22
  74. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  75. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  76. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  77. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  78. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  79. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  80. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  81. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  82. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/all_keys_matcher.rb +10 -21
  83. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +47 -0
  84. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  85. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/combiners.rb +4 -6
  86. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +80 -0
  87. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +20 -0
  88. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +16 -0
  89. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +43 -0
  90. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +26 -0
  91. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +42 -0
  92. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +37 -0
  93. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +44 -0
  94. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  95. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +16 -0
  96. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +43 -0
  97. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  98. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  99. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +43 -0
  100. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  101. data/lib/splitclient-rb/engine/matchers/matcher.rb +52 -0
  102. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +29 -0
  103. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +47 -0
  104. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +22 -0
  105. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  106. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  107. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  108. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +27 -0
  109. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +40 -0
  110. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +28 -0
  111. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
  112. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +66 -0
  113. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  114. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  116. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  117. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  118. data/lib/splitclient-rb/engine/models/label.rb +10 -0
  119. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  120. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  121. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  122. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +16 -0
  123. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  124. data/lib/splitclient-rb/engine/models/split.rb +17 -0
  125. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  126. data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
  127. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  128. data/lib/splitclient-rb/engine/parser/condition.rb +271 -0
  129. data/lib/splitclient-rb/engine/parser/evaluator.rb +112 -0
  130. data/lib/{splitclient-engine → splitclient-rb/engine}/parser/partition.rb +2 -4
  131. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  132. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  133. data/lib/splitclient-rb/engine/sync_manager.rb +183 -0
  134. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  135. data/lib/splitclient-rb/exceptions.rb +26 -0
  136. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  137. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  138. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  139. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  140. data/lib/splitclient-rb/helpers/util.rb +26 -0
  141. data/lib/splitclient-rb/managers/split_manager.rb +121 -0
  142. data/lib/splitclient-rb/spec.rb +9 -0
  143. data/lib/splitclient-rb/split_config.rb +591 -47
  144. data/lib/splitclient-rb/split_factory.rb +284 -0
  145. data/lib/splitclient-rb/split_factory_builder.rb +7 -0
  146. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  147. data/lib/splitclient-rb/split_logger.rb +23 -0
  148. data/lib/splitclient-rb/sse/event_source/client.rb +264 -0
  149. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  150. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  151. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  152. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  153. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  154. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  155. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  156. data/lib/splitclient-rb/sse/workers/splits_worker.rb +153 -0
  157. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  158. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  159. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  160. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  161. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  162. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  163. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  164. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  165. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  166. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  167. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  168. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  169. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  170. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  171. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  172. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  173. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  174. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  175. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  176. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  177. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  178. data/lib/splitclient-rb/utilitites.rb +49 -0
  179. data/lib/splitclient-rb/validators.rb +361 -0
  180. data/lib/splitclient-rb/version.rb +1 -1
  181. data/lib/splitclient-rb.rb +177 -25
  182. data/sonar-project.properties +6 -0
  183. data/splitclient-rb.gemspec +53 -26
  184. data/tasks/benchmark_get_treatment.rake +31 -17
  185. data/tasks/irb.rake +6 -0
  186. metadata +411 -86
  187. data/NEWS +0 -9
  188. data/lib/splitclient-cache/local_store.rb +0 -45
  189. data/lib/splitclient-engine/impressions/impressions.rb +0 -79
  190. data/lib/splitclient-engine/matchers/between_matcher.rb +0 -48
  191. data/lib/splitclient-engine/matchers/combining_matcher.rb +0 -94
  192. data/lib/splitclient-engine/matchers/equal_to_matcher.rb +0 -48
  193. data/lib/splitclient-engine/matchers/greater_than_or_equal_to_matcher.rb +0 -48
  194. data/lib/splitclient-engine/matchers/less_than_or_equal_to_matcher.rb +0 -48
  195. data/lib/splitclient-engine/matchers/negation_matcher.rb +0 -54
  196. data/lib/splitclient-engine/matchers/user_defined_segment_matcher.rb +0 -61
  197. data/lib/splitclient-engine/matchers/whitelist_matcher.rb +0 -64
  198. data/lib/splitclient-engine/metrics/binary_search_latency_tracker.rb +0 -122
  199. data/lib/splitclient-engine/metrics/metrics.rb +0 -158
  200. data/lib/splitclient-engine/parser/condition.rb +0 -143
  201. data/lib/splitclient-engine/parser/segment.rb +0 -84
  202. data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
  203. data/lib/splitclient-engine/parser/split.rb +0 -68
  204. data/lib/splitclient-engine/parser/split_adapter.rb +0 -433
  205. data/lib/splitclient-engine/parser/split_parser.rb +0 -139
  206. data/lib/splitclient-engine/partitions/treatments.rb +0 -40
  207. data/lib/splitclient-rb/split_client.rb +0 -156
  208. data/lib/splitclient-rb_utilitites.rb +0 -26
  209. data/tasks/console.rake +0 -4
  210. data/tasks/rspec.rake +0 -3
@@ -12,77 +12,369 @@ module SplitIoClient
12
12
  #
13
13
  # @param opts [Hash] optional hash with configuration options
14
14
  # @option opts [String] :base_uri ("https://sdk.split.io/api/") The base URL for split API end points
15
+ # @option opts [String] :events_uri ("https://events.split.io/api/") The events URL for events end points
15
16
  # @option opts [Int] :read_timeout (10) The read timeout for network connections in seconds.
16
17
  # @option opts [Int] :connection_timeout (2) The connect timeout for network connections in seconds.
17
- # @option opts [Object] :local_store A cache store for the Faraday HTTP caching library. Defaults to the Rails cache in a Rails environment, or a thread-safe in-memory store otherwise.
18
18
  # @option opts [Int] :features_refresh_rate The SDK polls Split servers for changes to feature roll-out plans. This parameter controls this polling period in seconds.
19
19
  # @option opts [Int] :segments_refresh_rate
20
- # @option opts [Int] :metrics_refresh_rate
21
20
  # @option opts [Int] :impressions_refresh_rate
22
21
  # @option opts [Object] :logger a logger to user for messages from the client. Defaults to stdout
23
22
  # @option opts [Boolean] :debug_enabled (false) The value for the debug flag
24
- #
23
+ # @option opts [Int] :impressions_queue_size Size of the impressions queue in the memory repository. Once reached, newer impressions will be dropped
24
+ # @option opts [Int] :impressions_bulk_size Max number of impressions to be sent to the backend on each post
25
+ # @option opts [#log] :impression_listener this object will capture all impressions and process them through `#log`
26
+ # @option opts [Int] :cache_ttl Time to live in seconds for the memory cache values when using Redis.
27
+ # @option opts [Int] :max_cache_size Max number of items to be held in the memory cache before prunning when using Redis.
25
28
  # @return [type] SplitConfig with configuration options
26
29
  def initialize(opts = {})
27
30
  @base_uri = (opts[:base_uri] || SplitConfig.default_base_uri).chomp('/')
28
- @local_store = opts[:local_store] || SplitConfig.default_local_store
31
+ @events_uri = (opts[:events_uri] || SplitConfig.default_events_uri).chomp('/')
32
+ @mode = opts[:mode] || SplitConfig.default_mode
33
+ @redis_url = opts[:redis_url] || SplitConfig.default_redis_url
34
+ @redis_namespace = opts[:redis_namespace] && opts[:redis_namespace].to_s.length > 0 ? "#{opts[:redis_namespace]}.#{SplitConfig.default_redis_namespace}" : SplitConfig.default_redis_namespace
35
+ @cache_adapter = SplitConfig.init_cache_adapter(
36
+ opts[:cache_adapter] || SplitConfig.default_cache_adapter, :map_adapter, nil, @redis_url
37
+ )
29
38
  @connection_timeout = opts[:connection_timeout] || SplitConfig.default_connection_timeout
30
39
  @read_timeout = opts[:read_timeout] || SplitConfig.default_read_timeout
31
- @features_refresh_rate = opts[:features_refresh_rate] || SplitConfig.default_features_refresh_rate
32
- @segments_refresh_rate = opts[:segments_refresh_rate] || SplitConfig.default_segments_refresh_rate
33
- @metrics_refresh_rate = opts[:metrics_refresh_rate] || SplitConfig.default_metrics_refresh_rate
34
- @impressions_refresh_rate = opts[:impressions_refresh_rate] || SplitConfig.default_impressions_refresh_rate
40
+
35
41
  @logger = opts[:logger] || SplitConfig.default_logger
42
+
43
+ if(opts[:reload_rate])
44
+ @features_refresh_rate = opts[:reload_rate]
45
+ @logger.warn('Localhost mode: reload_rate will be deprecated soon in favor of ' \
46
+ 'features_refresh_rate. Take a look in our documentation.'
47
+ )
48
+ else
49
+ @features_refresh_rate = opts[:features_refresh_rate] || SplitConfig.default_features_refresh_rate
50
+ end
51
+
52
+ @segments_refresh_rate = opts[:segments_refresh_rate] || SplitConfig.default_segments_refresh_rate
53
+
54
+ @impressions_mode = init_impressions_mode(opts[:impressions_mode], opts[:cache_adapter])
55
+
56
+ @impressions_refresh_rate = SplitConfig.init_impressions_refresh_rate(@impressions_mode, opts[:impressions_refresh_rate], SplitConfig.default_impressions_refresh_rate)
57
+ @impressions_queue_size = opts[:impressions_queue_size] || SplitConfig.default_impressions_queue_size
58
+ @impressions_adapter = SplitConfig.init_cache_adapter(
59
+ opts[:cache_adapter] || SplitConfig.default_cache_adapter, :queue_adapter, @impressions_queue_size, @redis_url
60
+ )
61
+ #Safeguard for users of older SDK versions.
62
+ @impressions_bulk_size = opts[:impressions_bulk_size] || @impressions_queue_size > 0 ? @impressions_queue_size : 0
63
+
36
64
  @debug_enabled = opts[:debug_enabled] || SplitConfig.default_debug
37
- @machine_name = SplitConfig.get_hostname
38
- @machine_ip = SplitConfig.get_ip
65
+ @transport_debug_enabled = opts[:transport_debug_enabled] || SplitConfig.default_debug
66
+ @block_until_ready = SplitConfig.default_block_until_ready
67
+
68
+ @ip_addresses_enabled = opts[:ip_addresses_enabled].nil? ? SplitConfig.default_ip_addresses_enabled : opts[:ip_addresses_enabled]
69
+
70
+ @machine_name = SplitConfig.machine_hostname(@ip_addresses_enabled, opts[:machine_name], opts[:cache_adapter] || SplitConfig.default_cache_adapter)
71
+ @machine_ip = SplitConfig.machine_ip(@ip_addresses_enabled, opts[:machine_ip], opts[:cache_adapter] || SplitConfig.default_cache_adapter)
72
+
73
+ @cache_ttl = opts[:cache_ttl] || SplitConfig.cache_ttl
74
+ @max_cache_size = opts[:max_cache_size] || SplitConfig.max_cache_size
75
+
76
+ @language = opts[:language] || 'ruby'
77
+ @version = opts[:version] || SplitIoClient::VERSION
78
+
79
+ @labels_enabled = opts[:labels_enabled].nil? ? SplitConfig.default_labels_logging : opts[:labels_enabled]
80
+
81
+ @impression_listener = opts[:impression_listener]
82
+ @impression_listener_refresh_rate = opts[:impression_listener_refresh_rate] || SplitConfig.default_impression_listener_refresh_rate
83
+
84
+ @max_key_size = SplitConfig.max_key_size
85
+
86
+ @threads = {}
87
+
88
+ @events_push_rate = opts[:events_push_rate] || SplitConfig.default_events_push_rate
89
+ @events_queue_size = opts[:events_queue_size] || SplitConfig.default_events_queue_size
90
+ @events_adapter = SplitConfig.init_cache_adapter(
91
+ opts[:cache_adapter] || SplitConfig.default_cache_adapter, :queue_adapter, @events_queue_size, @redis_url
92
+ )
93
+
94
+ @telemetry_adapter = SplitConfig.init_telemetry_adapter(
95
+ opts[:cache_adapter] || SplitConfig.default_cache_adapter, @redis_url
96
+ )
97
+
98
+ @split_file = opts[:split_file] || SplitConfig.default_split_file
99
+
100
+ @valid_mode = true
101
+ @split_logger = SplitIoClient::SplitLogger.new(self)
102
+ @split_validator = SplitIoClient::Validators.new(self)
103
+ @localhost_mode = opts[:localhost_mode]
104
+
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)
110
+
111
+ @telemetry_refresh_rate = SplitConfig.init_telemetry_refresh_rate(opts[:telemetry_refresh_rate])
112
+ @telemetry_service_url = opts[:telemetry_service_url] || SplitConfig.default_telemetry_service_url
113
+
114
+ @unique_keys_refresh_rate = SplitConfig.default_unique_keys_refresh_rate(@cache_adapter)
115
+ # @unique_keys_cache_max_size = SplitConfig.default_unique_keys_cache_max_size
116
+ @unique_keys_bulk_size = SplitConfig.default_unique_keys_bulk_size(@cache_adapter)
117
+
118
+ @counter_refresh_rate = SplitConfig.default_counter_refresh_rate(@cache_adapter)
119
+
120
+ @sdk_start_time = Time.now.to_f
121
+
122
+ @on_demand_fetch_retry_delay_seconds = SplitConfig.default_on_demand_fetch_retry_delay_seconds
123
+ @on_demand_fetch_max_retries = SplitConfig.default_on_demand_fetch_max_retries
124
+
125
+ @flag_sets_filter = SplitConfig.sanitize_flag_set_filter(opts[:flag_sets_filter], @split_validator, opts[:cache_adapter], @logger)
126
+
127
+ @fallback_treatments_configuration = SplitConfig.sanitize_fallback_config(opts[:fallback_treatments], @split_validator, @logger)
128
+ startup_log
39
129
  end
40
130
 
41
131
  #
42
132
  # The base URL for split API end points
43
133
  #
44
134
  # @return [String] The configured base URL for the split API end points
45
- attr_reader :base_uri
135
+ attr_accessor :base_uri
46
136
 
47
137
  #
48
- # The store for the Faraday HTTP caching library. Stores should respond to
49
- # 'read', 'write' and 'delete' requests.
138
+ # The base URL for split events API end points
50
139
  #
51
- # @return [Object] The configured store for the Faraday HTTP caching library.
52
- attr_reader :local_store
140
+ # @return [String] The configured URL for the events API end points
141
+ attr_accessor :events_uri
53
142
 
54
143
  #
144
+ # The mode SDK will run
145
+ #
146
+ # @return [Symbol] One of the available SDK modes: standalone, consumer
147
+ attr_accessor :mode
148
+
55
149
  # The read timeout for network connections in seconds.
56
150
  #
57
151
  # @return [Int] The timeout in seconds.
58
- attr_reader :read_timeout
152
+ attr_accessor :read_timeout
153
+
154
+ #
155
+ # The cache adapter to store splits/segments in
156
+ #
157
+ # @return [Object] Cache adapter instance
158
+ attr_accessor :cache_adapter
159
+
160
+ #
161
+ # The cache adapter to store impressions in
162
+ #
163
+ # @return [Object] Impressions adapter instance
164
+ attr_accessor :impressions_adapter
165
+
166
+ #
167
+ # The cache adapter to store events in
168
+ #
169
+ # @return [Object] Metrics adapter
170
+ attr_accessor :events_adapter
59
171
 
60
172
  #
61
173
  # The connection timeout for network connections in seconds.
62
174
  #
63
175
  # @return [Int] The connect timeout in seconds.
64
- attr_reader :connection_timeout
176
+ attr_accessor :connection_timeout
65
177
 
66
178
  #
67
179
  # The configured logger. The client library uses the log to
68
180
  # print warning and error messages.
69
181
  #
70
182
  # @return [Logger] The configured logger
71
- attr_reader :logger
183
+ attr_accessor :logger
184
+
185
+ #
186
+ # The split logger. The client library uses the split logger
187
+ # to use common functions around the logger
188
+ #
189
+ # @return [SplitLogger] The configured logger
190
+ attr_accessor :split_logger
191
+
192
+ #
193
+ # The split validator. The client library uses the split validator
194
+ # to validate inputs accross the sdk
195
+ #
196
+ # @return [SplitValidator] The validator
197
+ attr_accessor :split_validator
72
198
 
73
199
  #
74
200
  # The boolean that represents the state of the debug log level
75
201
  #
76
202
  # @return [Boolean] The value for the debug flag
77
- attr_reader :debug_enabled
203
+ attr_accessor :debug_enabled
204
+
205
+ #
206
+ # Enable to log the content retrieved from endpoints
207
+ #
208
+ # @return [Boolean] The value for the debug flag
209
+ attr_accessor :transport_debug_enabled
210
+
211
+ #
212
+ # Enable logging labels and sending potentially sensitive information
213
+ #
214
+ # @return [Boolean] The value for the labels enabled flag
215
+ attr_accessor :labels_enabled
216
+
217
+ #
218
+ # The number of seconds to wait for SDK readiness
219
+ # or false to disable waiting
220
+ # @return [Integer]/[FalseClass]
221
+ attr_accessor :block_until_ready
222
+
223
+ attr_accessor :machine_ip
224
+ attr_accessor :machine_name
225
+
226
+ attr_accessor :cache_ttl
227
+ attr_accessor :max_cache_size
78
228
 
79
- attr_reader :machine_ip
80
- attr_reader :machine_name
229
+ attr_accessor :max_key_size
81
230
 
82
- attr_reader :features_refresh_rate
83
- attr_reader :segments_refresh_rate
84
- attr_reader :metrics_refresh_rate
85
- attr_reader :impressions_refresh_rate
231
+ attr_accessor :language
232
+ attr_accessor :version
233
+
234
+ attr_accessor :features_refresh_rate
235
+ attr_accessor :segments_refresh_rate
236
+ attr_accessor :impressions_refresh_rate
237
+
238
+ attr_accessor :impression_listener
239
+ attr_accessor :impression_listener_refresh_rate
240
+
241
+ #
242
+ # How big the impressions queue is before dropping impressions
243
+ #
244
+ # @return [Integer]
245
+ attr_accessor :impressions_queue_size
246
+ attr_accessor :impressions_bulk_size
247
+
248
+ attr_accessor :redis_url
249
+ attr_accessor :redis_namespace
250
+
251
+ attr_accessor :threads
252
+
253
+ attr_accessor :valid_mode
254
+
255
+ #
256
+ # The schedule time for events flush after the first one
257
+ #
258
+ # @return [Integer]
259
+ attr_accessor :events_push_rate
260
+
261
+ #
262
+ # The max size of the events queue
263
+ #
264
+ # @return [Integer]
265
+ attr_accessor :events_queue_size
266
+
267
+ attr_accessor :split_file
268
+
269
+ attr_accessor :localhost_mode
270
+
271
+ attr_accessor :ip_addresses_enabled
272
+
273
+ attr_accessor :auth_service_url
274
+
275
+ attr_accessor :auth_retry_back_off_base
276
+
277
+ attr_accessor :streaming_service_url
278
+
279
+ attr_accessor :streaming_reconnect_back_off_base
280
+
281
+ attr_accessor :streaming_enabled
282
+
283
+ attr_accessor :impressions_mode
284
+
285
+ attr_accessor :telemetry_adapter
286
+
287
+ attr_accessor :telemetry_refresh_rate
288
+
289
+ attr_accessor :telemetry_service_url
290
+
291
+ attr_accessor :sdk_start_time
292
+
293
+ attr_accessor :on_demand_fetch_retry_delay_seconds
294
+ attr_accessor :on_demand_fetch_max_retries
295
+
296
+ attr_accessor :unique_keys_refresh_rate
297
+ #attr_accessor :unique_keys_cache_max_size
298
+ attr_accessor :unique_keys_bulk_size
299
+
300
+ attr_accessor :counter_refresh_rate
301
+
302
+ #
303
+ # Flagsets filter
304
+ #
305
+ # @return [Array]
306
+ attr_accessor :flag_sets_filter
307
+
308
+ attr_accessor :fallback_treatments_configuration
309
+
310
+ def self.default_counter_refresh_rate(adapter)
311
+ return 300 if adapter == :redis # Send bulk impressions count - Refresh rate: 5 min.
312
+
313
+ 1800 # Send bulk impressions count - Refresh rate: 30 min.
314
+ end
315
+
316
+ def self.default_on_demand_fetch_retry_delay_seconds
317
+ 0.05
318
+ end
319
+
320
+ def self.default_on_demand_fetch_max_retries
321
+ 10
322
+ end
323
+
324
+ def init_impressions_mode(impressions_mode, adapter)
325
+ case impressions_mode
326
+ when :optimized
327
+ return :optimized
328
+ when :none
329
+ return :none
330
+ when :debug
331
+ return :debug
332
+ else
333
+ default = adapter == :redis ? :debug : :optimized
334
+ @logger.error("You passed an invalid impressions_mode, impressions_mode should be one of the following values: :debug, :optimized or :none. Defaulting to #{default} mode") unless impressions_mode.nil?
335
+ return default
336
+ end
337
+ end
338
+
339
+ def self.init_impressions_refresh_rate(impressions_mode, refresh_rate, default_rate)
340
+ return (refresh_rate.nil? || refresh_rate <= 0 ? default_rate : refresh_rate) if impressions_mode == :debug
341
+
342
+ return refresh_rate.nil? || refresh_rate <= 0 ? SplitConfig.default_impressions_refresh_rate_optimized : [default_rate, refresh_rate].max
343
+ end
344
+
345
+ def self.init_telemetry_refresh_rate(refresh_rate)
346
+ return SplitConfig.default_telemetry_refresh_rate if refresh_rate.nil? || refresh_rate < 60
347
+
348
+ refresh_rate
349
+ end
350
+
351
+ def self.default_streaming_enabled
352
+ true
353
+ end
354
+
355
+ def self.default_streaming_service_url
356
+ 'https://streaming.split.io/event-stream'
357
+ end
358
+
359
+ def self.default_auth_service_url
360
+ 'https://auth.split.io/api/v2/auth'
361
+ end
362
+
363
+ def self.default_auth_retry_back_off_base
364
+ 1
365
+ end
366
+
367
+ def self.default_streaming_reconnect_back_off_base
368
+ 1
369
+ end
370
+
371
+ def self.init_auth_retry_back_off(auth_retry_back_off)
372
+ auth_retry_back_off < 1 ? SplitConfig.default_auth_retry_back_off_base : auth_retry_back_off
373
+ end
374
+
375
+ def self.init_streaming_reconnect_back_off(streaming_reconnect_back_off)
376
+ streaming_reconnect_back_off < 1 ? SplitConfig.default_streaming_reconnect_back_off_base : streaming_reconnect_back_off
377
+ end
86
378
 
87
379
  #
88
380
  # The default split client configuration
@@ -100,9 +392,56 @@ module SplitIoClient
100
392
  'https://sdk.split.io/api/'
101
393
  end
102
394
 
395
+ def self.default_events_uri
396
+ 'https://events.split.io/api/'
397
+ end
398
+
399
+ def self.init_cache_adapter(adapter, data_structure, queue_size = nil, redis_url = nil)
400
+ case adapter
401
+ when :memory
402
+ SplitIoClient::Cache::Adapters::MemoryAdapter.new(map_memory_adapter(data_structure, queue_size))
403
+ when :redis
404
+ begin
405
+ require 'redis'
406
+ rescue LoadError
407
+ fail StandardError, 'To use Redis as a cache adapter you must include it in your Gemfile'
408
+ end
409
+
410
+ SplitIoClient::Cache::Adapters::RedisAdapter.new(redis_url)
411
+ end
412
+ end
413
+
414
+ def self.init_telemetry_adapter(adapter, redis_url)
415
+ case adapter
416
+ when :memory
417
+ Telemetry::Storages::Memory.new
418
+ when :redis
419
+ begin
420
+ require 'redis'
421
+ rescue LoadError
422
+ fail StandardError, 'To use Redis as a cache adapter you must include it in your Gemfile'
423
+ end
424
+
425
+ SplitIoClient::Cache::Adapters::RedisAdapter.new(redis_url)
426
+ end
427
+ end
428
+
429
+ def self.map_memory_adapter(name, queue_size)
430
+ case name
431
+ when :map_adapter
432
+ SplitIoClient::Cache::Adapters::MemoryAdapters::MapAdapter.new
433
+ when :queue_adapter
434
+ SplitIoClient::Cache::Adapters::MemoryAdapters::QueueAdapter.new(queue_size)
435
+ end
436
+ end
437
+
438
+ def self.default_mode
439
+ :standalone
440
+ end
441
+
103
442
  # @return [LocalStore] configuration value for local cache store
104
- def self.default_local_store
105
- defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : LocalStore.new
443
+ def self.default_cache_adapter
444
+ :memory
106
445
  end
107
446
 
108
447
  #
@@ -122,27 +461,90 @@ module SplitIoClient
122
461
  end
123
462
 
124
463
  def self.default_features_refresh_rate
125
- 30
464
+ 60
126
465
  end
127
466
 
128
467
  def self.default_segments_refresh_rate
129
468
  60
130
469
  end
131
470
 
132
- def self.default_metrics_refresh_rate
471
+ def self.default_impressions_refresh_rate
133
472
  60
134
473
  end
135
474
 
136
- def self.default_impressions_refresh_rate
475
+ def self.default_impressions_refresh_rate_optimized
476
+ 300
477
+ end
478
+
479
+ def self.default_impression_listener_refresh_rate
480
+ 0
481
+ end
482
+
483
+ def self.default_impressions_queue_size
484
+ 5000
485
+ end
486
+
487
+ def self.default_events_push_rate
137
488
  60
138
489
  end
139
490
 
491
+ def self.default_events_queue_size
492
+ 500
493
+ end
494
+
495
+ def self.default_telemetry_refresh_rate
496
+ 3600
497
+ end
498
+
499
+ def self.default_unique_keys_refresh_rate(adapter)
500
+ return 300 if adapter == :redis
501
+
502
+ 900
503
+ end
504
+
505
+ # def self.default_unique_keys_cache_max_size
506
+ # 30000
507
+ # end
508
+
509
+ def self.default_unique_keys_bulk_size(adapter)
510
+ return 2000 if adapter == :redis
511
+
512
+ 5000
513
+ end
514
+
515
+ def self.default_telemetry_service_url
516
+ 'https://telemetry.split.io/api/v1'
517
+ end
518
+
519
+ def self.default_split_file
520
+ File.join(Dir.home, '.split')
521
+ end
522
+
523
+ def self.default_offline_refresh_rate
524
+ 5
525
+ end
526
+
527
+ def self.sanitize_flag_set_filter(flag_sets, validator, adapter, logger)
528
+ return [] if flag_sets.nil?
529
+ if adapter == :redis
530
+ logger.warn("config: : flag_sets_filter is not applicable for Consumer modes where the SDK does not keep rollout data in sync. FlagSet filter was discarded")
531
+ return []
532
+ end
533
+ return validator.valid_flag_sets(:config, flag_sets)
534
+ end
535
+
140
536
  #
141
537
  # The default logger object
142
538
  #
143
539
  # @return [object]
144
540
  def self.default_logger
145
- Logger.new($stdout)
541
+ if defined?(Rails) && Rails.logger
542
+ Rails.logger
543
+ elsif ENV['SPLITCLIENT_ENV'] == 'test'
544
+ Logger.new('/dev/null')
545
+ else
546
+ Logger.new($stdout)
547
+ end
146
548
  end
147
549
 
148
550
  #
@@ -153,41 +555,183 @@ module SplitIoClient
153
555
  false
154
556
  end
155
557
 
558
+ #
559
+ # The default labels logging value
560
+ #
561
+ # @return [boolean]
562
+ def self.default_labels_logging
563
+ true
564
+ end
565
+
566
+ def self.default_redis_url
567
+ 'redis://127.0.0.1:6379/0'
568
+ end
569
+
570
+ def self.default_redis_namespace
571
+ 'SPLITIO'
572
+ end
573
+
574
+ #
575
+ # The default block until ready value
576
+ #
577
+ # @return [int]
578
+ def self.default_block_until_ready
579
+ 15
580
+ end
581
+
582
+ #
583
+ # The default ip addresses enabled value
584
+ #
585
+ # @return [boolean]
586
+ def self.default_ip_addresses_enabled
587
+ true
588
+ end
589
+
590
+ #
591
+ # The default transport_debug_enabled value
592
+ #
593
+ # @return [boolean]
594
+ def self.transport_debug
595
+ false
596
+ end
597
+
598
+ #
599
+ # The default cache time to live
600
+ #
601
+ # @return [int]
602
+ def self.cache_ttl
603
+ 5
604
+ end
605
+
606
+ # The default max cache size
607
+ #
608
+ # @return [int]
609
+ def self.max_cache_size
610
+ 500
611
+ end
612
+
613
+ # The default max key size
614
+ #
615
+ # @return [int]
616
+ def self.max_key_size
617
+ 250
618
+ end
619
+
156
620
  #
157
621
  # custom logger of exceptions
158
622
  #
159
623
  # @return [void]
160
- def log_found_exception(caller, exn)
161
- error_traceback = "#{exn.inspect} #{exn}\n\t#{exn.backtrace.join("\n\t")}"
162
- error = "[splitclient-rb] Unexpected exception in #{caller}: #{error_traceback}"
163
- @logger.error(error)
624
+ def log_found_exception(caller, error)
625
+ message = ''
626
+
627
+ message << "[splitclient-rb] Unexpected exception in #{caller}: #{error.inspect} #{error}"
628
+ message << "\n\t#{error.backtrace.join("\n\t")}" if @debug_enabled
629
+
630
+ @logger.warn(message)
631
+ end
632
+
633
+ #
634
+ # log which cache class was loaded and SDK mode
635
+ #
636
+ # @return [void]
637
+ def startup_log
638
+ return if ENV['SPLITCLIENT_ENV'] == 'test'
639
+
640
+ @logger.info("Loaded Ruby SDK v#{VERSION} in the #{@mode} mode")
641
+ @logger.info("Loaded cache class: #{@cache_adapter.class}")
642
+ end
643
+
644
+ def standalone?
645
+ @mode.equal?(:standalone)
646
+ end
647
+
648
+ def consumer?
649
+ @mode.equal?(:consumer)
164
650
  end
165
651
 
652
+ def sdk_url_overriden?
653
+ return @base_uri != SplitConfig.default_base_uri
654
+ end
655
+
166
656
  #
167
657
  # gets the hostname where the sdk gem is running
168
658
  #
169
659
  # @return [string]
170
- def self.get_hostname
171
- begin
172
- Socket.gethostname
173
- rescue
174
- #unable to get hostname
175
- 'localhost'
660
+ def self.machine_hostname(ip_addresses_enabled, machine_name, adapter)
661
+ if ip_addresses_enabled
662
+ begin
663
+ return machine_name || Socket.gethostname
664
+ rescue
665
+ return 'unknown'.freeze
666
+ end
667
+ else
668
+ case adapter
669
+ when :redis
670
+ return 'NA'.freeze
671
+ end
176
672
  end
673
+
674
+ return ''.freeze
177
675
  end
178
676
 
179
677
  #
180
678
  # gets the ip where the sdk gem is running
181
679
  #
182
680
  # @return [string]
183
- def self.get_ip
184
- begin
185
- Socket::getaddrinfo(Socket.gethostname, 'echo', Socket::AF_INET)[0][3]
186
- rescue
187
- #unable to get local ip
188
- '127.0.0.0'
681
+ def self.machine_ip(ip_addresses_enabled, ip, adapter)
682
+ if ip_addresses_enabled
683
+ begin
684
+ return ip unless ip.nil? || ip.to_s.empty?
685
+
686
+ loopback_ip = Socket.ip_address_list.find { |ip| ip.ipv4_loopback? }
687
+ private_ip = Socket.ip_address_list.find { |ip| ip.ipv4_private? }
688
+
689
+ addr_info = private_ip || loopback_ip
690
+
691
+ return addr_info.ip_address
692
+ rescue
693
+ return 'unknown'.freeze
694
+ end
695
+ else
696
+ case adapter
697
+ when :redis
698
+ return 'NA'.freeze
699
+ end
189
700
  end
701
+
702
+ return ''.freeze
190
703
  end
191
704
 
705
+ def self.sanitize_fallback_config(fallback_config, validator, logger)
706
+ return fallback_config if fallback_config.nil?
707
+
708
+ processed = Engine::Models::FallbackTreatmentsConfiguration.new
709
+ if !fallback_config.is_a?(Engine::Models::FallbackTreatmentsConfiguration)
710
+ logger.warn('Config: fallbackTreatments parameter should be of `FallbackTreatmentsConfiguration` class.')
711
+ return processed
712
+ end
713
+
714
+ sanitized_global_fallback_treatment = fallback_config.global_fallback_treatment
715
+ if !fallback_config.global_fallback_treatment.nil? && !validator.validate_fallback_treatment('Config', fallback_config.global_fallback_treatment)
716
+ logger.warn('Config: global fallbacktreatment parameter is discarded.')
717
+ sanitized_global_fallback_treatment = nil
718
+ end
719
+
720
+ sanitized_flag_fallback_treatments = nil
721
+ if !fallback_config.by_flag_fallback_treatment.nil? && fallback_config.by_flag_fallback_treatment.is_a?(Hash)
722
+ sanitized_flag_fallback_treatments = Hash.new
723
+ for feature_name in fallback_config.by_flag_fallback_treatment.keys()
724
+ if !validator.valid_split_name?('Config', feature_name) || !validator.validate_fallback_treatment('Config', fallback_config.by_flag_fallback_treatment[feature_name])
725
+ logger.warn("Config: fallback treatment parameter for feature flag #{feature_name} is discarded.")
726
+ next
727
+ end
728
+
729
+ sanitized_flag_fallback_treatments[feature_name] = fallback_config.by_flag_fallback_treatment[feature_name]
730
+ end
731
+ end
732
+ processed = Engine::Models::FallbackTreatmentsConfiguration.new(sanitized_global_fallback_treatment, sanitized_flag_fallback_treatments)
733
+
734
+ processed
735
+ end
192
736
  end
193
737
  end