github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/helpers/rpcbroadcaster/broadcaster.go (about)

     1  package rpcbroadcaster
     2  
     3  import (
     4  	"time"
     5  
     6  	"go.uber.org/zap"
     7  )
     8  
     9  // RPCBroadcaster represents a generic RPC broadcaster.
    10  type RPCBroadcaster struct {
    11  	Clients   map[string]*RPCClient
    12  	Log       *zap.Logger
    13  	Responses chan []any
    14  
    15  	close       chan struct{}
    16  	finished    chan struct{}
    17  	sendTimeout time.Duration
    18  }
    19  
    20  // NewRPCBroadcaster returns a new RPC broadcaster instance.
    21  func NewRPCBroadcaster(log *zap.Logger, sendTimeout time.Duration) *RPCBroadcaster {
    22  	return &RPCBroadcaster{
    23  		Clients:     make(map[string]*RPCClient),
    24  		Log:         log,
    25  		close:       make(chan struct{}),
    26  		finished:    make(chan struct{}),
    27  		Responses:   make(chan []any),
    28  		sendTimeout: sendTimeout,
    29  	}
    30  }
    31  
    32  // Run implements oracle.Broadcaster.
    33  func (r *RPCBroadcaster) Run() {
    34  	for _, c := range r.Clients {
    35  		go c.run()
    36  	}
    37  run:
    38  	for {
    39  		select {
    40  		case <-r.close:
    41  			break run
    42  		case ps := <-r.Responses:
    43  			for _, c := range r.Clients {
    44  				select {
    45  				case c.responses <- ps:
    46  				default:
    47  					c.log.Error("can't send response, channel is full")
    48  				}
    49  			}
    50  		}
    51  	}
    52  	for _, c := range r.Clients {
    53  		<-c.finished
    54  	}
    55  drain:
    56  	for {
    57  		select {
    58  		case <-r.Responses:
    59  		default:
    60  			break drain
    61  		}
    62  	}
    63  	close(r.Responses)
    64  	close(r.finished)
    65  }
    66  
    67  // SendParams sends a request using all clients if the broadcaster is active.
    68  func (r *RPCBroadcaster) SendParams(params []any) {
    69  	select {
    70  	case <-r.close:
    71  	case r.Responses <- params:
    72  	}
    73  }
    74  
    75  // Shutdown implements oracle.Broadcaster. The same instance can't be Run again
    76  // after the shutdown.
    77  func (r *RPCBroadcaster) Shutdown() {
    78  	close(r.close)
    79  	<-r.finished
    80  }