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 }