optimizely-sdk 5.0.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +202 -202
  3. data/lib/optimizely/audience.rb +127 -127
  4. data/lib/optimizely/bucketer.rb +156 -156
  5. data/lib/optimizely/condition_tree_evaluator.rb +123 -123
  6. data/lib/optimizely/config/datafile_project_config.rb +558 -558
  7. data/lib/optimizely/config/proxy_config.rb +34 -34
  8. data/lib/optimizely/config_manager/async_scheduler.rb +95 -95
  9. data/lib/optimizely/config_manager/http_project_config_manager.rb +340 -340
  10. data/lib/optimizely/config_manager/project_config_manager.rb +25 -25
  11. data/lib/optimizely/config_manager/static_project_config_manager.rb +55 -55
  12. data/lib/optimizely/decide/optimizely_decide_option.rb +28 -28
  13. data/lib/optimizely/decide/optimizely_decision.rb +60 -60
  14. data/lib/optimizely/decide/optimizely_decision_message.rb +26 -26
  15. data/lib/optimizely/decision_service.rb +563 -563
  16. data/lib/optimizely/error_handler.rb +39 -39
  17. data/lib/optimizely/event/batch_event_processor.rb +235 -235
  18. data/lib/optimizely/event/entity/conversion_event.rb +44 -44
  19. data/lib/optimizely/event/entity/decision.rb +38 -38
  20. data/lib/optimizely/event/entity/event_batch.rb +86 -86
  21. data/lib/optimizely/event/entity/event_context.rb +50 -50
  22. data/lib/optimizely/event/entity/impression_event.rb +48 -48
  23. data/lib/optimizely/event/entity/snapshot.rb +33 -33
  24. data/lib/optimizely/event/entity/snapshot_event.rb +48 -48
  25. data/lib/optimizely/event/entity/user_event.rb +22 -22
  26. data/lib/optimizely/event/entity/visitor.rb +36 -36
  27. data/lib/optimizely/event/entity/visitor_attribute.rb +38 -38
  28. data/lib/optimizely/event/event_factory.rb +156 -156
  29. data/lib/optimizely/event/event_processor.rb +25 -25
  30. data/lib/optimizely/event/forwarding_event_processor.rb +44 -44
  31. data/lib/optimizely/event/user_event_factory.rb +88 -88
  32. data/lib/optimizely/event_builder.rb +221 -221
  33. data/lib/optimizely/event_dispatcher.rb +69 -69
  34. data/lib/optimizely/exceptions.rb +193 -193
  35. data/lib/optimizely/helpers/constants.rb +459 -459
  36. data/lib/optimizely/helpers/date_time_utils.rb +30 -30
  37. data/lib/optimizely/helpers/event_tag_utils.rb +132 -132
  38. data/lib/optimizely/helpers/group.rb +31 -31
  39. data/lib/optimizely/helpers/http_utils.rb +68 -68
  40. data/lib/optimizely/helpers/sdk_settings.rb +61 -61
  41. data/lib/optimizely/helpers/validator.rb +236 -236
  42. data/lib/optimizely/helpers/variable_type.rb +67 -67
  43. data/lib/optimizely/logger.rb +46 -46
  44. data/lib/optimizely/notification_center.rb +174 -174
  45. data/lib/optimizely/notification_center_registry.rb +71 -71
  46. data/lib/optimizely/odp/lru_cache.rb +114 -114
  47. data/lib/optimizely/odp/odp_config.rb +102 -102
  48. data/lib/optimizely/odp/odp_event.rb +75 -75
  49. data/lib/optimizely/odp/odp_event_api_manager.rb +70 -70
  50. data/lib/optimizely/odp/odp_event_manager.rb +286 -286
  51. data/lib/optimizely/odp/odp_manager.rb +159 -159
  52. data/lib/optimizely/odp/odp_segment_api_manager.rb +122 -122
  53. data/lib/optimizely/odp/odp_segment_manager.rb +97 -97
  54. data/lib/optimizely/optimizely_config.rb +273 -273
  55. data/lib/optimizely/optimizely_factory.rb +184 -184
  56. data/lib/optimizely/optimizely_user_context.rb +238 -238
  57. data/lib/optimizely/params.rb +31 -31
  58. data/lib/optimizely/project_config.rb +99 -99
  59. data/lib/optimizely/semantic_version.rb +166 -166
  60. data/lib/optimizely/user_condition_evaluator.rb +391 -391
  61. data/lib/optimizely/user_profile_service.rb +35 -35
  62. data/lib/optimizely/version.rb +21 -21
  63. data/lib/optimizely.rb +1262 -1262
  64. metadata +7 -5
