diff --git a/gateway/gateway.go b/gateway/gateway.go index 222d83b..b044584 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -85,11 +85,14 @@ type Gateway struct { // Session. Events chan Event + // SessionID is used to store the session ID received after Ready. It is not + // thread-safe. SessionID string Identifier *Identifier Sequence *Sequence - PacerLoop *wsutil.PacemakerLoop + + PacerLoop wsutil.PacemakerLoop ErrorLog func(err error) // default to log.Println @@ -98,11 +101,6 @@ type Gateway struct { // reconnections or any type of connection interruptions. AfterClose func(err error) // noop by default - // Mutex to hold off calls when the WS is not available. Doesn't block if - // Start() is not called or Close() is called. Also doesn't block for - // Identify or Resume. - // available sync.RWMutex - // Filled by methods, internal use waitGroup *sync.WaitGroup } @@ -356,13 +354,11 @@ func (g *Gateway) start(ctx context.Context) error { return errors.Wrap(err, "first error") } - // Use the pacemaker loop. - g.PacerLoop = wsutil.NewLoop(hello.HeartbeatInterval.Duration(), ch, g) - // Start the event handler, which also handles the pacemaker death signal. g.waitGroup.Add(1) - g.PacerLoop.RunAsync(func(err error) { + // Use the pacemaker loop. + g.PacerLoop.RunAsync(hello.HeartbeatInterval.Duration(), ch, g, func(err error) { g.waitGroup.Done() // mark so Close() can exit. wsutil.WSDebug("Event loop stopped with error:", err) diff --git a/gateway/op.go b/gateway/op.go index 2d6e0d6..e5d5b45 100644 --- a/gateway/op.go +++ b/gateway/op.go @@ -71,7 +71,6 @@ func (g *Gateway) HandleOP(op *wsutil.OP) error { return nil case HelloOP: - // What is this OP doing here??? return nil case DispatchOP: diff --git a/utils/wsutil/heart.go b/utils/wsutil/heart.go index 348e1ba..e4d9f69 100644 --- a/utils/wsutil/heart.go +++ b/utils/wsutil/heart.go @@ -16,7 +16,8 @@ type EventLoopHandler interface { HeartbeatCtx(context.Context) error } -// PacemakerLoop provides an event loop with a pacemaker. +// PacemakerLoop provides an event loop with a pacemaker. A zero-value instance +// is a valid instance only when RunAsync is called first. type PacemakerLoop struct { pacemaker *heart.Pacemaker // let's not copy this pacedeath chan error @@ -31,14 +32,6 @@ type PacemakerLoop struct { ErrorLog func(error) } -func NewLoop(heartrate time.Duration, evs <-chan Event, evl EventLoopHandler) *PacemakerLoop { - return &PacemakerLoop{ - pacemaker: heart.NewPacemaker(heartrate, evl.HeartbeatCtx), - events: evs, - handler: evl.HandleOP, - } -} - func (p *PacemakerLoop) errorLog(err error) { if p.ErrorLog == nil { WSDebug("Uncaught error:", err) @@ -67,9 +60,15 @@ func (p *PacemakerLoop) Stopped() bool { return p == nil || !p.running.Get() } -func (p *PacemakerLoop) RunAsync(exit func(error)) { +func (p *PacemakerLoop) RunAsync( + heartrate time.Duration, evs <-chan Event, evl EventLoopHandler, exit func(error)) { + WSDebug("Starting the pacemaker loop.") + p.pacemaker = heart.NewPacemaker(heartrate, evl.HeartbeatCtx) + p.events = evs + p.handler = evl.HandleOP + // callers should explicitly handle waitgroups. p.pacedeath = p.pacemaker.StartAsync(nil) p.running.Set(true) diff --git a/voice/voicegateway/gateway.go b/voice/voicegateway/gateway.go index 76dac4b..7be7fdb 100644 --- a/voice/voicegateway/gateway.go +++ b/voice/voicegateway/gateway.go @@ -181,13 +181,10 @@ func (c *Gateway) __start(ctx context.Context) error { return errors.Wrap(err, "failed to wait for Ready or Resumed") } - // Create an event loop executor. - c.EventLoop = wsutil.NewLoop(hello.HeartbeatInterval.Duration(), ch, c) - // Start the event handler, which also handles the pacemaker death signal. c.waitGroup.Add(1) - c.EventLoop.RunAsync(func(err error) { + c.EventLoop.RunAsync(hello.HeartbeatInterval.Duration(), ch, c, func(err error) { c.waitGroup.Done() // mark so Close() can exit. wsutil.WSDebug("Event loop stopped.")