// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package submatview import ( "github.com/hashicorp/consul/proto/private/pbsubscribe" ) // eventHandler is a function which performs some operation on the received // events, then returns the eventHandler that should be used for the next set // of events. // If eventHandler fails to handle the events it may return an error. If an // error is returned the next eventHandler will be ignored. // eventHandler is used to implement a very simple finite-state machine. type eventHandler func(state viewState, events *pbsubscribe.Event) (next eventHandler, err error) type viewState interface { updateView(events []*pbsubscribe.Event, index uint64) error reset() } func initialHandler(index uint64) eventHandler { if index == 0 { return newSnapshotHandler() } return resumeStreamHandler } // snapshotHandler accumulates events. When it receives an EndOfSnapshot event // it updates the view, and then returns eventStreamHandler to handle new events. type snapshotHandler struct { events []*pbsubscribe.Event } func newSnapshotHandler() eventHandler { return (&snapshotHandler{}).handle } func (h *snapshotHandler) handle(state viewState, event *pbsubscribe.Event) (eventHandler, error) { if event.GetEndOfSnapshot() { err := state.updateView(h.events, event.Index) return eventStreamHandler, err } h.events = append(h.events, eventsFromEvent(event)...) return h.handle, nil } // eventStreamHandler handles events by updating the view. It always returns // itself as the next handler. func eventStreamHandler(state viewState, event *pbsubscribe.Event) (eventHandler, error) { err := state.updateView(eventsFromEvent(event), event.Index) return eventStreamHandler, err } func eventsFromEvent(event *pbsubscribe.Event) []*pbsubscribe.Event { if batch := event.GetEventBatch(); batch != nil { return batch.Events } return []*pbsubscribe.Event{event} } // resumeStreamHandler checks if the event is a NewSnapshotToFollow event. If it // is it resets the view and returns a snapshotHandler to handle the next event. // Otherwise it uses eventStreamHandler to handle events. func resumeStreamHandler(state viewState, event *pbsubscribe.Event) (eventHandler, error) { if event.GetNewSnapshotToFollow() { state.reset() return newSnapshotHandler(), nil } return eventStreamHandler(state, event) }