@@ -1,46 +1,46 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright 2016-2017, 2022, Optimizely and contributors
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- require 'logger'
19
-
20
- module Optimizely
21
- class BaseLogger
22
- # Class encapsulating logging functionality. Override with your own logger providing log method.
23
-
24
- def log(_level, _message); end
25
- end
26
-
27
- class NoOpLogger < BaseLogger
28
- # Class providing log method which logs nothing.
29
-
30
- def log(_level, _message); end
31
- end
32
-
33
- class SimpleLogger < BaseLogger
34
- # Simple wrapper around Logger.
35
-
36
- def initialize(min_level = Logger::INFO)
37
- super()
38
- @logger = Logger.new($stdout)
39
- @logger.level = min_level
40
- end
41
-
42
- def log(level, message)
43
- @logger.add(level, message)
44
- end
45
- end
46
- end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2016-2017, 2022, Optimizely and contributors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'logger'
19
+
20
+ module Optimizely
21
+ class BaseLogger
22
+ # Class encapsulating logging functionality. Override with your own logger providing log method.
23
+
24
+ def log(_level, _message); end
25
+ end
26
+
27
+ class NoOpLogger < BaseLogger
28
+ # Class providing log method which logs nothing.
29
+
30
+ def log(_level, _message); end
31
+ end
32
+
33
+ class SimpleLogger < BaseLogger
34
+ # Simple wrapper around Logger.
35
+
36
+ def initialize(min_level = Logger::INFO)
37
+ super()
38
+ @logger = Logger.new($stdout)
39
+ @logger.level = min_level
40
+ end
41
+
42
+ def log(level, message)
43
+ @logger.add(level, message)
44
+ end
45
+ end
46
+ end
@@ -1,174 +1,174 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright 2017-2019, 2022, Optimizely and contributors
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- module Optimizely
19
- class NotificationCenter
20
- # @api no-doc
21
- attr_reader :notifications, :notification_id
22
-
23
- NOTIFICATION_TYPES = {
24
- # DEPRECATED: ACTIVATE notification type is deprecated since relase 3.1.0.
25
- ACTIVATE: 'ACTIVATE: experiment, user_id, attributes, variation, event',
26
- DECISION: 'DECISION: type, user_id, attributes, decision_info',
27
- LOG_EVENT: 'LOG_EVENT: type, log_event',
28
- OPTIMIZELY_CONFIG_UPDATE: 'optimizely_config_update',
29
- TRACK: 'TRACK: event_key, user_id, attributes, event_tags, event'
30
- }.freeze
31
-
32
- def initialize(logger, error_handler)
33
- @notification_id = 1
34
- @notifications = {}
35
- NOTIFICATION_TYPES.each_value { |value| @notifications[value] = [] }
36
- @logger = logger
37
- @error_handler = error_handler
38
- end
39
-
40
- # Adds notification callback to the notification center
41
- #
42
- # @param notification_type - One of the constants in NOTIFICATION_TYPES
43
- # @param notification_callback [lambda, Method, Callable] (default: block) - Called when the event is sent
44
- # @yield Block to be used as callback if callback omitted.
45
- #
46
- # @return [notification ID] Used to remove the notification
47
-
48
- def add_notification_listener(notification_type, notification_callback = nil, &block)
49
- return nil unless notification_type_valid?(notification_type)
50
-
51
- if notification_callback && block_given?
52
- @logger.log Logger::ERROR, 'Callback and block are mutually exclusive.'
53
- return nil
54
- end
55
-
56
- notification_callback ||= block
57
-
58
- unless notification_callback
59
- @logger.log Logger::ERROR, 'Callback can not be empty.'
60
- return nil
61
- end
62
-
63
- unless notification_callback.respond_to? :call
64
- @logger.log Logger::ERROR, 'Invalid notification callback given.'
65
- return nil
66
- end
67
-
68
- @notifications[notification_type].each do |notification|
69
- return -1 if notification[:callback] == notification_callback
70
- end
71
- @notifications[notification_type].push(notification_id: @notification_id, callback: notification_callback)
72
- notification_id = @notification_id
73
- @notification_id += 1
74
- notification_id
75
- end
76
-
77
- # Removes previously added notification callback
78
- #
79
- # @param notification_id
80
- #
81
- # @return [Boolean] true if found and removed, false otherwise
82
-
83
- def remove_notification_listener(notification_id)
84
- unless notification_id
85
- @logger.log Logger::ERROR, 'Notification ID can not be empty.'
86
- return nil
87
- end
88
- @notifications.each_key do |key|
89
- @notifications[key].each do |notification|
90
- if notification_id == notification[:notification_id]
91
- @notifications[key].delete(notification_id: notification_id, callback: notification[:callback])
92
- return true
93
- end
94
- end
95
- end
96
- false
97
- end
98
-
99
- # @deprecated Use {#clear_notification_listeners} instead.
100
- def clear_notifications(notification_type)
101
- @logger.log Logger::WARN, "'clear_notifications' is deprecated. Call 'clear_notification_listeners' instead."
102
- clear_notification_listeners(notification_type)
103
- end
104
-
105
- # Removes notifications for a certain notification type
106
- #
107
- # @param notification_type - one of the constants in NOTIFICATION_TYPES
108
-
109
- def clear_notification_listeners(notification_type)
110
- return nil unless notification_type_valid?(notification_type)
111
-
112
- @notifications[notification_type] = []
113
- @logger.log Logger::INFO, "All callbacks for notification type #{notification_type} have been removed."
114
- end
115
-
116
- # @deprecated Use {#clear_all_notification_listeners} instead.
117
- def clean_all_notifications
118
- @logger.log Logger::WARN, "'clean_all_notifications' is deprecated. Call 'clear_all_notification_listeners' instead."
119
- clear_all_notification_listeners
120
- end
121
-
122
- # Removes all notifications
123
- def clear_all_notification_listeners
124
- @notifications.each_key { |key| @notifications[key] = [] }
125
- end
126
-
127
- # Sends off the notification for the specific event. Uses var args to pass in a
128
- # arbitrary list of parameters according to which notification type was sent
129
- #
130
- # @param notification_type - one of the constants in NOTIFICATION_TYPES
131
- # @param args - list of arguments to the callback
132
- #
133
- # @api no-doc
134
- def send_notifications(notification_type, *args)
135
- return nil unless notification_type_valid?(notification_type)
136
-
137
- @notifications[notification_type].each do |notification|
138
- notification_callback = notification[:callback]
139
- notification_callback.call(*args)
140
- @logger.log Logger::INFO, "Notification #{notification_type} sent successfully."
141
- rescue => e
142
- @logger.log(Logger::ERROR, "Problem calling notify callback. Error: #{e}")
143
- return nil
144
- end
145
- end
146
-
147
- def notification_count(notification_type)
148
- @notifications.include?(notification_type) ? @notifications[notification_type].count : 0
149
- end
150
-
151
- private
152
-
153
- def notification_type_valid?(notification_type)
154
- # Validates notification type
155
-
156
- # Args:
157
- # notification_type: one of the constants in NOTIFICATION_TYPES
158
-
159
- # Returns true if notification_type is valid, false otherwise
160
-
161
- unless notification_type
162
- @logger.log Logger::ERROR, 'Notification type can not be empty.'
163
- return false
164
- end
165
-
166
- unless @notifications.include?(notification_type)
167
- @logger.log Logger::ERROR, 'Invalid notification type.'
168
- @error_handler.handle_error InvalidNotificationType
169
- return false
170
- end
171
- true
172
- end
173
- end
174
- end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2017-2019, 2022, Optimizely and contributors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module Optimizely
19
+ class NotificationCenter
20
+ # @api no-doc
21
+ attr_reader :notifications, :notification_id
22
+
23
+ NOTIFICATION_TYPES = {
24
+ # DEPRECATED: ACTIVATE notification type is deprecated since relase 3.1.0.
25
+ ACTIVATE: 'ACTIVATE: experiment, user_id, attributes, variation, event',
26
+ DECISION: 'DECISION: type, user_id, attributes, decision_info',
27
+ LOG_EVENT: 'LOG_EVENT: type, log_event',
28
+ OPTIMIZELY_CONFIG_UPDATE: 'optimizely_config_update',
29
+ TRACK: 'TRACK: event_key, user_id, attributes, event_tags, event'
30
+ }.freeze
31
+
32
+ def initialize(logger, error_handler)
33
+ @notification_id = 1
34
+ @notifications = {}
35
+ NOTIFICATION_TYPES.each_value { |value| @notifications[value] = [] }
36
+ @logger = logger
37
+ @error_handler = error_handler
38
+ end
39
+
40
+ # Adds notification callback to the notification center
41
+ #
42
+ # @param notification_type - One of the constants in NOTIFICATION_TYPES
43
+ # @param notification_callback [lambda, Method, Callable] (default: block) - Called when the event is sent
44
+ # @yield Block to be used as callback if callback omitted.
45
+ #
46
+ # @return [notification ID] Used to remove the notification
47
+
48
+ def add_notification_listener(notification_type, notification_callback = nil, &block)
49
+ return nil unless notification_type_valid?(notification_type)
50
+
51
+ if notification_callback && block_given?
52
+ @logger.log Logger::ERROR, 'Callback and block are mutually exclusive.'
53
+ return nil
54
+ end
55
+
56
+ notification_callback ||= block
57
+
58
+ unless notification_callback
59
+ @logger.log Logger::ERROR, 'Callback can not be empty.'
60
+ return nil
61
+ end
62
+
63
+ unless notification_callback.respond_to? :call
64
+ @logger.log Logger::ERROR, 'Invalid notification callback given.'
65
+ return nil
66
+ end
67
+
68
+ @notifications[notification_type].each do |notification|
69
+ return -1 if notification[:callback] == notification_callback
70
+ end
71
+ @notifications[notification_type].push(notification_id: @notification_id, callback: notification_callback)
72
+ notification_id = @notification_id
73
+ @notification_id += 1
74
+ notification_id
75
+ end
76
+
77
+ # Removes previously added notification callback
78
+ #
79
+ # @param notification_id
80
+ #
81
+ # @return [Boolean] true if found and removed, false otherwise
82
+
83
+ def remove_notification_listener(notification_id)
84
+ unless notification_id
85
+ @logger.log Logger::ERROR, 'Notification ID can not be empty.'
86
+ return nil
87
+ end
88
+ @notifications.each_key do |key|
89
+ @notifications[key].each do |notification|
90
+ if notification_id == notification[:notification_id]
91
+ @notifications[key].delete(notification_id: notification_id, callback: notification[:callback])
92
+ return true
93
+ end
94
+ end
95
+ end
96
+ false
97
+ end
98
+
99
+ # @deprecated Use {#clear_notification_listeners} instead.
100
+ def clear_notifications(notification_type)
101
+ @logger.log Logger::WARN, "'clear_notifications' is deprecated. Call 'clear_notification_listeners' instead."
102
+ clear_notification_listeners(notification_type)
103
+ end
104
+
105
+ # Removes notifications for a certain notification type
106
+ #
107
+ # @param notification_type - one of the constants in NOTIFICATION_TYPES
108
+
109
+ def clear_notification_listeners(notification_type)
110
+ return nil unless notification_type_valid?(notification_type)
111
+
112
+ @notifications[notification_type] = []
113
+ @logger.log Logger::INFO, "All callbacks for notification type #{notification_type} have been removed."
114
+ end
115
+
116
+ # @deprecated Use {#clear_all_notification_listeners} instead.
117
+ def clean_all_notifications
118
+ @logger.log Logger::WARN, "'clean_all_notifications' is deprecated. Call 'clear_all_notification_listeners' instead."
119
+ clear_all_notification_listeners
120
+ end
121
+
122
+ # Removes all notifications
123
+ def clear_all_notification_listeners
124
+ @notifications.each_key { |key| @notifications[key] = [] }
125
+ end
126
+
127
+ # Sends off the notification for the specific event. Uses var args to pass in a
128
+ # arbitrary list of parameters according to which notification type was sent
129
+ #
130
+ # @param notification_type - one of the constants in NOTIFICATION_TYPES
131
+ # @param args - list of arguments to the callback
132
+ #
133
+ # @api no-doc
134
+ def send_notifications(notification_type, *args)
135
+ return nil unless notification_type_valid?(notification_type)
136
+
137
+ @notifications[notification_type].each do |notification|
138
+ notification_callback = notification[:callback]
139
+ notification_callback.call(*args)
140
+ @logger.log Logger::INFO, "Notification #{notification_type} sent successfully."
141
+ rescue => e
142
+ @logger.log(Logger::ERROR, "Problem calling notify callback. Error: #{e}")
143
+ return nil
144
+ end
145
+ end
146
+
147
+ def notification_count(notification_type)
148
+ @notifications.include?(notification_type) ? @notifications[notification_type].count : 0
149
+ end
150
+
151
+ private
152
+
153
+ def notification_type_valid?(notification_type)
154
+ # Validates notification type
155
+
156
+ # Args:
157
+ # notification_type: one of the constants in NOTIFICATION_TYPES
158
+
159
+ # Returns true if notification_type is valid, false otherwise
160
+
161
+ unless notification_type
162
+ @logger.log Logger::ERROR, 'Notification type can not be empty.'
163
+ return false
164
+ end
165
+
166
+ unless @notifications.include?(notification_type)
167
+ @logger.log Logger::ERROR, 'Invalid notification type.'
168
+ @error_handler.handle_error InvalidNotificationType
169
+ return false
170
+ end
171
+ true
172
+ end
173
+ end
174
+ end
@@ -1,71 +1,71 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright 2023, Optimizely and contributors
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- require_relative 'notification_center'
19
- require_relative 'exceptions'
20
-
21
- module Optimizely
22
- class NotificationCenterRegistry
23
- private_class_method :new
24
- # Class managing internal notification centers.
25
- # @api no-doc
26
- @notification_centers = {}
27
- @mutex = Mutex.new
28
-
29
- # Returns an internal notification center for the given sdk_key, creating one
30
- # if none exists yet.
31
- #
32
- # Args:
33
- # sdk_key: A string sdk key to uniquely identify the notification center.
34
- # logger: Optional logger.
35
-
36
- # Returns:
37
- # nil or NotificationCenter
38
- def self.get_notification_center(sdk_key, logger)
39
- unless sdk_key
40
- logger&.log(Logger::ERROR, "#{MissingSdkKeyError.new.message} ODP may not work properly without it.")
41
- return nil
42
- end
43
-
44
- notification_center = nil
45
-
46
- @mutex.synchronize do
47
- if @notification_centers.key?(sdk_key)
48
- notification_center = @notification_centers[sdk_key]
49
- else
50
- notification_center = NotificationCenter.new(logger, nil)
51
- @notification_centers[sdk_key] = notification_center
52
- end
53
- end
54
-
55
- notification_center
56
- end
57
-
58
- # Remove a previously added notification center and clear all its listeners.
59
-
60
- # Args:
61
- # sdk_key: The sdk_key of the notification center to remove.
62
- def self.remove_notification_center(sdk_key)
63
- @mutex.synchronize do
64
- @notification_centers
65
- .delete(sdk_key)
66
- &.clear_all_notification_listeners
67
- end
68
- nil
69
- end
70
- end
71
- end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2023, Optimizely and contributors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require_relative 'notification_center'
19
+ require_relative 'exceptions'
20
+
21
+ module Optimizely
22
+ class NotificationCenterRegistry
23
+ private_class_method :new
24
+ # Class managing internal notification centers.
25
+ # @api no-doc
26
+ @notification_centers = {}
27
+ @mutex = Mutex.new
28
+
29
+ # Returns an internal notification center for the given sdk_key, creating one
30
+ # if none exists yet.
31
+ #
32
+ # Args:
33
+ # sdk_key: A string sdk key to uniquely identify the notification center.
34
+ # logger: Optional logger.
35
+
36
+ # Returns:
37
+ # nil or NotificationCenter
38
+ def self.get_notification_center(sdk_key, logger)
39
+ unless sdk_key
40
+ logger&.log(Logger::ERROR, "#{MissingSdkKeyError.new.message} ODP may not work properly without it.")
41
+ return nil
42
+ end
43
+
44
+ notification_center = nil
45
+
46
+ @mutex.synchronize do
47
+ if @notification_centers.key?(sdk_key)
48
+ notification_center = @notification_centers[sdk_key]
49
+ else
50
+ notification_center = NotificationCenter.new(logger, nil)
51
+ @notification_centers[sdk_key] = notification_center
52
+ end
53
+ end
54
+
55
+ notification_center
56
+ end
57
+
58
+ # Remove a previously added notification center and clear all its listeners.
59
+
60
+ # Args:
61
+ # sdk_key: The sdk_key of the notification center to remove.
62
+ def self.remove_notification_center(sdk_key)
63
+ @mutex.synchronize do
64
+ @notification_centers
65
+ .delete(sdk_key)
66
+ &.clear_all_notification_listeners
67
+ end
68
+ nil
69
+ end
70
+ end
71
+ end