package traverse // EventStage mirrors the :stage symbols reported by traverser.rb's // report_progress: new/start/answer/resolve plus the fast-mode and // multi-childset variants. type EventStage int const ( // StageNew fires when a referral node is created (before processing). StageNew EventStage = iota // StageStart fires when a referral is popped for processing. StageStart // StageNewReferralSet fires once per extra childset when more than one // IP of a server produced children. StageNewReferralSet // StageNewFast fires instead of StageNew when fast mode already knows // this referral will be completed from the memo. StageNewFast // StageResolve fires after a resolve subtree's statistics are folded // into the referral (post-order, Ruby's :calc_resolve marker). StageResolve // StageAnswer fires after a referral's statistics are calculated // (post-order, Ruby's :calc_answer marker). StageAnswer // StageAnswerFast fires when fast mode replaced the referral with an // earlier completed one instead of processing it. StageAnswerFast ) func (s EventStage) String() string { switch s { case StageNew: return "new" case StageStart: return "start" case StageNewReferralSet: return "new_referral_set" case StageNewFast: return "new_fast" case StageResolve: return "resolve" case StageAnswer: return "answer" case StageAnswerFast: return "answer_fast" default: return "unknown" } } // TraversalEvent is one progress callback. RefID/Status/IsResolve are // denormalised from Referral so renderers (CLI, web) need not walk the tree. type TraversalEvent struct { Stage EventStage Referral *Referral RefID string // Status summarises the referral's outcome so far (see // Referral.OverallStatus); empty before any response arrives. Status Status // IsResolve is true for nodes inside a glue-resolution subtree. IsResolve bool // CompletedEarlier carries the refid of the earlier identical referral // on fast-mode events (StageNewFast / StageAnswerFast). CompletedEarlier string } type EventHandler func(TraversalEvent) type TraverserHooks struct { OnEvent EventHandler } func (h *TraverserHooks) emit(stage EventStage, r *Referral, completedEarlier string) { if h == nil || h.OnEvent == nil || r == nil { return } h.OnEvent(TraversalEvent{ Stage: stage, Referral: r, RefID: r.RefID, Status: r.OverallStatus(), IsResolve: r.IsResolve(), CompletedEarlier: completedEarlier, }) }