go.dedis.ch/onet/v4@v4.0.0-pre1/network/dispatch.go (about)

     1  package network
     2  
     3  import (
     4  	"sync"
     5  
     6  	"go.dedis.ch/onet/v4/log"
     7  	"golang.org/x/xerrors"
     8  )
     9  
    10  // Dispatcher is an interface whose sole role is to distribute messages to the
    11  // right Processor. No processing is done,i.e. no looking at packet content.
    12  // Each Processor that wants to receive all messages of a specific
    13  // type must register itself to the dispatcher using `RegisterProcessor()`.
    14  // The network layer calls `Dispatch()` each time it receives a message, so
    15  // the dispatcher is able to dispatch correctly to the corresponding Processor.
    16  // Two Dispatchers are available:
    17  //   * BlockingDispatcher - waits for the return of the Processor before taking
    18  //     another message
    19  //   * RoutineDispatcher - starts every Processor in a go-routine
    20  type Dispatcher interface {
    21  	// RegisterProcessor is called by a Processor so it can receive all messages
    22  	// of type msgType. If given multiple msgType, the same processor will be
    23  	// called for each of the msgType given.
    24  	// **NOTE** In the current version, if a subsequent call to RegisterProcessor
    25  	// happens for the same msgType, the latest Processor will be used; there
    26  	// is no *copy* or *duplication* of messages.
    27  	RegisterProcessor(p Processor, msgType ...MessageTypeID)
    28  	// RegisterProcessorFunc enables to register directly a function that will
    29  	// be called for each message of type msgType. It's a shorter way of
    30  	// registering a Processor.
    31  	RegisterProcessorFunc(MessageTypeID, func(*Envelope) error)
    32  	// Dispatch will find the right processor to dispatch the packet to. The id
    33  	// is the identity of the author / sender of the packet.
    34  	// It can be called for example by the network layer.
    35  	// If no processor is found for this message type, then an error is returned
    36  	Dispatch(*Envelope) error
    37  }
    38  
    39  // Processor is an abstraction to represent any object that want to process
    40  // messages. It is used in conjunction with Dispatcher:
    41  // A processor must register itself to a Dispatcher so the Dispatcher will
    42  // dispatch every messages asked for to the Processor.
    43  type Processor interface {
    44  	// Process takes a received Envelope.
    45  	Process(*Envelope)
    46  }
    47  
    48  // BlockingDispatcher is a Dispatcher that simply calls `p.Process()` on a
    49  // processor p each time it receives a message with `Dispatch`. It does *not*
    50  // launch a go routine, or put the message in a queue, etc.
    51  // It can be re-used for more complex dispatchers.
    52  type BlockingDispatcher struct {
    53  	sync.Mutex
    54  	procs map[MessageTypeID]Processor
    55  }
    56  
    57  // NewBlockingDispatcher will return a new BlockingDispatcher.
    58  func NewBlockingDispatcher() *BlockingDispatcher {
    59  	return &BlockingDispatcher{
    60  		procs: make(map[MessageTypeID]Processor),
    61  	}
    62  }
    63  
    64  // RegisterProcessor saves the given processor in the dispatcher.
    65  func (d *BlockingDispatcher) RegisterProcessor(p Processor, msgType ...MessageTypeID) {
    66  	d.Lock()
    67  	defer d.Unlock()
    68  	for _, t := range msgType {
    69  		d.procs[t] = p
    70  	}
    71  }
    72  
    73  // RegisterProcessorFunc takes a func, creates a Processor struct around it and
    74  // registers it to the dispatcher.
    75  func (d *BlockingDispatcher) RegisterProcessorFunc(msgType MessageTypeID, fn func(*Envelope) error) {
    76  	p := &defaultProcessor{
    77  		fn: fn,
    78  	}
    79  	d.RegisterProcessor(p, msgType)
    80  }
    81  
    82  // Dispatch calls the corresponding processor's method Process. It's a
    83  // blocking call if the Processor is blocking.
    84  func (d *BlockingDispatcher) Dispatch(packet *Envelope) error {
    85  	// cannot use the "defer unlock" idiom here because we cannot
    86  	// be holding the lock while calling p.Process in case the
    87  	// processor wants to call RegisterProcessor.
    88  	d.Lock()
    89  	var p Processor
    90  	if p = d.procs[packet.MsgType]; p == nil {
    91  		d.Unlock()
    92  		return xerrors.New("No Processor attached to this message type " + packet.MsgType.String())
    93  	}
    94  	d.Unlock()
    95  	p.Process(packet)
    96  	return nil
    97  }
    98  
    99  // RoutineDispatcher dispatches messages to the Processors
   100  // in a go routine. RoutineDispatcher creates one go routine per messages it
   101  // receives.
   102  type RoutineDispatcher struct {
   103  	*BlockingDispatcher
   104  	// routines counts how many routines are running
   105  	routines      int
   106  	routinesMutex sync.Mutex
   107  }
   108  
   109  // NewRoutineDispatcher returns a fresh RoutineDispatcher
   110  func NewRoutineDispatcher() *RoutineDispatcher {
   111  	return &RoutineDispatcher{
   112  		BlockingDispatcher: NewBlockingDispatcher(),
   113  	}
   114  }
   115  
   116  // Dispatch implements the Dispatcher interface. It will give the packet to the
   117  // right Processor in a go routine.
   118  func (d *RoutineDispatcher) Dispatch(packet *Envelope) error {
   119  	d.Lock()
   120  	defer d.Unlock()
   121  	var p = d.procs[packet.MsgType]
   122  	if p == nil {
   123  		return xerrors.New("no Processor attached to this message type")
   124  	}
   125  	go func() {
   126  		d.routinesMutex.Lock()
   127  		d.routines++
   128  		d.routinesMutex.Unlock()
   129  		p.Process(packet)
   130  		d.routinesMutex.Lock()
   131  		d.routines--
   132  		d.routinesMutex.Unlock()
   133  	}()
   134  	return nil
   135  }
   136  
   137  // GetRoutines returns how many routines are waiting.
   138  func (d *RoutineDispatcher) GetRoutines() int {
   139  	d.routinesMutex.Lock()
   140  	defer d.routinesMutex.Unlock()
   141  	return d.routines
   142  }
   143  
   144  type defaultProcessor struct {
   145  	fn func(*Envelope) error
   146  }
   147  
   148  func (dp *defaultProcessor) Process(msg *Envelope) {
   149  	err := dp.fn(msg)
   150  	if err != nil {
   151  		log.Errorf("error while processing msg type %v from %v: %+v", msg.MsgType, msg.ServerIdentity, err)
   152  	}
   153  }