ws

package
v3.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2024 License: ISC Imports: 13 Imported by: 14

Documentation

Overview

Package wsutil provides abstractions around the Websocket, including rate limits.

Index

Constants

This section is empty.

Variables

View Source
var (
	// WSError is the default error handler
	WSError = func(err error) { log.Println("Gateway error:", err) }
	// WSDebug is used for extra debug logging. This is expected to behave
	// similarly to log.Println().
	WSDebug = func(v ...interface{}) {}
)
View Source
var DefaultGatewayOpts = GatewayOpts{
	ReconnectDelay: func(try int) time.Duration {

		return time.Duration(4+(2*try)) * time.Second
	},
	DialTimeout:           0,
	ReconnectAttempt:      0,
	AlwaysCloseGracefully: true,
}

DefaultGatewayOpts is the default event loop options.

View Source
var EnableRawEvents = false

EnableRawEvents, if true, will cause ws to generate a RawEvent for each regular Event. It should only be used for debugging.

View Source
var ErrWebsocketClosed = errors.New("websocket is closed")

ErrWebsocketClosed is returned if the websocket is already closed.

View Source
var SendBurst = 5

SendBurst determines the number of gateway commands that can be sent all at once before being throttled. The higher the burst, the slower the rate limiter recovers.

Functions

func IsUnknownEvent

func IsUnknownEvent(err error) bool

IsBrokenConnection returns true if the error is a broken connection error.

func NewDialLimiter

func NewDialLimiter() *rate.Limiter

NewDialLimiter returns a rate limiter for throttling new gateway connections.

func NewGlobalIdentityLimiter

func NewGlobalIdentityLimiter() *rate.Limiter

NewGlobalIdentityLimiter returns a rate limiter for throttling global gateway Identify commands.

func NewIdentityLimiter

func NewIdentityLimiter() *rate.Limiter

NewIdentityLimiter returns a rate limiter for throttling gateway Identify commands.

func NewSendLimiter

func NewSendLimiter() *rate.Limiter

NewSendLimiter returns a rate limiter for throttling gateway commands.

Types

type BackgroundErrorEvent

type BackgroundErrorEvent struct {
	Err error
}

BackgroundErrorEvent describes an error that the gateway event loop might stumble upon while it's running. See Gateway's documentation for possible usages.

func (*BackgroundErrorEvent) Error

func (err *BackgroundErrorEvent) Error() string

Error formats the BackgroundErrorEvent.

func (*BackgroundErrorEvent) EventType

func (err *BackgroundErrorEvent) EventType() EventType

EventType implements Op. It returns an opaque unique string.

func (*BackgroundErrorEvent) Op

func (err *BackgroundErrorEvent) Op() OpCode

Op implements Op. It returns -1.

func (*BackgroundErrorEvent) Unwrap

func (err *BackgroundErrorEvent) Unwrap() error

Unwrap returns err.Err.

type Broadcaster

type Broadcaster struct {
	// contains filtered or unexported fields
}

Broadcaster is primarily used for debugging.

func NewBroadcaster

func NewBroadcaster(src <-chan Op) *Broadcaster

NewBroadcaster creates a new broadcaster.

func (*Broadcaster) NewSubscribed

func (b *Broadcaster) NewSubscribed() <-chan Op

NewSubscribed creates a newly subscribed Op channel.

func (*Broadcaster) Start

func (b *Broadcaster) Start()

Start starts the broadcasting loop.

func (*Broadcaster) Subscribe

func (b *Broadcaster) Subscribe(ch chan<- Op)

Subscribe subscribes the given channel

type CloseEvent

type CloseEvent struct {
	// Err is the underlying error.
	Err error
	// Code is the websocket close code, if any. It is -1 otherwise.
	Code int
}

CloseEvent is an event that is given from wsutil when the websocket is closed.

func (*CloseEvent) Error

func (e *CloseEvent) Error() string

Error formats the CloseEvent. A CloseEvent is also an error.

func (*CloseEvent) EventType

