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
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ module Storages
6
+ class Memory
7
+ attr_reader :latencies,
8
+ :exceptions,
9
+ :factory_counters,
10
+ :tags,
11
+ :impressions_data_records,
12
+ :events_data_records,
13
+ :last_synchronization,
14
+ :http_errors,
15
+ :http_latencies,
16
+ :auth_rejections,
17
+ :token_refreshes,
18
+ :streaming_events,
19
+ :session_length,
20
+ :updates_from_sse
21
+
22
+ def initialize
23
+ init_latencies
24
+ init_exceptions
25
+ init_factory_counters
26
+ init_impressions_data_records
27
+ init_events_data_records
28
+ init_last_synchronization
29
+ init_http_errors
30
+ init_http_latencies
31
+ init_auth_rejections
32
+ init_token_refreshes
33
+ init_streaming_events
34
+ init_session_length
35
+ init_tags
36
+ init_updates_from_sse
37
+ end
38
+
39
+ def init_latencies
40
+ @latencies = Concurrent::Array.new
41
+ treatment_with_config_by_flag_set_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET
42
+ treatment_with_config_by_flag_sets_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
43
+
44
+ array_size = BinarySearchLatencyTracker::BUCKETS.length
45
+ @latencies << { method: Domain::Constants::TREATMENT, latencies: Concurrent::Array.new(array_size, 0) }
46
+ @latencies << { method: Domain::Constants::TREATMENTS, latencies: Concurrent::Array.new(array_size, 0) }
47
+ @latencies << { method: Domain::Constants::TREATMENT_WITH_CONFIG, latencies: Concurrent::Array.new(array_size, 0) }
48
+ @latencies << { method: Domain::Constants::TREATMENTS_WITH_CONFIG, latencies: Concurrent::Array.new(array_size, 0) }
49
+ @latencies << { method: Domain::Constants::TREATMENTS_BY_FLAG_SET, latencies: Concurrent::Array.new(array_size, 0) }
50
+ @latencies << { method: Domain::Constants::TREATMENTS_BY_FLAG_SETS, latencies: Concurrent::Array.new(array_size, 0) }
51
+ @latencies << { method: treatment_with_config_by_flag_set_const, latencies: Concurrent::Array.new(array_size, 0) }
52
+ @latencies << { method: treatment_with_config_by_flag_sets_const, latencies: Concurrent::Array.new(array_size, 0) }
53
+ @latencies << { method: Domain::Constants::TRACK, latencies: Concurrent::Array.new(array_size, 0) }
54
+ end
55
+
56
+ def init_exceptions
57
+ @exceptions = Concurrent::Array.new
58
+ treatment_with_config_by_flag_set_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET
59
+ treatment_with_config_by_flag_sets_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
60
+
61
+ @exceptions << { method: Domain::Constants::TREATMENT, exceptions: Concurrent::AtomicFixnum.new(0) }
62
+ @exceptions << { method: Domain::Constants::TREATMENTS, exceptions: Concurrent::AtomicFixnum.new(0) }
63
+ @exceptions << { method: Domain::Constants::TREATMENT_WITH_CONFIG, exceptions: Concurrent::AtomicFixnum.new(0) }
64
+ @exceptions << { method: Domain::Constants::TREATMENTS_WITH_CONFIG, exceptions: Concurrent::AtomicFixnum.new(0) }
65
+ @exceptions << { method: Domain::Constants::TREATMENTS_BY_FLAG_SET, exceptions: Concurrent::AtomicFixnum.new(0) }
66
+ @exceptions << { method: Domain::Constants::TREATMENTS_BY_FLAG_SETS, exceptions: Concurrent::AtomicFixnum.new(0) }
67
+ @exceptions << { method: treatment_with_config_by_flag_set_const, exceptions: Concurrent::AtomicFixnum.new(0) }
68
+ @exceptions << { method: treatment_with_config_by_flag_sets_const, exceptions: Concurrent::AtomicFixnum.new(0) }
69
+ @exceptions << { method: Domain::Constants::TRACK, exceptions: Concurrent::AtomicFixnum.new(0) }
70
+ end
71
+
72
+ def init_factory_counters
73
+ @factory_counters = Concurrent::Array.new
74
+
75
+ @factory_counters << { action: Domain::Constants::BUR_TIMEOUT, counts: Concurrent::AtomicFixnum.new(0) }
76
+ @factory_counters << { action: Domain::Constants::NON_READY_USAGES, counts: Concurrent::AtomicFixnum.new(0) }
77
+ end
78
+
79
+ def init_impressions_data_records
80
+ @impressions_data_records = Concurrent::Array.new
81
+
82
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_DEDUPE, value: Concurrent::AtomicFixnum.new(0) }
83
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_DROPPED, value: Concurrent::AtomicFixnum.new(0) }
84
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_QUEUED, value: Concurrent::AtomicFixnum.new(0) }
85
+ end
86
+
87
+ def init_events_data_records
88
+ @events_data_records = Concurrent::Array.new
89
+
90
+ @events_data_records << { type: Domain::Constants::EVENTS_DROPPED, value: Concurrent::AtomicFixnum.new(0) }
91
+ @events_data_records << { type: Domain::Constants::EVENTS_QUEUED, value: Concurrent::AtomicFixnum.new(0) }
92
+ end
93
+
94
+ def init_last_synchronization
95
+ @last_synchronization = Concurrent::Array.new
96
+
97
+ @last_synchronization << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
98
+ @last_synchronization << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
99
+ @last_synchronization << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
100
+ @last_synchronization << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
101
+ @last_synchronization << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::AtomicFixnum.new(0) }
102
+ @last_synchronization << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::AtomicFixnum.new(0) }
103
+ @last_synchronization << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::AtomicFixnum.new(0) }
104
+ end
105
+
106
+ def init_tags
107
+ @tags = Concurrent::Array.new
108
+ end
109
+
110
+ def init_http_errors
111
+ @http_errors = Concurrent::Array.new
112
+
113
+ @http_errors << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::Hash.new }
114
+ @http_errors << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::Hash.new }
115
+ @http_errors << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::Hash.new }
116
+ @http_errors << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::Hash.new }
117
+ @http_errors << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::Hash.new }
118
+ @http_errors << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::Hash.new }
119
+ @http_errors << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::Hash.new }
120
+ end
121
+
122
+ def init_http_latencies
123
+ @http_latencies = Concurrent::Array.new
124
+
125
+ array_size = BinarySearchLatencyTracker::BUCKETS.length
126
+ @http_latencies << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::Array.new(array_size, 0) }
127
+ @http_latencies << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::Array.new(array_size, 0) }
128
+ @http_latencies << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::Array.new(array_size, 0) }
129
+ @http_latencies << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::Array.new(array_size, 0) }
130
+ @http_latencies << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::Array.new(array_size, 0) }
131
+ @http_latencies << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::Array.new(array_size, 0) }
132
+ @http_latencies << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::Array.new(array_size, 0) }
133
+ end
134
+
135
+ def init_auth_rejections
136
+ @auth_rejections = Concurrent::AtomicFixnum.new(0)
137
+ end
138
+
139
+ def init_token_refreshes
140
+ @token_refreshes = Concurrent::AtomicFixnum.new(0)
141
+ end
142
+
143
+ def init_streaming_events
144
+ @streaming_events = Concurrent::Array.new
145
+ end
146
+
147
+ def init_session_length
148
+ @session_length = Concurrent::AtomicFixnum.new(0)
149
+ end
150
+
151
+ def init_updates_from_sse
152
+ @updates_from_sse = Concurrent::Hash.new
153
+
154
+ @updates_from_sse[Domain::Constants::SPLITS] = 0
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class SyncTask
6
+ def initialize(config, telemetry_synchronizer)
7
+ @config = config
8
+ @telemetry_synchronizer = telemetry_synchronizer
9
+ end
10
+
11
+ def call
12
+ stats_thread
13
+ end
14
+
15
+ private
16
+
17
+ def stats_thread
18
+ @config.threads[:telemetry_stats_sender] = Thread.new { telemetry_sync_task }
19
+ end
20
+
21
+ def telemetry_sync_task
22
+ @config.logger.info('Starting Telemetry Sync Task')
23
+
24
+ loop do
25
+ sleep(@config.telemetry_refresh_rate)
26
+
27
+ @telemetry_synchronizer.synchronize_stats
28
+ end
29
+ rescue SplitIoClient::SDKShutdownException
30
+ @telemetry_synchronizer.synchronize_stats
31
+
32
+ @config.logger.info('Posting Telemetry due to shutdown')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class Synchronizer
6
+ extend Forwardable
7
+ def_delegators :@synchronizer,
8
+ :synchronize_config,
9
+ :synchronize_stats
10
+
11
+ def initialize(config,
12
+ telemtry_consumers,
13
+ telemetry_init_producer,
14
+ repositories,
15
+ telemetry_api,
16
+ flag_sets,
17
+ flag_sets_invalid)
18
+ @synchronizer = case config.telemetry_adapter.class.to_s
19
+ when 'SplitIoClient::Cache::Adapters::RedisAdapter'
20
+ SplitIoClient::Telemetry::RedisSynchronizer.new(config,
21
+ telemetry_init_producer)
22
+ else
23
+ SplitIoClient::Telemetry::MemorySynchronizer.new(config,
24
+ telemtry_consumers,
25
+ repositories,
26
+ telemetry_api,
27
+ flag_sets,
28
+ flag_sets_invalid)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,49 @@
1
+ module SplitIoClient
2
+ module Utilities
3
+ extend self
4
+
5
+ # Convert String with Time info to its epoch FixNum previously setting to zero the seconds
6
+ def to_epoch(value)
7
+ parsed = Time.parse(value)
8
+ zeroed = Time.new(parsed.year, parsed.month, parsed.day, parsed.hour, parsed.min, 0, 0)
9
+
10
+ zeroed.to_i
11
+ end
12
+
13
+ def to_epoch_milis(value)
14
+ to_epoch(value) * 1000
15
+ end
16
+
17
+ def to_milis_zero_out_from_seconds(value)
18
+ parsed_value = Time.strptime(value.to_s, '%s').utc
19
+ zeroed = Time.new(parsed_value.year, parsed_value.month, parsed_value.day, parsed_value.hour, parsed_value.min, 0, 0)
20
+
21
+ zeroed.to_i * 1000
22
+ rescue StandardError
23
+ return :non_valid_date_info
24
+ end
25
+
26
+ def to_milis_zero_out_from_hour(value)
27
+ parsed_value = Time.strptime(value.to_s, '%s').utc
28
+ zeroed = Time.new(parsed_value.year, parsed_value.month, parsed_value.day, 0, 0, 0, 0)
29
+
30
+ zeroed.to_i * 1000
31
+ rescue StandardError
32
+ return :non_valid_date_info
33
+ end
34
+
35
+ def randomize_interval(interval)
36
+ random_factor = Random.new.rand(50..100) / 100.0
37
+
38
+ interval * random_factor
39
+ end
40
+
41
+ def split_bulk_to_send(items, divisions)
42
+ to_return = []
43
+ items.to_a.each_slice(divisions) {|bulk|
44
+ to_return.push(bulk.to_set)
45
+ }
46
+ to_return
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,361 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ class Validators
5
+
6
+ Flagset_regex = /^[a-z0-9][_a-z0-9]{0,49}$/
7
+ Fallback_treatment_regex = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/
8
+ Fallback_treatment_size = 100
9
+
10
+ def initialize(config)
11
+ @config = config
12
+ end
13
+
14
+ def valid_get_treatment_parameters(method, key, split_name, matching_key, bucketing_key, attributes)
15
+ valid_key?(method, key) &&
16
+ valid_split_name?(method, split_name) &&
17
+ valid_matching_key?(method, matching_key) &&
18
+ valid_bucketing_key?(method, key, bucketing_key) &&
19
+ valid_attributes?(method, attributes)
20
+ end
21
+
22
+ def valid_get_treatments_parameters(method, key, split_names, matching_key, bucketing_key, attributes)
23
+ valid_key?(method, key) &&
24
+ valid_split_names?(method, split_names)
25
+ valid_matching_key?(method, matching_key) &&
26
+ valid_bucketing_key?(method, key, bucketing_key) &&
27
+ valid_attributes?(method, attributes)
28
+ end
29
+
30
+ def valid_track_parameters(key, traffic_type_name, event_type, value, properties)
31
+ valid_track_key?(key) &&
32
+ valid_traffic_type_name?(traffic_type_name) &&
33
+ valid_event_type?(event_type) &&
34
+ valid_value?(value) &&
35
+ valid_properties?(properties)
36
+ end
37
+
38
+ def valid_split_parameters(split_name)
39
+ valid_split_name?(:split, split_name)
40
+ end
41
+
42
+ def valid_matcher_arguments(args)
43
+ return false if !args.key?(:attributes) && !args.key?(:value)
44
+ return false if args.key?(:value) && args[:value].nil?
45
+ return false if args.key?(:attributes) && args[:attributes].nil?
46
+ true
47
+ end
48
+
49
+ def valid_flag_sets(method, flag_sets)
50
+ if flag_sets.nil? || !flag_sets.is_a?(Array)
51
+ @config.logger.error("#{method}: FlagSets must be a non-empty list.")
52
+ return []
53
+ end
54
+ if flag_sets.empty?
55
+ @config.logger.error("#{method}: FlagSets must be a non-empty list.")
56
+ return []
57
+ end
58
+ without_nil = Array.new
59
+ flag_sets.each { |flag_set|
60
+ if !flag_set.nil?
61
+ without_nil.push(flag_set)
62
+ next
63
+ end
64
+
65
+ log_nil("flag set", method)
66
+ }
67
+ if without_nil.length() == 0
68
+ log_invalid_flag_set_type(method)
69
+ return []
70
+ end
71
+ valid_flag_sets = Set[]
72
+ without_nil.compact.uniq.select do |flag_set|
73
+ if flag_set.nil? || !flag_set.is_a?(String)
74
+ log_invalid_flag_set_type(method)
75
+ elsif flag_set.is_a?(String) && flag_set.empty?
76
+ log_invalid_flag_set_type(method)
77
+ elsif !flag_set.empty? && string_match?(flag_set.strip.downcase, method, Flagset_regex, :log_invalid_match)
78
+ valid_flag_sets.add(flag_set.strip.downcase)
79
+ else
80
+ log_invalid_flag_set_type(method)
81
+ end
82
+ end
83
+ !valid_flag_sets.empty? ? valid_flag_sets.to_a.sort : []
84
+ end
85
+
86
+ def validate_fallback_treatment(method, fallback_treatment)
87
+ if !fallback_treatment.is_a? Engine::Models::FallbackTreatment
88
+ @config.logger.warn("#{method}: Fallback treatment instance should be FallbackTreatment, input is discarded")
89
+ return false
90
+ end
91
+
92
+ if !fallback_treatment.treatment.is_a? String
93
+ @config.logger.warn("#{method}: Fallback treatment value should be str type, input is discarded")
94
+ return false
95
+ end
96
+
97
+ return false unless string_match?(fallback_treatment.treatment, method, Fallback_treatment_regex, :log_invalid_fallback_treatment)
98
+
99
+ if fallback_treatment.treatment.size > Fallback_treatment_size
100
+ @config.logger.warn("#{method}: Fallback treatment size should not exceed #{Fallback_treatment_size} characters")
101
+ return false
102
+ end
103
+
104
+ true
105
+ end
106
+
107
+ def valid_split_name?(method, split_name)
108
+ if split_name.nil?
109
+ log_nil(:split_name, method)
110
+ return false
111
+ end
112
+
113
+ unless string?(split_name)
114
+ log_invalid_type(:split_name, method)
115
+ return false
116
+ end
117
+
118
+ if empty_string?(split_name)
119
+ log_empty_string(:split_name, method)
120
+ return false
121
+ end
122
+
123
+ true
124
+ end
125
+
126
+ private
127
+
128
+ def string?(value)
129
+ value.is_a?(String) || value.is_a?(Symbol)
130
+ end
131
+
132
+ def empty_string?(value)
133
+ value.is_a?(String) && value.empty?
134
+ end
135
+
136
+ def number_or_string?(value)
137
+ (value.is_a?(Numeric) && !value.to_f.nan?) || string?(value)
138
+ end
139
+
140
+ def string_match?(value, method, regex_exp, log_if_invalid)
141
+ if regex_exp.match(value) == nil
142
+ method(log_if_invalid).call(value, method)
143
+ false
144
+ else
145
+ true
146
+ end
147
+ end
148
+
149
+ def log_invalid_match(key, method)
150
+ @config.logger.error("#{method}: you passed #{key}, flag set must adhere to the regular expression #{Flagset_regex}. " +
151
+ "This means flag set must be alphanumeric, cannot be more than 50 characters long, and can only include a dash, underscore, " +
152
+ "period, or colon as separators of alphanumeric characters.")
153
+ end
154
+
155
+ def log_nil(key, method)
156
+ msg_text = String.new("#{method}: you passed a nil #{key}, #{key} must be a non-empty String")
157
+ msg_text << " or a Symbol" if !key.equal?("flag set")
158
+ @config.logger.error(msg_text)
159
+ end
160
+
161
+ def log_empty_string(key, method)
162
+ @config.logger.error("#{method}: you passed an empty #{key}, #{key} must be a non-empty String or a Symbol")
163
+ end
164
+
165
+ def log_invalid_type(key, method)
166
+ @config.logger.error("#{method}: you passed an invalid #{key} type, #{key} must be a non-empty String or a Symbol")
167
+ end
168
+
169
+ def log_invalid_flag_set_type(method)
170
+ @config.logger.warn("#{method}: you passed an invalid flag set type, flag set must be a non-empty String")
171
+ end
172
+
173
+ def log_convert_numeric(key, method, value)
174
+ @config.logger.warn("#{method}: #{key} \"#{value}\" is not of type String, converting")
175
+ end
176
+
177
+ def log_key_too_long(key, method)
178
+ @config.logger.error("#{method}: #{key} is too long - must be #{@config.max_key_size} characters or less")
179
+ end
180
+
181
+ def valid_key?(method, key)
182
+ if key.nil?
183
+ log_nil(:key, method)
184
+ return false
185
+ end
186
+
187
+ true
188
+ end
189
+
190
+ def valid_matching_key?(method, matching_key)
191
+ if matching_key.nil?
192
+ log_nil(:matching_key, method)
193
+ return false
194
+ end
195
+
196
+ unless number_or_string?(matching_key)
197
+ log_invalid_type(:matching_key, method)
198
+ return false
199
+ end
200
+
201
+ if empty_string?(matching_key)
202
+ log_empty_string(:matching_key, method)
203
+ return false
204
+ end
205
+
206
+ log_convert_numeric(:matching_key, method, matching_key) if matching_key.is_a? Numeric
207
+
208
+ if matching_key.size > @config.max_key_size
209
+ log_key_too_long(:matching_key, method)
210
+ return false
211
+ end
212
+
213
+ true
214
+ end
215
+
216
+ def valid_bucketing_key?(method, key, bucketing_key)
217
+ if key.is_a? Hash
218
+ if bucketing_key.nil?
219
+ log_nil(:bucketing_key, method)
220
+ return false
221
+ end
222
+
223
+ unless number_or_string?(bucketing_key)
224
+ log_invalid_type(:bucketing_key, method)
225
+ return false
226
+ end
227
+
228
+ if empty_string?(bucketing_key)
229
+ log_empty_string(:bucketing_key, method)
230
+ return false
231
+ end
232
+
233
+ log_convert_numeric(:bucketing_key, method, bucketing_key) if bucketing_key.is_a? Numeric
234
+
235
+ if bucketing_key.size > @config.max_key_size
236
+ log_key_too_long(:bucketing_key, method)
237
+ return false
238
+ end
239
+ end
240
+
241
+ true
242
+ end
243
+
244
+ def valid_split_names?(method, split_names)
245
+ unless !split_names.nil? && split_names.is_a?(Array)
246
+ @config.logger.error("#{method}: feature_flag_names must be a non-empty Array")
247
+ return false
248
+ end
249
+
250
+ true
251
+ end
252
+
253
+ def valid_attributes?(method, attributes)
254
+ unless attributes.nil? || attributes.is_a?(Hash)
255
+ @config.logger.error("#{method}: attributes must be of type Hash")
256
+ return false
257
+ end
258
+
259
+ true
260
+ end
261
+
262
+ def valid_track_key?(key)
263
+ if key.nil?
264
+ log_nil(:key, :track)
265
+ return false
266
+ end
267
+
268
+ unless number_or_string?(key)
269
+ log_invalid_type(:key, :track)
270
+ return false
271
+ end
272
+
273
+ if empty_string?(key)
274
+ log_empty_string(:key, :track)
275
+ return false
276
+ end
277
+
278
+ log_convert_numeric(:key, :track, key) if key.is_a? Numeric
279
+
280
+ if key.size > @config.max_key_size
281
+ log_key_too_long(:key, :track)
282
+ return false
283
+ end
284
+
285
+ true
286
+ end
287
+
288
+ def valid_event_type?(event_type)
289
+ if event_type.nil?
290
+ log_nil(:event_type, :track)
291
+ return false
292
+ end
293
+
294
+ unless string?(event_type)
295
+ log_invalid_type(:event_type, :track)
296
+ return false
297
+ end
298
+
299
+ if event_type.empty?
300
+ log_empty_string(:event_type, :track)
301
+ return false
302
+ end
303
+
304
+ if (event_type.to_s =~ /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/).nil?
305
+ @config.logger.error("track: you passed '#{event_type}', " \
306
+ 'event_type must adhere to the regular expression ^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$. ' \
307
+ 'This means an event name must be alphanumeric, cannot be more than 80 characters long, ' \
308
+ 'and can only include a dash, underscore, period, or colon as separators of alphanumeric characters')
309
+ return false
310
+ end
311
+
312
+ true
313
+ end
314
+
315
+ def valid_traffic_type_name?(traffic_type_name)
316
+ if traffic_type_name.nil?
317
+ log_nil(:traffic_type_name, :track)
318
+ return false
319
+ end
320
+
321
+ unless string?(traffic_type_name)
322
+ log_invalid_type(:traffic_type_name, :track)
323
+ return false
324
+ end
325
+
326
+ if traffic_type_name.empty?
327
+ log_empty_string(:traffic_type_name, :track)
328
+ return false
329
+ end
330
+
331
+ unless traffic_type_name == traffic_type_name.downcase
332
+ @config.logger.warn('track: traffic_type_name should be all lowercase - ' \
333
+ 'converting string to lowercase')
334
+ end
335
+
336
+ true
337
+ end
338
+
339
+ def valid_value?(value)
340
+ unless (value.is_a?(Numeric) && !value.to_f.nan?) || value.nil?
341
+ @config.logger.error('track: value must be Numeric')
342
+ return false
343
+ end
344
+
345
+ true
346
+ end
347
+
348
+ def valid_properties?(properties)
349
+ unless properties.is_a?(Hash) || properties.nil?
350
+ @config.logger.error('track: properties must be a Hash')
351
+ return false
352
+ end
353
+
354
+ true
355
+ end
356
+
357
+ def log_invalid_fallback_treatment(key, method)
358
+ @config.logger.warn("#{method}: Invalid treatment #{key}, Fallback treatment should match regex #{Fallback_treatment_regex}")
359
+ end
360
+ end
361
+ end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '1.0.2.wip'
2
+ VERSION = '8.11.1-rc1'
3
3
  end