github.com/diamondburned/arikawa/v2@v2.1.0/internal/handleloop/handleloop.go (about)

     1  // Package handleloop provides clean abstractions to handle listening to
     2  // channels and passing them onto event handlers.
     3  package handleloop
     4  
     5  import "github.com/diamondburned/arikawa/v2/utils/handler"
     6  
     7  // Loop provides a reusable event looper abstraction. It is thread-safe to use
     8  // concurrently.
     9  type Loop struct {
    10  	dst  *handler.Handler
    11  	run  chan struct{}
    12  	stop chan struct{}
    13  }
    14  
    15  func NewLoop(dst *handler.Handler) *Loop {
    16  	return &Loop{
    17  		dst:  dst,
    18  		run:  make(chan struct{}, 1), // intentional 1 buffer
    19  		stop: make(chan struct{}),    // intentional unbuffer
    20  	}
    21  }
    22  
    23  // Start starts a new event loop. It will try to stop existing loops before.
    24  func (l *Loop) Start(src <-chan interface{}) {
    25  	// Ensure we're stopped.
    26  	l.Stop()
    27  
    28  	// Mark that we're running.
    29  	l.run <- struct{}{}
    30  
    31  	go func() {
    32  		for {
    33  			select {
    34  			case event := <-src:
    35  				l.dst.Call(event)
    36  
    37  			case <-l.stop:
    38  				l.stop <- struct{}{}
    39  				return
    40  			}
    41  		}
    42  	}()
    43  }
    44  
    45  // Stop tries to stop the Loop. If the Loop is not running, then it does
    46  // nothing; thus, it can be called multiple times.
    47  func (l *Loop) Stop() {
    48  	// Ensure that we are running before stopping.
    49  	select {
    50  	case <-l.run:
    51  		// running
    52  	default:
    53  		return
    54  	}
    55  
    56  	// send a close request
    57  	l.stop <- struct{}{}
    58  	// wait for a reply
    59  	<-l.stop
    60  }