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

     1  package relay
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/koko1123/flow-go-1/engine"
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/network"
    11  	"github.com/koko1123/flow-go-1/network/channels"
    12  )
    13  
    14  // Relay engine relays all the messages that are received to the given network for the corresponding channel
    15  type Engine struct {
    16  	unit     *engine.Unit                         // used to manage concurrency & shutdown
    17  	log      zerolog.Logger                       // used to log relevant actions with context
    18  	conduits map[channels.Channel]network.Conduit // conduits for unstaked network
    19  }
    20  
    21  func New(
    22  	log zerolog.Logger,
    23  	channelList channels.ChannelList,
    24  	net network.Network,
    25  	unstakedNet network.Network,
    26  ) (*Engine, error) {
    27  	e := &Engine{
    28  		unit:     engine.NewUnit(),
    29  		log:      log.With().Str("engine", "relay").Logger(),
    30  		conduits: make(map[channels.Channel]network.Conduit),
    31  	}
    32  
    33  	for _, channel := range channelList {
    34  		_, err := net.Register(channel, e)
    35  		if err != nil {
    36  			return nil, fmt.Errorf("could not register relay engine on channel: %w", err)
    37  		}
    38  
    39  		conduit, err := unstakedNet.Register(channel, e)
    40  		if err != nil {
    41  			return nil, fmt.Errorf("could not register relay engine on unstaked network channel: %w", err)
    42  		}
    43  		e.conduits[channel] = conduit
    44  	}
    45  
    46  	return e, nil
    47  }
    48  
    49  // Ready returns a ready channel that is closed once the engine has fully
    50  // started.
    51  func (e *Engine) Ready() <-chan struct{} {
    52  	return e.unit.Ready()
    53  }
    54  
    55  // Done returns a done channel that is closed once the engine has fully stopped.
    56  func (e *Engine) Done() <-chan struct{} {
    57  	return e.unit.Done()
    58  }
    59  
    60  // SubmitLocal submits an event originating on the local node.
    61  func (e *Engine) SubmitLocal(event interface{}) {
    62  	e.unit.Launch(func() {
    63  		err := e.ProcessLocal(event)
    64  		if err != nil {
    65  			engine.LogError(e.log, err)
    66  		}
    67  	})
    68  }
    69  
    70  // ProcessLocal processes an event originating on the local node.
    71  func (e *Engine) ProcessLocal(event interface{}) error {
    72  	return e.unit.Do(func() error {
    73  		return fmt.Errorf("relay engine does not process local events")
    74  	})
    75  }
    76  
    77  // Submit submits the given event from the node with the given origin ID
    78  // for processing in a non-blocking manner. It returns instantly and logs
    79  // a potential processing error internally when done.
    80  func (e *Engine) Submit(channel channels.Channel, originID flow.Identifier, event interface{}) {
    81  	e.unit.Launch(func() {
    82  		err := e.Process(channel, originID, event)
    83  		if err != nil {
    84  			engine.LogError(e.log, err)
    85  		}
    86  	})
    87  }
    88  
    89  // Process processes the given event from the node with the given origin ID
    90  // in a blocking manner. It returns the potential processing error when
    91  // done.
    92  func (e *Engine) Process(channel channels.Channel, originID flow.Identifier, event interface{}) error {
    93  	return e.unit.Do(func() error {
    94  		return e.process(channel, originID, event)
    95  	})
    96  }
    97  
    98  func (e *Engine) process(channel channels.Channel, originID flow.Identifier, event interface{}) error {
    99  	conduit, ok := e.conduits[channel]
   100  
   101  	if !ok {
   102  		return fmt.Errorf("received message on unknown channel %s", channel)
   103  	}
   104  
   105  	e.log.Trace().Interface("event", event).Str("channel", channel.String()).Str("originID", originID.String()).Msg("relaying message")
   106  
   107  	// We use a dummy target ID here so that events are broadcast to the entire network
   108  	if err := conduit.Publish(event, flow.ZeroID); err != nil {
   109  		return fmt.Errorf("could not relay message: %w", err)
   110  	}
   111  
   112  	return nil
   113  }