1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2025-07-23 13:20:51 +00:00

Compare commits

...

2 commits

3 changed files with 19 additions and 22 deletions

View file

@ -30,6 +30,11 @@ const (
GuildSubscriptionsOP OPCode = 14 GuildSubscriptionsOP OPCode = 14
) )
// ErrReconnectRequest is returned by HandleOP if a ReconnectOP is given. This
// is used mostly internally to signal the heartbeat loop to reconnect, if
// needed. It is not a fatal error.
var ErrReconnectRequest = errors.New("ReconnectOP received")
func (g *Gateway) HandleOP(op *wsutil.OP) error { func (g *Gateway) HandleOP(op *wsutil.OP) error {
switch op.Code { switch op.Code {
case HeartbeatAckOP: case HeartbeatAckOP:
@ -47,13 +52,9 @@ func (g *Gateway) HandleOP(op *wsutil.OP) error {
// Server requests to reconnect, die and retry. // Server requests to reconnect, die and retry.
wsutil.WSDebug("ReconnectOP received.") wsutil.WSDebug("ReconnectOP received.")
// We must reconnect in another goroutine, as running Reconnect // Exit with the ReconnectOP error to force the heartbeat event loop to
// synchronously would prevent the main event loop from exiting. // reconnect synchronously. Not really a fatal error.
go g.Reconnect() return ErrReconnectRequest
// Gracefully exit with a nil let the event handler take the signal from
// the pacemaker.
return nil
case InvalidSessionOP: case InvalidSessionOP:
// Discord expects us to sleep for no reason // Discord expects us to sleep for no reason
@ -101,7 +102,7 @@ func (g *Gateway) HandleOP(op *wsutil.OP) error {
g.SessionID = ev.SessionID g.SessionID = ev.SessionID
} }
// Throw the event into a channel, it's valid now. // Throw the event into a channel; it's valid now.
g.Events <- ev g.Events <- ev
return nil return nil

View file

@ -4,6 +4,8 @@
package session package session
import ( import (
"sync"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/diamondburned/arikawa/api" "github.com/diamondburned/arikawa/api"
@ -39,6 +41,7 @@ type Session struct {
Ticket string Ticket string
hstop chan struct{} hstop chan struct{}
wstop sync.Once
} }
func NewWithIntents(token string, intents ...gateway.Intents) (*Session, error) { func NewWithIntents(token string, intents ...gateway.Intents) (*Session, error) {
@ -103,9 +106,9 @@ func NewWithGateway(gw *gateway.Gateway) *Session {
func (s *Session) Open() error { func (s *Session) Open() error {
// Start the handler beforehand so no events are missed. // Start the handler beforehand so no events are missed.
stop := make(chan struct{}) s.hstop = make(chan struct{})
s.hstop = stop s.wstop = sync.Once{}
go s.startHandler(stop) go s.startHandler()
// Set the AfterClose's handler. // Set the AfterClose's handler.
s.Gateway.AfterClose = func(err error) { s.Gateway.AfterClose = func(err error) {
@ -121,10 +124,10 @@ func (s *Session) Open() error {
return nil return nil
} }
func (s *Session) startHandler(stop <-chan struct{}) { func (s *Session) startHandler() {
for { for {
select { select {
case <-stop: case <-s.hstop:
return return
case ev := <-s.Gateway.Events: case ev := <-s.Gateway.Events:
s.Call(ev) s.Call(ev)
@ -134,14 +137,7 @@ func (s *Session) startHandler(stop <-chan struct{}) {
func (s *Session) Close() error { func (s *Session) Close() error {
// Stop the event handler // Stop the event handler
s.close() s.wstop.Do(func() { s.hstop <- struct{}{} })
// Close the websocket // Close the websocket
return s.Gateway.Close() return s.Gateway.Close()
} }
func (s *Session) close() {
if s.hstop != nil {
close(s.hstop)
}
}

View file

@ -108,7 +108,7 @@ func (p *PacemakerLoop) startLoop() error {
// Handle the event // Handle the event
if err := p.handler(o); err != nil { if err := p.handler(o); err != nil {
p.errorLog(errors.Wrap(err, "handler failed")) return errors.Wrap(err, "handler failed")
} }
} }
} }