Gateway: Added reconnect timeout; fixed UA (#154)

* Gateway: use gateway version 8

* API: remove old v0.0.1 version tag

* Discord: fix typos

* Gateway: add timeout

* Gateway: revert to returning errors on ReconnectCtx
This commit is contained in:
Maximilian von Lindern 2020-10-30 21:41:04 +01:00 committed by GitHub
parent f3372e016a
commit 607250ae55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 12 deletions

View File

@ -21,7 +21,7 @@ var (
EndpointGatewayBot = EndpointGateway + "/bot" EndpointGatewayBot = EndpointGateway + "/bot"
) )
var UserAgent = "DiscordBot (https://github.com/diamondburned/arikawa/v2, v0.0.1)" var UserAgent = "DiscordBot (https://github.com/diamondburned/arikawa/v2)"
type Client struct { type Client struct {
*httputil.Client *httputil.Client

View File

@ -128,7 +128,7 @@ const (
OverwriteMember OverwriteMember
) )
// UnmarshalJSON unmarshals both a string-quoteed number and a regular number // UnmarshalJSON unmarshalls both a string-quoted number and a regular number
// into OverwriteType. We need to do this because Discord is so bad that they // into OverwriteType. We need to do this because Discord is so bad that they
// can't even handle 1s and 0s properly. // can't even handle 1s and 0s properly.
func (otype *OverwriteType) UnmarshalJSON(b []byte) error { func (otype *OverwriteType) UnmarshalJSON(b []byte) error {

View File

@ -78,6 +78,13 @@ func BotURL(token string) (*BotData, error) {
type Gateway struct { type Gateway struct {
WS *wsutil.Websocket WS *wsutil.Websocket
WSTimeout time.Duration WSTimeout time.Duration
// ReconnectTimeout is the timeout used during reconnection.
// If the a connection to the gateway can't be established before the
// duration passes, the Gateway will be closed and FatalErrorCallback will
// be called.
//
// Setting this to 0 is equivalent to no timeout.
ReconnectTimeout time.Duration
// All events sent over are pointers to Event structs (structs suffixed with // All events sent over are pointers to Event structs (structs suffixed with
// "Event"). This shouldn't be accessed if the Gateway is created with a // "Event"). This shouldn't be accessed if the Gateway is created with a
@ -94,6 +101,16 @@ type Gateway struct {
PacerLoop wsutil.PacemakerLoop PacerLoop wsutil.PacemakerLoop
ErrorLog func(err error) // default to log.Println ErrorLog func(err error) // default to log.Println
// FatalErrorCallback is called, if the Gateway exits fatally. At the point
// of calling, the gateway will be already closed.
//
// Currently this will only be called, if the ReconnectTimeout was changed
// to a definite timeout, and connection could not be established during
// that time.
// err will be ErrWSMaxTries in that case.
//
// Defaults to noop.
FatalErrorCallback func(err error)
// AfterClose is called after each close. Error can be non-nil, as this is // AfterClose is called after each close. Error can be non-nil, as this is
// called even when the Gateway is gracefully closed. It's used mainly for // called even when the Gateway is gracefully closed. It's used mainly for
@ -182,20 +199,25 @@ func (g *Gateway) Close() error {
return err return err
} }
// Reconnect tries to reconnect forever. It will resume the connection if // Reconnect tries to reconnect until the ReconnectTimeout is reached, or if
// possible. If an Invalid Session is received, it will start a fresh one. // set to 0 reconnects indefinitely.
func (g *Gateway) Reconnect() { func (g *Gateway) Reconnect() {
for { ctx := context.Background()
if err := g.ReconnectCtx(context.Background()); err != nil {
g.ErrorLog(err) if g.ReconnectTimeout > 0 {
} else { var cancel func()
return ctx, cancel = context.WithTimeout(context.Background(), g.WSTimeout)
}
defer cancel()
} }
// ignore the error, it is already logged and FatalErrorCallback was called
g.ReconnectCtx(ctx)
} }
// ReconnectCtx attempts to reconnect until context expires. If context cannot // ReconnectCtx attempts to reconnect until context expires.
// expire, then the gateway will try to reconnect forever. // If the context expires FatalErrorCallback will be called with ErrWSMaxTries,
// and the last error returned by Open will be returned.
func (g *Gateway) ReconnectCtx(ctx context.Context) (err error) { func (g *Gateway) ReconnectCtx(ctx context.Context) (err error) {
wsutil.WSDebug("Reconnecting...") wsutil.WSDebug("Reconnecting...")
@ -206,6 +228,7 @@ func (g *Gateway) ReconnectCtx(ctx context.Context) (err error) {
for i := 1; ; i++ { for i := 1; ; i++ {
select { select {
case <-ctx.Done(): case <-ctx.Done():
g.FatalErrorCallback(ErrWSMaxTries)
return err return err
default: default:
} }