func (e *CloseEvent) EventType() EventType

EventType implements Event. It returns an emty string.

func (*CloseEvent) Op

func (e *CloseEvent) Op() OpCode

Op implements Event. It returns -1.

func (*CloseEvent) Unwrap

func (e *CloseEvent) Unwrap() error

Unwrap returns err.Err.

type Codec

type Codec struct {
	Unmarshalers OpUnmarshalers
	Headers      http.Header
}

Codec holds the codec states for Websocket implementations to share with the manager. It is used internally in the Websocket and the Connection implementation.

func NewCodec

func NewCodec(unmarshalers OpUnmarshalers) Codec

NewCodec creates a new default Codec instance.

func (Codec) DecodeInto

func (c Codec) DecodeInto(ctx context.Context, r io.Reader, buf *DecodeBuffer, out chan<- Op) error

DecodeInto reads the given reader and decodes it into the Op out channel.

buf is optional.

type Conn

type Conn struct {

	// CloseTimeout is the timeout for graceful closing. It's defaulted to 5s.
	CloseTimeout time.Duration
	// contains filtered or unexported fields
}

Conn is the default Websocket connection. It tries to compresses all payloads using zlib.

func NewConn

func NewConn(codec Codec) *Conn

NewConn creates a new default websocket connection with a default dialer.

func NewConnWithDialer

func NewConnWithDialer(codec Codec, dialer websocket.Dialer) *Conn

NewConnWithDialer creates a new default websocket connection with a custom dialer.

func (*Conn) Close

func (c *Conn) Close(gracefully bool) error

Close implements Connection.

func (*Conn) Dial

func (c *Conn) Dial(ctx context.Context, addr string) (<-chan Op, error)

Dial starts a new connection and returns the listening channel for it. If the websocket is already dialed, then the connection is closed first.

func (*Conn) Send

func (c *Conn) Send(ctx context.Context, b []byte) error

Send implements Connection.

type Connection

type Connection interface {
	// Dial dials the address (string). Context needs to be passed in for
	// timeout. This method should also be re-usable after Close is called.
	Dial(context.Context, string) (<-chan Op, error)

	// Send allows the caller to send bytes.
	Send(context.Context, []byte) error

	// Close should close the websocket connection. The underlying connection
	// may be reused, but this Connection instance will be reused with Dial. The
	// Connection must still be reusable even if Close returns an error. If
	// gracefully is true, then the implementation must send a close frame
	// prior.
	Close(gracefully bool) error
}

Connection is an interface that abstracts around a generic Websocket driver. This connection expects the driver to handle compression by itself, including modifying the connection URL. The implementation doesn't have to be safe for concurrent use.

type ConnectionError

type ConnectionError struct {
	Err error
}

ConnectionError is given to the user if the gateway fails to connect to the gateway for any reason, including during an initial connection or a reconnection. To check for this error, use the errors.As function.

func (ConnectionError) Error

func (err ConnectionError) Error() string

Error formats the error.

func (ConnectionError) Unwrap

func (err ConnectionError) Unwrap() error

Unwrap unwraps the ConnectionError.

type DecodeBuffer

type DecodeBuffer struct {
	// contains filtered or unexported fields
}

DecodeBuffer boxes a byte slice to provide a shared and thread-unsafe buffer. It is used internally and should only be handled around as an opaque thing.

func NewDecodeBuffer

func NewDecodeBuffer(cap int) DecodeBuffer

NewDecodeBuffer creates a new preallocated DecodeBuffer.

type Event

type Event interface {
	Op() OpCode
	EventType() EventType
}

Event describes an Event data that comes from a gateway Operation.

type EventType

type EventType string

EventType is a type for event types, which is the "t" field in the payload.

type Gateway

type Gateway struct {
	// contains filtered or unexported fields
}

Gateway describes an instance that handles the Discord gateway. It is basically an abstracted concurrent event loop that the user could signal to start connecting to the Discord gateway server.

func NewGateway

