11use crossbeam_channel:: { bounded, select, tick, Receiver , Sender } ;
2- use std:: collections:: HashSet ;
3- use std:: iter:: FromIterator ;
42use std:: time:: SystemTime ;
53
64use launchdarkly_server_sdk_evaluation:: Context ;
75use lru:: LruCache ;
86
9- use super :: event:: FeatureRequestEvent ;
7+ use super :: event:: { BaseEvent , FeatureRequestEvent , IndexEvent } ;
108use super :: sender:: EventSenderResult ;
119use super :: {
1210 event:: { EventSummary , InputEvent , OutputEvent } ,
@@ -192,11 +190,13 @@ impl EventDispatcher {
192190 self . events_configuration . private_attributes . clone ( ) ,
193191 ) ;
194192
195- if self . notice_context ( & fre. base . context ) {
196- self . outbox . add_event ( OutputEvent :: Index ( fre. to_index_event (
193+ if let Some ( context ) = self . get_indexable_context ( & fre. base ) {
194+ let base = BaseEvent :: new ( fre. base . creation_date , context ) . into_inline (
197195 self . events_configuration . all_attributes_private ,
198196 self . events_configuration . private_attributes . clone ( ) ,
199- ) ) ) ;
197+ ) ;
198+ self . outbox
199+ . add_event ( OutputEvent :: Index ( IndexEvent :: from ( base) ) ) ;
200200 }
201201
202202 let now = match SystemTime :: now ( ) . duration_since ( std:: time:: UNIX_EPOCH ) {
@@ -219,30 +219,53 @@ impl EventDispatcher {
219219 self . outbox . add_event ( OutputEvent :: FeatureRequest ( inlined) ) ;
220220 }
221221 }
222- InputEvent :: Identify ( identify) => {
222+ InputEvent :: Identify ( mut identify) => {
223+ if self . events_configuration . omit_anonymous_contexts {
224+ match identify. base . context . without_anonymous_contexts ( ) {
225+ Ok ( context) => identify. base . context = context,
226+ Err ( _) => return ,
227+ }
228+ }
229+
223230 self . notice_context ( & identify. base . context ) ;
224231 self . outbox
225232 . add_event ( OutputEvent :: Identify ( identify. into_inline (
226233 self . events_configuration . all_attributes_private ,
227- HashSet :: from_iter (
228- self . events_configuration . private_attributes . iter ( ) . cloned ( ) ,
229- ) ,
234+ self . events_configuration . private_attributes . clone ( ) ,
230235 ) ) ) ;
231236 }
232237 InputEvent :: Custom ( custom) => {
233- if self . notice_context ( & custom. base . context ) {
238+ if let Some ( context) = self . get_indexable_context ( & custom. base ) {
239+ let base = BaseEvent :: new ( custom. base . creation_date , context) . into_inline (
240+ self . events_configuration . all_attributes_private ,
241+ self . events_configuration . private_attributes . clone ( ) ,
242+ ) ;
234243 self . outbox
235- . add_event ( OutputEvent :: Index ( custom. to_index_event (
236- self . events_configuration . all_attributes_private ,
237- self . events_configuration . private_attributes . clone ( ) ,
238- ) ) ) ;
244+ . add_event ( OutputEvent :: Index ( IndexEvent :: from ( base) ) ) ;
239245 }
240246
241247 self . outbox . add_event ( OutputEvent :: Custom ( custom) ) ;
242248 }
243249 }
244250 }
245251
252+ fn get_indexable_context ( & mut self , event : & BaseEvent ) -> Option < Context > {
253+ let context = match self . events_configuration . omit_anonymous_contexts {
254+ true => event. context . without_anonymous_contexts ( ) ,
255+ false => Ok ( event. context . clone ( ) ) ,
256+ } ;
257+
258+ if let Ok ( ctx) = context {
259+ if self . notice_context ( & ctx) {
260+ return Some ( ctx) ;
261+ }
262+
263+ return None ;
264+ }
265+
266+ None
267+ }
268+
246269 fn notice_context ( & mut self , context : & Context ) -> bool {
247270 let key = context. canonical_key ( ) ;
248271
@@ -273,7 +296,9 @@ mod tests {
273296 use crate :: events:: event:: { EventFactory , OutputEvent } ;
274297 use crate :: events:: { create_event_sender, create_events_configuration} ;
275298 use crate :: test_common:: basic_flag;
276- use launchdarkly_server_sdk_evaluation:: { ContextBuilder , Detail , FlagValue , Reason } ;
299+ use launchdarkly_server_sdk_evaluation:: {
300+ ContextBuilder , Detail , FlagValue , MultiContextBuilder , Reason ,
301+ } ;
277302 use test_case:: test_case;
278303
279304 #[ test]
@@ -359,6 +384,48 @@ mod tests {
359384 assert_eq ! ( 1 , dispatcher. outbox. summary. features. len( ) ) ;
360385 }
361386
387+ #[ test]
388+ fn dispatcher_strips_anonymous_contexts_from_index_for_feature_request_events ( ) {
389+ let ( event_sender, _) = create_event_sender ( ) ;
390+ let mut events_configuration =
391+ create_events_configuration ( event_sender, Duration :: from_secs ( 100 ) ) ;
392+ events_configuration. omit_anonymous_contexts = true ;
393+ let mut dispatcher = create_dispatcher ( events_configuration) ;
394+
395+ let context = ContextBuilder :: new ( "context" )
396+ . anonymous ( true )
397+ . build ( )
398+ . expect ( "Failed to create context" ) ;
399+ let mut flag = basic_flag ( "flag" ) ;
400+ flag. debug_events_until_date = Some ( 64_060_606_800_000 ) ;
401+ flag. track_events = true ;
402+
403+ let detail = Detail {
404+ value : Some ( FlagValue :: from ( false ) ) ,
405+ variation_index : Some ( 1 ) ,
406+ reason : Reason :: Fallthrough {
407+ in_experiment : false ,
408+ } ,
409+ } ;
410+
411+ let event_factory = EventFactory :: new ( true ) ;
412+ let feature_request_event = event_factory. new_eval_event (
413+ & flag. key ,
414+ context,
415+ & flag,
416+ detail,
417+ FlagValue :: from ( false ) ,
418+ None ,
419+ ) ;
420+
421+ dispatcher. process_event ( feature_request_event) ;
422+ assert_eq ! ( 2 , dispatcher. outbox. events. len( ) ) ;
423+ assert_eq ! ( "debug" , dispatcher. outbox. events[ 0 ] . kind( ) ) ;
424+ assert_eq ! ( "feature" , dispatcher. outbox. events[ 1 ] . kind( ) ) ;
425+ assert_eq ! ( 0 , dispatcher. context_keys. len( ) ) ;
426+ assert_eq ! ( 1 , dispatcher. outbox. summary. features. len( ) ) ;
427+ }
428+
362429 #[ test_case( 0 , 64_060_606_800_000 , vec![ "debug" , "index" , "summary" ] ) ]
363430 #[ test_case( 64_060_606_800_000 , 64_060_606_800_000 , vec![ "index" , "summary" ] ) ]
364431 #[ test_case( 64_060_606_800_001 , 64_060_606_800_000 , vec![ "index" , "summary" ] ) ]
@@ -446,6 +513,61 @@ mod tests {
446513 assert_eq ! ( 1 , dispatcher. context_keys. len( ) ) ;
447514 }
448515
516+ #[ test]
517+ fn dispatcher_can_ignore_identify_if_anonymous ( ) {
518+ let ( event_sender, _) = create_event_sender ( ) ;
519+ let mut events_configuration =
520+ create_events_configuration ( event_sender, Duration :: from_secs ( 100 ) ) ;
521+ events_configuration. omit_anonymous_contexts = true ;
522+ let mut dispatcher = create_dispatcher ( events_configuration) ;
523+
524+ let context = ContextBuilder :: new ( "context" )
525+ . anonymous ( true )
526+ . build ( )
527+ . expect ( "Failed to create context" ) ;
528+ let event_factory = EventFactory :: new ( true ) ;
529+
530+ dispatcher. process_event ( event_factory. new_identify ( context) ) ;
531+ assert_eq ! ( 0 , dispatcher. outbox. events. len( ) ) ;
532+ assert_eq ! ( 0 , dispatcher. context_keys. len( ) ) ;
533+ }
534+
535+ #[ test]
536+ fn dispatcher_strips_anon_contexts_from_multi_kind_identify ( ) {
537+ let ( event_sender, _) = create_event_sender ( ) ;
538+ let mut events_configuration =
539+ create_events_configuration ( event_sender, Duration :: from_secs ( 100 ) ) ;
540+ events_configuration. omit_anonymous_contexts = true ;
541+ let mut dispatcher = create_dispatcher ( events_configuration) ;
542+
543+ let user_context = ContextBuilder :: new ( "user" )
544+ . anonymous ( true )
545+ . build ( )
546+ . expect ( "Failed to create context" ) ;
547+ let org_context = ContextBuilder :: new ( "org" )
548+ . kind ( "org" )
549+ . build ( )
550+ . expect ( "Failed to create context" ) ;
551+ let context = MultiContextBuilder :: new ( )
552+ . add_context ( user_context)
553+ . add_context ( org_context)
554+ . build ( )
555+ . expect ( "Failed to create context" ) ;
556+
557+ let event_factory = EventFactory :: new ( true ) ;
558+
559+ dispatcher. process_event ( event_factory. new_identify ( context) ) ;
560+ assert_eq ! ( 1 , dispatcher. outbox. events. len( ) ) ;
561+ assert_eq ! ( "identify" , dispatcher. outbox. events[ 0 ] . kind( ) ) ;
562+ assert_eq ! ( 1 , dispatcher. context_keys. len( ) ) ;
563+
564+ if let OutputEvent :: Identify ( identify) = & dispatcher. outbox . events [ 0 ] {
565+ assert_eq ! ( "org:org" , identify. base. context. canonical_key( ) ) ;
566+ } else {
567+ panic ! ( "Expected an identify event" ) ;
568+ }
569+ }
570+
449571 #[ test]
450572 fn dispatcher_adds_index_on_custom_event ( ) {
451573 let ( event_sender, _) = create_event_sender ( ) ;
@@ -468,6 +590,62 @@ mod tests {
468590 assert_eq ! ( 1 , dispatcher. context_keys. len( ) ) ;
469591 }
470592
593+ #[ test]
594+ fn dispatcher_can_strip_anonymous_from_index_events ( ) {
595+ let ( event_sender, _) = create_event_sender ( ) ;
596+ let mut events_configuration =
597+ create_events_configuration ( event_sender, Duration :: from_secs ( 100 ) ) ;
598+ events_configuration. omit_anonymous_contexts = true ;
599+ let mut dispatcher = create_dispatcher ( events_configuration) ;
600+
601+ let context = ContextBuilder :: new ( "context" )
602+ . anonymous ( true )
603+ . build ( )
604+ . expect ( "Failed to create context" ) ;
605+ let event_factory = EventFactory :: new ( true ) ;
606+ let custom_event = event_factory
607+ . new_custom ( context, "context" , None , "" )
608+ . expect ( "failed to make new custom event" ) ;
609+
610+ dispatcher. process_event ( custom_event) ;
611+ assert_eq ! ( 1 , dispatcher. outbox. events. len( ) ) ;
612+ assert_eq ! ( "custom" , dispatcher. outbox. events[ 0 ] . kind( ) ) ;
613+ assert_eq ! ( 0 , dispatcher. context_keys. len( ) ) ;
614+ }
615+
616+ #[ test]
617+ fn dispatcher_can_strip_anonymous_from_index_events_with_multi_kinds ( ) {
618+ let ( event_sender, _) = create_event_sender ( ) ;
619+ let mut events_configuration =
620+ create_events_configuration ( event_sender, Duration :: from_secs ( 100 ) ) ;
621+ events_configuration. omit_anonymous_contexts = true ;
622+ let mut dispatcher = create_dispatcher ( events_configuration) ;
623+
624+ let user_context = ContextBuilder :: new ( "user" )
625+ . anonymous ( true )
626+ . build ( )
627+ . expect ( "Failed to create context" ) ;
628+ let org_context = ContextBuilder :: new ( "org" )
629+ . kind ( "org" )
630+ . build ( )
631+ . expect ( "Failed to create context" ) ;
632+ let context = MultiContextBuilder :: new ( )
633+ . add_context ( user_context)
634+ . add_context ( org_context)
635+ . build ( )
636+ . expect ( "Failed to create context" ) ;
637+ let event_factory = EventFactory :: new ( true ) ;
638+ let custom_event = event_factory
639+ . new_custom ( context, "context" , None , "" )
640+ . expect ( "failed to make new custom event" ) ;
641+
642+ dispatcher. process_event ( custom_event) ;
643+ assert_eq ! ( 2 , dispatcher. outbox. events. len( ) ) ;
644+ assert_eq ! ( "index" , dispatcher. outbox. events[ 0 ] . kind( ) ) ;
645+ assert_eq ! ( "custom" , dispatcher. outbox. events[ 1 ] . kind( ) ) ;
646+ assert_eq ! ( 1 , dispatcher. context_keys. len( ) ) ;
647+ }
648+
471649 #[ test]
472650 fn can_process_events_successfully ( ) {
473651 let ( event_sender, event_rx) = create_event_sender ( ) ;
0 commit comments