github.com/koko1123/flow-go-1@v0.29.6/engine/enqueue.go (about)

     1  package engine
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/koko1123/flow-go-1/model/flow"
     9  	"github.com/koko1123/flow-go-1/utils/logging"
    10  )
    11  
    12  type Message struct {
    13  	OriginID flow.Identifier
    14  	Payload  interface{}
    15  }
    16  
    17  // MessageStore is the interface to abstract how messages are buffered in memory before
    18  // being handled by the engine
    19  type MessageStore interface {
    20  	Put(*Message) bool
    21  	Get() (*Message, bool)
    22  }
    23  
    24  type Pattern struct {
    25  	// Match is a function to match a message to this pattern, typically by payload type.
    26  	Match MatchFunc
    27  	// Map is a function to apply to messages before storing them. If not provided, then the message is stored in its original form.
    28  	Map MapFunc
    29  	// Store is an abstract message store where we will store the message upon receipt.
    30  	Store MessageStore
    31  }
    32  
    33  type FilterFunc func(*Message) bool
    34  
    35  type MatchFunc func(*Message) bool
    36  
    37  type MapFunc func(*Message) (*Message, bool)
    38  
    39  type MessageHandler struct {
    40  	log      zerolog.Logger
    41  	notifier Notifier
    42  	patterns []Pattern
    43  }
    44  
    45  func NewMessageHandler(log zerolog.Logger, notifier Notifier, patterns ...Pattern) *MessageHandler {
    46  	return &MessageHandler{
    47  		log:      log.With().Str("component", "message_handler").Logger(),
    48  		notifier: notifier,
    49  		patterns: patterns,
    50  	}
    51  }
    52  
    53  // Process iterates over the internal processing patterns and determines if the payload matches.
    54  // The _first_ matching pattern processes the payload.
    55  // Returns
    56  //   - IncompatibleInputTypeError if no matching processor was found
    57  //   - All other errors are potential symptoms of internal state corruption or bugs (fatal).
    58  func (e *MessageHandler) Process(originID flow.Identifier, payload interface{}) error {
    59  	msg := &Message{
    60  		OriginID: originID,
    61  		Payload:  payload,
    62  	}
    63  
    64  	for _, pattern := range e.patterns {
    65  		if pattern.Match(msg) {
    66  			var keep bool
    67  			if pattern.Map != nil {
    68  				msg, keep = pattern.Map(msg)
    69  				if !keep {
    70  					return nil
    71  				}
    72  			}
    73  
    74  			ok := pattern.Store.Put(msg)
    75  			if !ok {
    76  				e.log.Warn().
    77  					Str("msg_type", logging.Type(payload)).
    78  					Hex("origin_id", originID[:]).
    79  					Msg("failed to store message - discarding")
    80  				return nil
    81  			}
    82  			e.notifier.Notify()
    83  
    84  			// message can only be matched by one pattern, and processed by one handler
    85  			return nil
    86  		}
    87  	}
    88  
    89  	return fmt.Errorf("no matching processor for message of type %T from origin %x: %w", payload, originID[:], IncompatibleInputTypeError)
    90  }
    91  
    92  func (e *MessageHandler) GetNotifier() <-chan struct{} {
    93  	return e.notifier.Channel()
    94  }