func NewGateway(ws *Websocket, opts *GatewayOpts) *Gateway

NewGateway creates a new Gateway with a custom gateway URL and a pre-existing Identifier. If opts is nil, then DefaultOpts is used.

func (*Gateway) AssertIsNotRunning

func (g *Gateway) AssertIsNotRunning()

AssertIsNotRunning asserts that the gateway is currently not running. If the gateway is running, the method will panic. Since a gateway cannot be started back up, this method can be used to detect whether or not the caller in a single goroutine can read the state safely.

func (*Gateway) Connect

func (g *Gateway) Connect(ctx context.Context, h Handler) <-chan Op

Connect starts the background goroutine that tries its best to maintain a stable connection to the Websocket gateway. To the user, the gateway should appear to be working seamlessly.

For more documentation, refer to (*gateway.Gateway).Connect.

func (*Gateway) HasStarted

func (g *Gateway) HasStarted() bool

HasStarted returns true if the gateway event loop is currently spinning.

func (*Gateway) LastError

func (g *Gateway) LastError() error

LastError returns the last error that the gateway has received.

func (*Gateway) Opts added in v3.2.0

func (g *Gateway) Opts() *GatewayOpts

Opts returns a copy of the gateway options. The options can only be changed during construction, so a copy is a must.

func (*Gateway) QueueReconnect

func (g *Gateway) QueueReconnect()

QueueReconnect queues a reconnection in the gateway loop. This method should only be called in the event loop ONCE; calling more than once will deadlock the loop.

func (*Gateway) ResetHeartbeat

func (g *Gateway) ResetHeartbeat(d time.Duration)

ResetHeartbeat resets the heartbeat to be the given duration.

func (*Gateway) Send

func (g *Gateway) Send(ctx context.Context, data Event) error

Send is a function to send an Op payload to the Gateway.

func (*Gateway) SendError

func (g *Gateway) SendError(err error)

SendError sends the given error wrapped in a BackgroundErrorEvent into the event channel.

func (*Gateway) SendErrorWrap

func (g *Gateway) SendErrorWrap(err error, message string)

SendErrorWrap is a convenient function over SendError.

type GatewayOpts

type GatewayOpts struct {
	// ReconnectDelay determines the duration to idle after each failed retry.
	// This can be used to implement exponential backoff. The default is already
	// sane, so this field rarely needs to be changed.
	ReconnectDelay func(try int) time.Duration

	// FatalCloseCodes is a list of close codes that will cause the gateway to
	// exit out if it stumbles on one of these. It is a copy of FatalCloseCodes
	// (the global variable) by default.
	FatalCloseCodes []int

	// DialTimeout is the timeout to wait for each websocket dial before failing
	// it and retrying. Default is 0.
	DialTimeout time.Duration

	// ReconnectAttempt is the maximum number of attempts made to Reconnect
	// before aborting the whole gateway. If this set to 0, unlimited attempts
	// will be made. Default is 0.
	ReconnectAttempt int

	// AlwaysCloseGracefully, if true, will always make the Gateway close
	// gracefully once the context given to Open is cancelled. It governs the
	// Close behavior. The default is true.
	AlwaysCloseGracefully bool
}

GatewayOpts describes the gateway event loop options.

func (GatewayOpts) ErrorIsFatalClose added in v3.2.0

func (opts GatewayOpts) ErrorIsFatalClose(err error) bool

ErrorIsFatalClose returns true if the error is a fatal close error. It uses opts.FatalCloseCodes to check for the codes.

type Handler

type Handler interface {
	// OnOp is called by the gateway event loop on every new Op. If the returned
	// boolean is false, then the loop fatally exits.
	OnOp(context.Context, Op) (canContinue bool)
	// SendHeartbeat is called by the gateway event loop everytime a heartbeat
	// needs to be sent over.
	SendHeartbeat(context.Context)
	// Close closes the handler.
	Close() error
}

Handler describes a gateway handler. It describes the core that governs the behavior of the gateway event loop.

type Op

