1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-28 09:42:58 +00:00
arikawa/internal/wsutil/ws.go

90 lines
1.7 KiB
Go
Raw Normal View History

2020-01-15 04:56:50 +00:00
// Package wsutil provides abstractions around the Websocket, including rate
// limits.
2020-01-09 05:24:45 +00:00
package wsutil
import (
"context"
"time"
2020-01-15 18:32:54 +00:00
"github.com/diamondburned/arikawa/internal/json"
2020-01-09 05:24:45 +00:00
"github.com/pkg/errors"
"golang.org/x/time/rate"
)
const DefaultTimeout = 10 * time.Second
type Event struct {
Data []byte
// Error is non-nil if Data is nil.
Error error
}
type Websocket struct {
2020-01-15 04:43:34 +00:00
Conn Connection
Addr string
2020-01-09 05:24:45 +00:00
2020-01-15 04:43:34 +00:00
SendLimiter *rate.Limiter
DialLimiter *rate.Limiter
listener <-chan Event
2020-01-16 03:28:21 +00:00
dialed bool
2020-01-09 05:24:45 +00:00
}
2020-01-15 04:43:34 +00:00
func New(ctx context.Context, addr string) (*Websocket, error) {
return NewCustom(ctx, NewConn(json.Default{}), addr)
}
2020-01-09 05:24:45 +00:00
2020-01-15 04:43:34 +00:00
// NewCustom creates a new undialed Websocket.
func NewCustom(
ctx context.Context, conn Connection, addr string) (*Websocket, error) {
2020-01-09 05:24:45 +00:00
2020-01-15 04:43:34 +00:00
ws := &Websocket{
Conn: conn,
Addr: addr,
SendLimiter: NewSendLimiter(),
DialLimiter: NewDialLimiter(),
2020-01-09 05:24:45 +00:00
}
2020-01-15 04:43:34 +00:00
return ws, nil
2020-01-09 05:24:45 +00:00
}
2020-01-15 04:43:34 +00:00
func (ws *Websocket) Redial(ctx context.Context) error {
if err := ws.DialLimiter.Wait(ctx); err != nil {
// Expired, fatal error
return errors.Wrap(err, "Failed to wait")
}
2020-01-09 05:24:45 +00:00
2020-01-16 03:28:21 +00:00
// Close the connection
if ws.dialed {
ws.Conn.Close(nil)
}
ws.dialed = true
2020-01-15 04:43:34 +00:00
if err := ws.Conn.Dial(ctx, ws.Addr); err != nil {
return errors.Wrap(err, "Failed to dial")
2020-01-09 05:24:45 +00:00
}
2020-01-15 04:43:34 +00:00
return nil
2020-01-09 05:24:45 +00:00
}
func (ws *Websocket) Listen() <-chan Event {
2020-01-15 04:43:34 +00:00
if ws.listener == nil {
ws.listener = ws.Conn.Listen()
}
return ws.listener
2020-01-09 05:24:45 +00:00
}
2020-01-15 04:43:34 +00:00
func (ws *Websocket) Send(ctx context.Context, b []byte) error {
2020-01-09 05:24:45 +00:00
if err := ws.SendLimiter.Wait(ctx); err != nil {
return errors.Wrap(err, "SendLimiter failed")
}
2020-01-15 04:43:34 +00:00
return ws.Conn.Send(ctx, b)
}
func (ws *Websocket) Close(err error) error {
return ws.Conn.Close(err)
2020-01-09 05:24:45 +00:00
}