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 }