type Op struct {
	Code OpCode `json:"op"`
	Data Event  `json:"d,omitempty"`

	// Type is only for gateway dispatch events.
	Type EventType `json:"t,omitempty"`
	// Sequence is only for gateway dispatch events (Op 0).
	Sequence int64 `json:"s,omitempty"`
}

Op is a gateway Operation.

func ReadOp

func ReadOp(ctx context.Context, ch <-chan Op) (Op, error)

ReadOp reads a single Op.

func ReadOps

func ReadOps(ctx context.Context, ch <-chan Op, n int) ([]Op, error)

ReadOps reads maximum n Ops and accumulate them into a slice.

type OpCode

type OpCode int

OpCode is the type for websocket Op codes. Op codes less than 0 are internal Op codes and should usually be ignored.

type OpFunc

type OpFunc func() Event

OpFunc is a constructor function for an Operation.

type OpUnmarshalers

type OpUnmarshalers struct {
	// contains filtered or unexported fields
}

OpUnmarshalers contains a map of event constructor function.

func NewOpUnmarshalers

func NewOpUnmarshalers(funcs ...OpFunc) OpUnmarshalers

NewOpUnmarshalers creates a nwe OpUnmarshalers instance from the given constructor functions.

func (OpUnmarshalers) Add

func (m OpUnmarshalers) Add(funcs ...OpFunc)

Add adds the given functions into the unmarshaler registry.

func (OpUnmarshalers) Each

func (m OpUnmarshalers) Each(f func(OpCode, EventType, OpFunc) (done bool))

Each iterates over the marshaler map.

func (OpUnmarshalers) Lookup

func (m OpUnmarshalers) Lookup(op OpCode, t EventType) OpFunc

Lookup searches the OpMarshalers map for the given constructor function.

type RawEvent

type RawEvent struct {
	json.Raw
	OriginalCode OpCode    `json:"-"`
	OriginalType EventType `json:"-"`
}

RawEvent is used if EnableRawEvents is true.

func (*RawEvent) EventType

func (e *RawEvent) EventType() EventType

EventType implements Event. It returns an emty string.

func (*RawEvent) Op

func (e *RawEvent) Op() OpCode

Op implements Event. It returns -1.

type UnknownEventError

type UnknownEventError struct {
	Op   OpCode
	Type EventType
}

UnknownEventError is required by HandleOp if an event is encountered that is not known. Internally, unknown events are logged and ignored. It is not a fatal error.

func (UnknownEventError) Error

func (err UnknownEventError) Error() string

Error formats the unknown event error to with the event name and payload

type Websocket

type Websocket struct {
	// contains filtered or unexported fields
}

Websocket is a wrapper around a websocket Conn with thread safety and rate limiting for sending and throttling.

func NewCustomWebsocket

func NewCustomWebsocket(conn Connection, addr string) *Websocket

NewCustomWebsocket creates a new undialed Websocket.

func NewWebsocket

func NewWebsocket(c Codec, addr string) *Websocket

NewWebsocket creates a default Websocket with the given address.

func (*Websocket) Close

func (ws *Websocket) Close() error

Close closes the websocket connection. It assumes that the Websocket is closed even when it returns an error. If the Websocket was already closed before, ErrWebsocketClosed will be returned.

func (*Websocket) CloseGracefully

func (ws *Websocket) CloseGracefully() error

CloseGracefully is similar to Close, but a proper close frame is sent to Discord, invalidating the internal session ID and voiding resumes.

func (*Websocket) Dial

func (ws *Websocket) Dial(ctx context.Context) (<-chan Op, error)

Dial waits until the rate limiter allows then dials the websocket.

func (*Websocket) Send

func (ws *Websocket) Send(ctx context.Context, b []byte) error

Send sends b over the Websocket with a deadline. It closes the internal Websocket if the Send method errors out.

Directories

Path Synopsis
Package ophandler provides an Op channel reader that redistributes the events into handlers.
Package ophandler provides an Op channel reader that redistributes the events into handlers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL