Compare commits

...

2 Commits

Author SHA1 Message Date
Cléo Rebert 8f548d2607 go fmt + gci
Signed-off-by: Cléo Rebert <cleo.rebert@gmail.com>
2023-09-19 11:37:24 -07:00
Cléo Rebert d36955acea Move away from github.com/pkg/errors
Signed-off-by: Cléo Rebert <cleo.rebert@gmail.com>
2023-09-19 11:37:24 -07:00
48 changed files with 357 additions and 388 deletions

View File

@ -2,6 +2,7 @@ package main
import (
"context"
"errors"
"flag"
"log"
"os"
@ -16,7 +17,6 @@ import (
"github.com/diamondburned/arikawa/v3/voice"
"github.com/diamondburned/arikawa/v3/voice/udp"
"github.com/diamondburned/oggreader"
"github.com/pkg/errors"
)
func main() {

View File

@ -1,9 +1,10 @@
package cmdroute
import (
"fmt"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/pkg/errors"
)
// BulkCommandsOverwriter is an interface that allows to overwrite all commands
@ -20,9 +21,9 @@ var _ BulkCommandsOverwriter = (*api.Client)(nil)
func OverwriteCommands(client BulkCommandsOverwriter, cmds []api.CreateCommandData) error {
app, err := client.CurrentApplication()
if err != nil {
return errors.Wrap(err, "cannot get current app ID")
return fmt.Errorf("cannot get current app ID: %w", err)
}
_, err = client.BulkOverwriteCommands(app.ID, cmds)
return errors.Wrap(err, "cannot overwrite commands")
return fmt.Errorf("cannot overwrite commands: %w", err)
}

View File

@ -3,11 +3,11 @@ package api
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"net/http"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
var ErrInvalidImageCT = errors.New("unknown image content-type")
@ -43,11 +43,11 @@ func DecodeImage(data []byte) (*Image, error) {
}
if !bytes.HasPrefix(parts[0], []byte("data:")) {
return nil, errors.Wrap(ErrInvalidImageData, "invalid header")
return nil, fmt.Errorf("invalid header: %w", ErrInvalidImageData)
}
if !bytes.HasPrefix(parts[1], []byte("base64,")) {
return nil, errors.Wrap(ErrInvalidImageData, "invalid base64")
return nil, fmt.Errorf("invalid base64: %w", ErrInvalidImageData)
}
var b64 = parts[1][len("base64,"):]

View File

@ -1,10 +1,8 @@
package api
import (
"fmt"
"mime/multipart"
"strconv"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json/option"
@ -105,10 +103,9 @@ func (d InteractionResponseData) WriteMultipart(body *multipart.Writer) error {
//
// The following types implement this interface:
//
// - AutocompleteStringChoices
// - AutocompleteIntegerChoices
// - AutocompleteNumberChoices
//
// - AutocompleteStringChoices
// - AutocompleteIntegerChoices
// - AutocompleteNumberChoices
type AutocompleteChoices interface {
choices()
}
@ -158,7 +155,7 @@ func (c *Client) RespondInteraction(
if resp.Data.AllowedMentions != nil {
if err := resp.Data.AllowedMentions.Verify(); err != nil {
return errors.Wrap(err, "allowedMentions error")
return fmt.Errorf("allowedMentions error: %w", err)
}
}
@ -166,7 +163,7 @@ func (c *Client) RespondInteraction(
sum := 0
for i, embed := range *resp.Data.Embeds {
if err := embed.Validate(); err != nil {
return errors.Wrap(err, "embed error at "+strconv.Itoa(i))
return fmt.Errorf("embed error at %d: %w", i, err)
}
sum += embed.Length()
if sum > 6000 {
@ -225,7 +222,7 @@ func (c *Client) EditInteractionResponse(
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
@ -233,7 +230,7 @@ func (c *Client) EditInteractionResponse(
sum := 0
for i, e := range *data.Embeds {
if err := e.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error")
return nil, fmt.Errorf("embed error: %w", err)
}
sum += e.Length()
if sum > 6000 {
@ -275,7 +272,7 @@ func (c *Client) FollowUpInteraction(
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
@ -283,7 +280,7 @@ func (c *Client) FollowUpInteraction(
sum := 0
for i, embed := range *data.Embeds {
if err := embed.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
return nil, fmt.Errorf("embed error at %d: %w", i, err)
}
sum += embed.Length()
if sum > 6000 {
@ -305,7 +302,7 @@ func (c *Client) EditInteractionFollowup(
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
@ -313,7 +310,7 @@ func (c *Client) EditInteractionFollowup(
sum := 0
for i, e := range *data.Embeds {
if err := e.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error")
return nil, fmt.Errorf("embed error: %w", err)
}
sum += e.Length()
if sum > 6000 {

View File

@ -1,10 +1,8 @@
package api
import (
"fmt"
"mime/multipart"
"strconv"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/internal/intmath"
@ -370,7 +368,7 @@ func (c *Client) EditMessageComplex(
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
@ -378,7 +376,7 @@ func (c *Client) EditMessageComplex(
sum := 0
for i, embed := range *data.Embeds {
if err := embed.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
return nil, fmt.Errorf("embed error at %d: %w", i, err)
}
sum += embed.Length()
if sum > 6000 {

View File

@ -2,6 +2,8 @@ package rate
import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
@ -10,7 +12,6 @@ import (
"time"
"github.com/diamondburned/arikawa/v3/internal/moreatomic"
"github.com/pkg/errors"
)
// ExtraDelay because Discord is trash. I've seen this in both litcord and
@ -209,7 +210,7 @@ func (l *Limiter) Release(path string, headers http.Header) error {
case retryAfter != "":
i, err := strconv.Atoi(retryAfter)
if err != nil {
return errors.Wrapf(err, "invalid retryAfter %q", retryAfter)
return fmt.Errorf("invalid retryAfter %q: %w", retryAfter, err)
}
at := time.Now().Add(time.Duration(i) * time.Second)
@ -223,7 +224,7 @@ func (l *Limiter) Release(path string, headers http.Header) error {
case reset != "":
unix, err := strconv.ParseFloat(reset, 64)
if err != nil {
return errors.Wrap(err, "invalid reset "+reset)
return fmt.Errorf("invalid reset %q: %w", reset, err)
}
sec := int64(unix)
@ -235,7 +236,7 @@ func (l *Limiter) Release(path string, headers http.Header) error {
if remaining != "" {
u, err := strconv.ParseUint(remaining, 10, 64)
if err != nil {
return errors.Wrap(err, "invalid remaining "+remaining)
return fmt.Errorf("invalid remaining %q: %w", remaining, err)
}
b.remaining = u

View File

@ -1,10 +1,9 @@
package api
import (
"errors"
"fmt"
"mime/multipart"
"strconv"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json/option"
@ -15,7 +14,7 @@ const AttachmentSpoilerPrefix = "SPOILER_"
// AllowedMentions is a allowlist of mentions for a message.
//
// Allowlists
// # Allowlists
//
// Roles and Users are slices that act as allowlists for IDs that are allowed
// to be mentioned. For example, if only 1 ID is provided in Users, then only
@ -25,7 +24,7 @@ const AttachmentSpoilerPrefix = "SPOILER_"
// If Parse is an empty slice and both Users and Roles are empty slices, then no
// mentions will be parsed.
//
// Constraints
// # Constraints
//
// If the Users slice is not empty, then Parse must not have AllowUserMention.
// Likewise, if the Roles slice is not empty, then Parse must not have
@ -65,10 +64,10 @@ const (
// AllowedMentions' documentation. This will be called on SendMessageComplex.
func (am AllowedMentions) Verify() error {
if len(am.Roles) > 100 {
return errors.Errorf("roles slice length %d is over 100", len(am.Roles))
return fmt.Errorf("roles slice length %d is over 100", len(am.Roles))
}
if len(am.Users) > 100 {
return errors.Errorf("users slice length %d is over 100", len(am.Users))
return fmt.Errorf("users slice length %d is over 100", len(am.Users))
}
for _, allowed := range am.Parse {
@ -160,14 +159,14 @@ func (c *Client) SendMessageComplex(
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
sum := 0
for i, embed := range data.Embeds {
if err := embed.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
return nil, fmt.Errorf("embed error at %d: %w", i, err)
}
sum += embed.Length()
if sum > 6000 {

View File

@ -5,6 +5,8 @@ import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"mime/multipart"
@ -12,7 +14,6 @@ import (
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/pkg/errors"
)
func writeError(w http.ResponseWriter, code int, err error) {
@ -94,7 +95,7 @@ type InteractionServer struct {
func NewInteractionServer(pubkey string, handler InteractionHandler) (*InteractionServer, error) {
pubkeyB, err := hex.DecodeString(pubkey)
if err != nil {
return nil, errors.Wrap(err, "cannot decode hex pubkey")
return nil, fmt.Errorf("cannot decode hex pubkey: %w", err)
}
s := InteractionServer{
@ -125,7 +126,7 @@ func (s *InteractionServer) handle(w http.ResponseWriter, r *http.Request) {
var ev discord.InteractionEvent
if err := json.NewDecoder(r.Body).Decode(&ev); err != nil {
s.ErrorFunc(w, r, 400, errors.Wrap(err, "cannot decode interaction body"))
s.ErrorFunc(w, r, 400, fmt.Errorf("cannot decode interaction : %w", err))
return
}
@ -165,7 +166,7 @@ func (s *InteractionServer) withVerification(next http.Handler) http.Handler {
sig, err := hex.DecodeString(signature)
if err != nil {
s.ErrorFunc(w, r, 400, errors.Wrap(err, "X-Signature-Ed25519 is not valid hex-encoded"))
s.ErrorFunc(w, r, 400, fmt.Errorf("X-Signature-Ed25519 is not valid hex-encoded: %w", err))
return
}
@ -185,7 +186,7 @@ func (s *InteractionServer) withVerification(next http.Handler) http.Handler {
msg.WriteString(timestamp)
if _, err := io.Copy(&msg, r.Body); err != nil {
s.ErrorFunc(w, r, 500, errors.Wrap(err, "cannot read body"))
s.ErrorFunc(w, r, 500, fmt.Errorf("cannot read body: %w", err))
return
}

View File

@ -4,13 +4,13 @@ package webhook
import (
"context"
"errors"
"fmt"
"mime/multipart"
"net/url"
"regexp"
"strconv"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/api/rate"
"github.com/diamondburned/arikawa/v3/discord"
@ -34,7 +34,7 @@ func ParseURL(webhookURL string) (id discord.WebhookID, token string, err error)
idInt, err := strconv.ParseUint(matches[1], 10, 64)
if err != nil {
return 0, "", errors.Wrap(err, "failed to parse webhook ID")
return 0, "", fmt.Errorf("failed to parse webhook ID: %w", err)
}
return discord.WebhookID(idInt), matches[2], nil
@ -222,14 +222,14 @@ func (c *Client) execute(data ExecuteData, wait bool) (*discord.Message, error)
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
sum := 0
for i, embed := range data.Embeds {
if err := embed.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
return nil, fmt.Errorf("embed error at %d: %w", i, err)
}
sum += embed.Length()
if sum > 6000 {
@ -284,14 +284,14 @@ type EditMessageData struct {
func (c *Client) EditMessage(messageID discord.MessageID, data EditMessageData) (*discord.Message, error) {
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
return nil, fmt.Errorf("allowedMentions error: %w", err)
}
}
if data.Embeds != nil {
sum := 0
for _, e := range *data.Embeds {
if err := e.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error")
return nil, fmt.Errorf("embed error: %w", err)
}
sum += e.Length()
if sum > 6000 {

View File

@ -1,26 +1,26 @@
// Package arikawa contains a set of modular packages that allows you to make a
// Discord bot or any type of session (OAuth unsupported).
//
// Session
// # Session
//
// Package session is the most simple abstraction, which combines the API
// package and the Gateway websocket package together into one. This could be
// used for minimal bots that only use gateway events and such.
//
// State
// # State
//
// Package state abstracts on top of session and provides a local cache of API
// calls and events. Bots that either don't need a command router or already has
// its own should use this package.
//
// Bot
// # Bot
//
// Package bot abstracts on top of state and provides a command router based on
// Go code. This is similar to discord.py's API, only it's Go and there's no
// optional arguments (yet, although it could be worked around). Most bots are
// recommended to use this package, as it's the easiest way to make a bot.
//
// Voice
// # Voice
//
// Package voice provides an abstraction on top of State and adds voice support.
// This allows bots to join voice channels and talk. The package uses an
@ -29,12 +29,11 @@
package arikawa
import (
// Low level packages.
_ "github.com/diamondburned/arikawa/v3/api"
_ "github.com/diamondburned/arikawa/v3/gateway"
// Packages that most should use.
_ "github.com/diamondburned/arikawa/v3/session"
_ "github.com/diamondburned/arikawa/v3/state"
_ "github.com/diamondburned/arikawa/v3/voice"
// Low level packages.
_ "github.com/diamondburned/arikawa/v3/api"
_ "github.com/diamondburned/arikawa/v3/gateway"
)

View File

@ -1,10 +1,9 @@
package discord
import (
"fmt"
"time"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/utils/json"
)
@ -150,29 +149,28 @@ type AuditEntryInfo struct {
// AuditLogChange is a single key type to changed value audit log entry. The
// type can be found in the key's comment. Values can be nil.
//
// What
// # What
//
// I'm glad to see the same reaction that I had on you. In short, in this
// struct, the Key dictates what type NewValue and OldValue will have. They will
// always be the same type, but I will leave that as JSON for the user.
//
// Usage
// # Usage
//
// The usage of this is pretty simple, as AuditLogChange already has a
// convenient method to use. Here's an example on how to do "owner_id":
//
// if change.Key != discord.AuditGuildOwnerID {
// return errors.New("not owner ID")
// }
// if change.Key != discord.AuditGuildOwnerID {
// return errors.New("not owner ID")
// }
//
// // We know these are UserIDs because the comment said so for AuditGuildOwnerID.
// var oldOwnerID, newOwnerID discord.UserID
// if err := change.UnmarshalValues(&oldOwnerID, &newOwnerID); err != nil {
// return err
// }
//
// log.Println("Transferred ownership from user", oldOwnerID, "to", newOwnerID)
// // We know these are UserIDs because the comment said so for AuditGuildOwnerID.
// var oldOwnerID, newOwnerID discord.UserID
// if err := change.UnmarshalValues(&oldOwnerID, &newOwnerID); err != nil {
// return err
// }
//
// log.Println("Transferred ownership from user", oldOwnerID, "to", newOwnerID)
type AuditLogChange struct {
// Key is the name of audit log change key.
Key AuditLogChangeKey `json:"key"`
@ -186,10 +184,10 @@ type AuditLogChange struct {
// interfaces.
func (a AuditLogChange) UnmarshalValues(old, new interface{}) error {
if err := a.NewValue.UnmarshalTo(new); err != nil {
return errors.Wrap(err, "failed to unmarshal old value")
return fmt.Errorf("failed to unmarshal old value: %w", err)
}
if err := a.OldValue.UnmarshalTo(old); err != nil {
return errors.Wrap(err, "failed to unmarshal new value")
return fmt.Errorf("failed to unmarshal new value: %w", err)
}
return nil
}

View File

@ -6,7 +6,6 @@ import (
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/pkg/errors"
)
// CommandType is the type of the command, which describes the intended
@ -257,7 +256,7 @@ func (u *UnknownCommandOption) UnmarshalJSON(b []byte) error {
type unknown UnknownCommandOption
if err := json.Unmarshal(b, (*unknown)(u)); err != nil {
return errors.Wrap(err, "failed to unmarshal unknown")
return fmt.Errorf("failed to unmarshal unknown: %w", err)
}
switch u.Type() {
@ -289,7 +288,7 @@ func (u *UnknownCommandOption) UnmarshalJSON(b []byte) error {
}
if err := json.Unmarshal(b, u.data); err != nil {
return errors.Wrapf(err, "failed to unmarshal type %d", u.Type())
return fmt.Errorf("failed to unmarshal type %d: %w", u.Type(), err)
}
return nil
@ -319,18 +318,17 @@ const (
//
// The following types implement this interface:
//
// - *SubcommandGroupOption
// - *SubcommandOption
// - *StringOption
// - *IntegerOption
// - *BooleanOption
// - *UserOption
// - *ChannelOption
// - *RoleOption
// - *MentionableOption
// - *NumberOption
// - *AttachmentOption
//
// - *SubcommandGroupOption
// - *SubcommandOption
// - *StringOption
// - *IntegerOption
// - *BooleanOption
// - *UserOption
// - *ChannelOption
// - *RoleOption
// - *MentionableOption
// - *NumberOption
// - *AttachmentOption
type CommandOption interface {
Name() string
Type() CommandOptionType
@ -424,16 +422,15 @@ func (s *SubcommandOption) UnmarshalJSON(b []byte) error {
//
// The following types implement this interface:
//
// - *StringOption
// - *IntegerOption
// - *BooleanOption
// - *UserOption
// - *ChannelOption
// - *RoleOption
// - *MentionableOption
// - *NumberOption
// - *AttachmentOption
//
// - *StringOption
// - *IntegerOption
// - *BooleanOption
// - *UserOption
// - *ChannelOption
// - *RoleOption
// - *MentionableOption
// - *NumberOption
// - *AttachmentOption
type CommandOptionValue interface {
CommandOption
_val()

View File

@ -8,7 +8,6 @@ import (
"github.com/diamondburned/arikawa/v3/internal/rfutil"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// ComponentType is the type of a component.
@ -78,14 +77,14 @@ func (c *ContainerComponents) Find(customID ComponentID) Component {
// matching custom ID. The struct must be a flat struct that lists all the
// components it needs using the custom ID.
//
// Supported Types
// # Supported Types
//
// The following types are supported:
//
// - string (SelectComponent if range = [n, 1], TextInputComponent)
// - int*, uint*, float* (uses Parse{Int,Uint,Float}, SelectComponent if range = [n, 1], TextInputComponent)
// - bool (ButtonComponent or any component, true if present)
// - []string (SelectComponent)
// - string (SelectComponent if range = [n, 1], TextInputComponent)
// - int*, uint*, float* (uses Parse{Int,Uint,Float}, SelectComponent if range = [n, 1], TextInputComponent)
// - bool (ButtonComponent or any component, true if present)
// - []string (SelectComponent)
//
// Any types that are derived from any of the above built-in types are also
// supported.
@ -248,15 +247,14 @@ func (c *ContainerComponents) UnmarshalJSON(b []byte) error {
//
// The following types satisfy this interface:
//
// - *ActionRowComponent
// - *ButtonComponent
// - *StringSelectComponent
// - *TextInputComponent
// - *UserSelectComponent
// - *RoleSelectComponent
// - *MentionableSelectComponent
// - *ChannelSelectComponent
//
// - *ActionRowComponent
// - *ButtonComponent
// - *StringSelectComponent
// - *TextInputComponent
// - *UserSelectComponent
// - *RoleSelectComponent
// - *MentionableSelectComponent
// - *ChannelSelectComponent
type Component interface {
// Type returns the type of the underlying component.
Type() ComponentType
@ -269,14 +267,13 @@ type Component interface {
//
// The following types satisfy this interface:
//
// - *ButtonComponent
// - *SelectComponent
// - *TextInputComponent
// - *UserSelectComponent
// - *RoleSelectComponent
// - *MentionableSelectComponent
// - *ChannelSelectComponent
//
// - *ButtonComponent
// - *SelectComponent
// - *TextInputComponent
// - *UserSelectComponent
// - *RoleSelectComponent
// - *MentionableSelectComponent
// - *ChannelSelectComponent
type InteractiveComponent interface {
Component
// ID returns the ID of the underlying component.
@ -290,8 +287,7 @@ type InteractiveComponent interface {
//
// The following types satisfy this interface:
//
// - *ActionRowComponent
//
// - *ActionRowComponent
type ContainerComponent interface {
Component
_ctn()
@ -305,7 +301,7 @@ func ParseComponent(b []byte) (Component, error) {
}
if err := json.Unmarshal(b, &t); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal component type")
return nil, fmt.Errorf("failed to unmarshal component type: %w", err)
}
var c Component
@ -324,7 +320,7 @@ func ParseComponent(b []byte) (Component, error) {
}
if err := json.Unmarshal(b, c); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal component body")
return nil, fmt.Errorf("failed to unmarshal component body: %w", err)
}
return c, nil
@ -342,14 +338,13 @@ type ActionRowComponent []InteractiveComponent
//
// Here's an example of how to use it:
//
// discord.Components(
// discord.TextButtonComponent("Hello, world!"),
// discord.Components(
// discord.TextButtonComponent("Hello!"),
// discord.TextButtonComponent("Delete."),
// ),
// )
//
// discord.Components(
// discord.TextButtonComponent("Hello, world!"),
// discord.Components(
// discord.TextButtonComponent("Hello!"),
// discord.TextButtonComponent("Delete."),
// ),
// )
func Components(components ...Component) ContainerComponents {
new := make([]ContainerComponent, len(components))
@ -421,7 +416,7 @@ func (a *ActionRowComponent) UnmarshalJSON(b []byte) error {
for i, b := range row.Components {
p, err := ParseComponent(b)
if err != nil {
return errors.Wrapf(err, "failed to parse component %d", i)
return fmt.Errorf("failed to parse component %d: %w", i, err)
}
ic, ok := p.(InteractiveComponent)

View File

@ -1,13 +1,13 @@
package discord
import (
"errors"
"fmt"
"reflect"
"strings"
"github.com/diamondburned/arikawa/v3/internal/rfutil"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// InteractionEvent describes the full incoming interaction event. It may be a
@ -93,7 +93,7 @@ func (e *InteractionEvent) UnmarshalJSON(b []byte) error {
case ComponentInteractionType:
d, err := ParseComponentInteraction(target.Data)
if err != nil {
return errors.Wrap(err, "failed to unmarshal component interaction event data")
return fmt.Errorf("failed to unmarshal component interaction event data: %w", err)
}
e.Data = d
return nil
@ -110,7 +110,7 @@ func (e *InteractionEvent) UnmarshalJSON(b []byte) error {
}
if err := json.Unmarshal(target.Data, e.Data); err != nil {
return errors.Wrap(err, "failed to unmarshal interaction event data")
return fmt.Errorf("failed to unmarshal interaction event data: %w", err)
}
return err
@ -155,17 +155,16 @@ const (
//
// The following types implement this interface:
//
// - *PingInteraction
// - *AutocompleteInteraction
// - *CommandInteraction
// - *ModalInteraction
// - *StringSelectInteraction (also ComponentInteraction)
// - *RoleSelectInteraction (also ComponentInteraction)
// - *UserSelectInteraction (also ComponentInteraction)
// - *ChannelSelectInteraction (also ComponentInteraction)
// - *MentionableSelectInteraction (also ComponentInteraction)
// - *ButtonInteraction (also ComponentInteraction)
//
// - *PingInteraction
// - *AutocompleteInteraction
// - *CommandInteraction
// - *ModalInteraction
// - *StringSelectInteraction (also ComponentInteraction)
// - *RoleSelectInteraction (also ComponentInteraction)
// - *UserSelectInteraction (also ComponentInteraction)
// - *ChannelSelectInteraction (also ComponentInteraction)
// - *MentionableSelectInteraction (also ComponentInteraction)
// - *ButtonInteraction (also ComponentInteraction)
type InteractionData interface {
InteractionType() InteractionDataType
data()
@ -289,13 +288,12 @@ func (o AutocompleteOption) FloatValue() (float64, error) {
//
// The following types implement this interface:
//
// - *StringSelectInteraction
// - *ChannelSelectInteraction
// - *RoleSelectInteraction
// - *UserSelectInteraction
// - *MentionableSelectInteraction
// - *ButtonInteraction
//
// - *StringSelectInteraction
// - *ChannelSelectInteraction
// - *RoleSelectInteraction
// - *UserSelectInteraction
// - *MentionableSelectInteraction
// - *ButtonInteraction
type ComponentInteraction interface {
InteractionData
// ID returns the ID of the component in response. Not all component
@ -439,7 +437,7 @@ func ParseComponentInteraction(b []byte) (ComponentInteraction, error) {
}
if err := json.Unmarshal(b, &t); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal component interaction header")
return nil, fmt.Errorf("failed to unmarshal component interaction header: %w", err)
}
var d ComponentInteraction
@ -467,7 +465,7 @@ func ParseComponentInteraction(b []byte) (ComponentInteraction, error) {
}
if err := json.Unmarshal(b, d); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal component interaction data")
return nil, fmt.Errorf("failed to unmarshal component interaction data: %w", err)
}
return d, nil
@ -565,20 +563,20 @@ var optionKindMap = map[reflect.Kind]CommandOptionType{
// tag with a value "-" is ignored. Fields that aren't found in the list of
// options and have a "?" at the end of the "discord" struct tag are ignored.
//
// Supported Types
// # Supported Types
//
// The following types are supported:
//
// - ChannelID (ChannelOptionType)
// - UserID (UserOptionType)
// - RoleID (RoleOptionType)
// - Snowflake (MentionableOptionType)
// - string (StringOptionType)
// - bool (BooleanOptionType)
// - int* (int, int8, int16, int32, int64) (NumberOptionType)
// - uint* (uint, uint8, uint16, uint32, uint64) (NumberOptionType)
// - float* (float32, float64) (NumberOptionType)
// - (any struct and struct pointer) (not Discord-type-checked)
// - ChannelID (ChannelOptionType)
// - UserID (UserOptionType)
// - RoleID (RoleOptionType)
// - Snowflake (MentionableOptionType)
// - string (StringOptionType)
// - bool (BooleanOptionType)
// - int* (int, int8, int16, int32, int64) (NumberOptionType)
// - uint* (uint, uint8, uint16, uint32, uint64) (NumberOptionType)
// - float* (float32, float64) (NumberOptionType)
// - (any struct and struct pointer) (not Discord-type-checked)
//
// Any types that are derived from any of the above built-in types are also
// supported.
@ -664,7 +662,7 @@ func unmarshalOptions(find func(string) unmarshalingOption, rv reflect.Value) er
var snowflake Snowflake
if err := option.Value.UnmarshalTo(&snowflake); err != nil {
return errors.Wrapf(err, "option %q is not a valid snowflake", name)
return fmt.Errorf("option %q is not a valid snowflake: %w", name, err)
}
fieldv.Set(reflect.ValueOf(snowflake).Convert(fieldt))
@ -681,7 +679,7 @@ func unmarshalOptions(find func(string) unmarshalingOption, rv reflect.Value) er
switch fieldk {
case reflect.Struct:
if err := unmarshalOptions(option.Find, fieldv.Addr()); err != nil {
return errors.Wrapf(err, "option %q has invalid suboptions", name)
return fmt.Errorf("option %q has invalid suboptions: %w", name, err)
}
case reflect.Bool, reflect.String, reflect.Float32, reflect.Float64,
@ -690,7 +688,7 @@ func unmarshalOptions(find func(string) unmarshalingOption, rv reflect.Value) er
v := reflect.New(fieldt)
if err := option.Value.UnmarshalTo(v.Interface()); err != nil {
return errors.Wrapf(err, "option %q is not a valid %s", name, fieldt)
return fmt.Errorf("option %q is not a valid %s: %w", name, fieldt, err)
}
fieldv.Set(v.Elem())

View File

@ -18,7 +18,6 @@ import (
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/internal/lazytime"
"github.com/diamondburned/arikawa/v3/utils/ws"
"github.com/pkg/errors"
)
var (
@ -246,7 +245,7 @@ func (g *Gateway) Send(ctx context.Context, data ws.Event) error {
// stable connection to the Discord gateway. To the user, the gateway should
// appear to be working seamlessly.
//
// Behaviors
// # Behaviors
//
// There are several behaviors that the gateway will overload onto the channel.
//
@ -264,12 +263,12 @@ func (g *Gateway) Send(ctx context.Context, data ws.Event) error {
// BackgroundErrorEvent event. The user can type-assert the Op's data field,
// like so:
//
// switch data := ev.Data.(type) {
// case *gateway.BackgroundErrorEvent:
// log.Println("gateway error:", data.Error)
// }
// switch data := ev.Data.(type) {
// case *gateway.BackgroundErrorEvent:
// log.Println("gateway error:", data.Error)
// }
//
// Closing
// # Closing
//
// As outlined in the first paragraph, closing the gateway would involve
// cancelling the context that's given to gateway. If AlwaysCloseGracefully is
@ -279,33 +278,32 @@ func (g *Gateway) Send(ctx context.Context, data ws.Event) error {
// To wait until the gateway has completely successfully exited, the user can
// keep spinning on the event loop:
//
// for op := range ch {
// select op.Data.(type) {
// case *gateway.ReadyEvent:
// // Close the gateway on READY.
// cancel()
// }
// }
// for op := range ch {
// select op.Data.(type) {
// case *gateway.ReadyEvent:
// // Close the gateway on READY.
// cancel()
// }
// }
//
// // Gateway is now completely closed.
// // Gateway is now completely closed.
//
// To capture the final close errors, the user can use the Error method once the
// event channel is closed, like so:
//
// var err error
// var err error
//
// for op := range ch {
// switch data := op.Data.(type) {
// case *gateway.ReadyEvent:
// cancel()
// }
// }
//
// // Gateway is now completely closed.
// if gateway.LastError() != nil {
// return gateway.LastError()
// }
// for op := range ch {
// switch data := op.Data.(type) {
// case *gateway.ReadyEvent:
// cancel()
// }
// }
//
// // Gateway is now completely closed.
// if gateway.LastError() != nil {
// return gateway.LastError()
// }
func (g *Gateway) Connect(ctx context.Context) <-chan ws.Op {
return g.gateway.Connect(ctx, &gatewayImpl{Gateway: g})
}
@ -325,7 +323,7 @@ func (g *gatewayImpl) invalidate() {
// with the given context for timeout.
func (g *gatewayImpl) sendIdentify(ctx context.Context) error {
if err := g.state.Identifier.Wait(ctx); err != nil {
return errors.Wrap(err, "can't wait for identify()")
return fmt.Errorf("can't wait for identify(): %w", err)
}
return g.gateway.Send(ctx, &g.state.Identifier.IdentifyCommand)

View File

@ -2,6 +2,7 @@ package gateway
import (
"context"
"fmt"
"runtime"
"strings"
"time"
@ -9,7 +10,6 @@ import (
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/pkg/errors"
"golang.org/x/time/rate"
)
@ -46,13 +46,13 @@ func NewIdentifier(data IdentifyCommand) Identifier {
func (id *Identifier) Wait(ctx context.Context) error {
if id.IdentifyShortLimit != nil {
if err := id.IdentifyShortLimit.Wait(ctx); err != nil {
return errors.Wrap(err, "can't wait for short limit")
return fmt.Errorf("can't wait for short limit: %w", err)
}
}
if id.IdentifyGlobalLimit != nil {
if err := id.IdentifyGlobalLimit.Wait(ctx); err != nil {
return errors.Wrap(err, "can't wait for global limit")
return fmt.Errorf("can't wait for global limit: %w", err)
}
}
@ -67,13 +67,13 @@ func (id *Identifier) QueryGateway(ctx context.Context) (gatewayURL string, err
if strings.HasPrefix(id.Token, "Bot ") {
botData, err = BotURL(ctx, id.Token)
if err != nil {
return "", errors.Wrap(err, "failed to get bot data")
return "", fmt.Errorf("failed to get bot data: %w", err)
}
gatewayURL = botData.URL
} else {
gatewayURL, err = URL(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to get gateway endpoint")
return "", fmt.Errorf("failed to get gateway endpoint: %w", err)
}
}

1
go.mod
View File

@ -5,7 +5,6 @@ go 1.16
require (
github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.4.2
github.com/pkg/errors v0.9.1
golang.org/x/crypto v0.1.0
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
)

2
go.sum
View File

@ -2,8 +2,6 @@ github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=

View File

@ -4,6 +4,8 @@
package testenv
import (
"errors"
"fmt"
"os"
"strconv"
"sync"
@ -11,7 +13,6 @@ import (
"time"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/pkg/errors"
)
const PerseveranceTime = 50 * time.Minute
@ -56,13 +57,13 @@ func getEnv() {
id, err := discord.ParseSnowflake(os.Getenv("CHANNEL_ID"))
if err != nil {
globalErr = errors.Wrap(err, "invalid $CHANNEL_ID")
globalErr = fmt.Errorf("invalid $CHANNEL_ID: %w", err)
return
}
vid, err := discord.ParseSnowflake(os.Getenv("VOICE_ID"))
if err != nil {
globalErr = errors.Wrap(err, "invalid $VOICE_ID")
globalErr = fmt.Errorf("invalid $VOICE_ID: %w", err)
return
}

View File

@ -4,9 +4,9 @@ package zlib
import (
"bytes"
"errors"
"fmt"
"log"
"github.com/pkg/errors"
)
var Suffix = [4]byte{'\x00', '\x00', '\xff', '\xff'}
@ -61,7 +61,7 @@ func (i *Inflator) Flush() ([]byte, error) {
if i.zlib == nil {
r, err := zlibStreamer(&i.wbuf)
if err != nil {
return nil, errors.Wrap(err, "failed to make a FLATE reader")
return nil, fmt.Errorf("failed to make a FLATE reader: %w", err)
}
// safe assertion
i.zlib = r
@ -79,7 +79,7 @@ func (i *Inflator) Flush() ([]byte, error) {
// to verify checksum. Discord doesn't send this.
if err != nil {
// Unexpected error, try and close.
return nil, errors.Wrap(err, "failed to read from FLATE reader")
return nil, fmt.Errorf("failed to read from FLATE reader: %w", err)
}
// if err := i.zlib.Close(); err != nil && err != io.ErrUnexpectedEOF {

View File

@ -5,11 +5,11 @@ package session
import (
"context"
"errors"
"fmt"
"log"
"sync"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/api/webhook"
"github.com/diamondburned/arikawa/v3/gateway"
@ -85,7 +85,7 @@ func Login(ctx context.Context, email, password, mfa string) (*Session, error) {
// Try to login without TOTP
l, err := client.Login(email, password)
if err != nil {
return nil, errors.Wrap(err, "failed to login")
return nil, fmt.Errorf("failed to login: %w", err)
}
if l.Token != "" && !l.MFA {
@ -101,7 +101,7 @@ func Login(ctx context.Context, email, password, mfa string) (*Session, error) {
// Retry logging in with a 2FA token
l, err = client.TOTP(mfa, l.Ticket)
if err != nil {
return nil, errors.Wrap(err, "failed to login with 2FA")
return nil, fmt.Errorf("failed to login with 2FA: %w", err)
}
return New(l.Token), nil

View File

@ -2,6 +2,7 @@ package shard
import (
"context"
"fmt"
"sync"
"time"
@ -9,7 +10,6 @@ import (
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/internal/backoff"
"github.com/pkg/errors"
)
func updateIdentifier(ctx context.Context, id *gateway.Identifier) (url string, err error) {
@ -63,7 +63,7 @@ func NewManager(token string, fn NewShardFunc) (*Manager, error) {
url, err := updateIdentifier(context.Background(), &id)
if err != nil {
return nil, errors.Wrap(err, "failed to get gateway info")
return nil, fmt.Errorf("failed to get gateway info: %w", err)
}
return NewIdentifiedManagerWithURL(url, id, fn)
@ -86,7 +86,7 @@ func NewIdentifiedManager(idData gateway.IdentifyCommand, fn NewShardFunc) (*Man
url, err := updateIdentifier(context.Background(), &id)
if err != nil {
return nil, errors.Wrap(err, "failed to get gateway info")
return nil, fmt.Errorf("failed to get gateway info: %w", err)
}
id.Shard = idData.Shard
@ -121,7 +121,7 @@ func NewIdentifiedManagerWithURL(
m.shards[i].Shard, err = fn(&m, &m.shards[i].ID)
if err != nil {
return nil, errors.Wrapf(err, "failed to create shard %d/%d", i, len(m.shards)-1)
return nil, fmt.Errorf("failed to create shard %d/%d: %w", i, len(m.shards)-1, err)
}
}

View File

@ -2,12 +2,12 @@ package shard
import (
"context"
"fmt"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/session"
"github.com/diamondburned/arikawa/v3/utils/handler"
"github.com/pkg/errors"
)
// Shard defines a shard gateway interface that the shard manager can use.
@ -57,7 +57,7 @@ func OpenShards(ctx context.Context, shards []ShardState) error {
for i, shard := range shards {
if err := shard.Shard.Open(ctx); err != nil {
CloseShards(shards)
return errors.Wrapf(err, "failed to open shard %d/%d", i, len(shards)-1)
return fmt.Errorf("failed to open shard %d/%d: %w", i, len(shards)-1, err)
}
// Mark as opened so we can close them.

View File

@ -4,6 +4,8 @@ package state
import (
"context"
"errors"
"fmt"
"sync"
"github.com/diamondburned/arikawa/v3/api"
@ -14,8 +16,6 @@ import (
"github.com/diamondburned/arikawa/v3/state/store"
"github.com/diamondburned/arikawa/v3/state/store/defaultstore"
"github.com/diamondburned/arikawa/v3/utils/handler"
"github.com/pkg/errors"
)
var (
@ -38,7 +38,7 @@ func NewShardFunc(opts func(*shard.Manager, *State)) shard.NewShardFunc {
// State is the cache to store events coming from Discord as well as data from
// API calls.
//
// Store
// # Store
//
// The state basically provides abstractions on top of the API and the state
// storage (Store). The state storage is effectively a set of interfaces which
@ -54,7 +54,7 @@ func NewShardFunc(opts func(*shard.Manager, *State)) shard.NewShardFunc {
// state fetch information from the API. The setters are all no-ops, so the
// fetched data won't be updated.
//
// Handler
// # Handler
//
// The state uses its own handler over session's to make all handlers run after
// the state updates itself. A PreHandler is exposed in any case the user needs
@ -289,7 +289,7 @@ func (s *State) Permissions(
ch, err := s.Channel(channelID)
if err != nil {
return 0, errors.Wrap(err, "failed to get channel")
return 0, fmt.Errorf("failed to get channel: %w", err)
}
if !ch.GuildID.IsValid() {
@ -332,10 +332,10 @@ func (s *State) Permissions(
wg.Wait()
if gerr != nil {
return 0, errors.Wrap(merr, "failed to get guild")
return 0, fmt.Errorf("failed to get guild: %w", gerr)
}
if merr != nil {
return 0, errors.Wrap(merr, "failed to get member")
return 0, fmt.Errorf("failed to get member: %w", merr)
}
return discord.CalcOverwrites(*g, *ch, *m), nil
@ -590,13 +590,13 @@ func (s *State) Message(
m, err = s.Session.Message(channelID, messageID)
if err != nil {
return nil, errors.Wrap(err, "unable to fetch message")
return nil, fmt.Errorf("unable to fetch message: %w", err)
}
wg.Wait()
if cerr != nil {
return nil, errors.Wrap(cerr, "unable to fetch channel")
return nil, fmt.Errorf("unable to fetch channel: %w", cerr)
}
m.ChannelID = c.ID

View File

@ -1,7 +1,7 @@
package state
import (
"github.com/pkg/errors"
"fmt"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
@ -375,7 +375,7 @@ func (s *State) onEvent(iface interface{}) {
}
func (s *State) stateErr(err error, wrap string) {
s.StateLog(errors.Wrap(err, wrap))
s.StateLog(fmt.Errorf("%s: %w", wrap, err))
}
func (s *State) batchLog(errors []error) {
@ -495,6 +495,6 @@ func storeGuildCreate(cab *store.Cabinet, guild *gateway.GuildCreateEvent) []err
func newErrorStack() (*[]error, func(error, string)) {
var errs = new([]error)
return errs, func(err error, wrap string) {
*errs = append(*errs, errors.Wrap(err, wrap))
*errs = append(*errs, fmt.Errorf("%s: %w", wrap, err))
}
}

View File

@ -1,7 +1,7 @@
// Package store contains interfaces of the state's storage and its
// implementations.
//
// Getter Methods
// # Getter Methods
//
// All getter methods will be wrapped by the State. If the State can't find
// anything in the storage, it will call the API itself and automatically add
@ -15,7 +15,7 @@
// Getter methods should not care about returning slices in order, unless
// explicitly stated against.
//
// ErrNotFound Rules
// # ErrNotFound Rules
//
// If a getter method cannot find something, it should return ErrNotFound.
// Callers including State may check if the error is ErrNotFound to do something
@ -27,7 +27,7 @@
// ErrNotFound when either happens. This will make State refetch from the API,
// so it is not ideal.
//
// Remove Methods
// # Remove Methods
//
// Remove methods should return a nil error if the item it wants to delete is
// not found. This helps save some additional work in some cases.

View File

@ -8,11 +8,11 @@ import (
"strings"
"time"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/utils/bot"
"github.com/diamondburned/arikawa/v3/utils/bot/extras/arguments"
"github.com/diamondburned/arikawa/v3/utils/bot/extras/middlewares"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
)
type Bot struct {

View File

@ -6,9 +6,9 @@ import (
"runtime"
"strings"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/utils/bot"
"github.com/diamondburned/arikawa/v3/utils/bot/extras/middlewares"
"github.com/diamondburned/arikawa/v3/gateway"
)
// Flag for administrators only.

View File

@ -2,6 +2,7 @@ package bot
import (
"context"
"errors"
"fmt"
"log"
"os"
@ -11,8 +12,6 @@ import (
"syscall"
"time"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/session"
@ -61,7 +60,7 @@ func NewShardFunc(fn func(*state.State) (*Context, error)) shard.NewShardFunc {
bot, err := fn(state)
if err != nil {
return nil, errors.Wrap(err, "failed to create bot instance")
return nil, fmt.Errorf("failed to create bot instance: %w", err)
}
return bot, nil
@ -70,17 +69,17 @@ func NewShardFunc(fn func(*state.State) (*Context, error)) shard.NewShardFunc {
// Context is the bot state for commands and subcommands.
//
// Commands
// # Commands
//
// A command can be created by making it a method of Commands, or whatever
// struct was given to the constructor. This following example creates a command
// with a single integer argument (which can be ran with "~example 123"):
//
// func (c *Commands) Example(
// m *gateway.MessageCreateEvent, i int) (string, error) {
// func (c *Commands) Example(
// m *gateway.MessageCreateEvent, i int) (string, error) {
//
// return fmt.Sprintf("You sent: %d", i)
// }
// return fmt.Sprintf("You sent: %d", i)
// }
//
// Commands' exported methods will all be used as commands. Messages are parsed
// with its first argument (the command) mapped accordingly to c.MapName, which
@ -91,15 +90,15 @@ func NewShardFunc(fn func(*state.State) (*Context, error)) shard.NewShardFunc {
// types allowed are string, *discord.Embed, and *api.SendMessageData. Any other
// return types will invalidate the method.
//
// Events
// # Events
//
// An event can only have one argument, which is the pointer to the event
// struct. It can also only return error.
//
// func (c *Commands) Example(o *gateway.TypingStartEvent) error {
// log.Println("Someone's typing!")
// return nil
// }
// func (c *Commands) Example(o *gateway.TypingStartEvent) error {
// log.Println("Someone's typing!")
// return nil
// }
type Context struct {
*Subcommand
*state.State
@ -213,11 +212,11 @@ func Start(
m, err := shard.NewManager(token, newShard)
if err != nil {
return nil, errors.Wrap(err, "failed to create shard manager")
return nil, fmt.Errorf("failed to create shard manager: %w", err)
}
if err := m.Open(context.Background()); err != nil {
return nil, errors.Wrap(err, "failed to open")
return nil, fmt.Errorf("failed to open: %w", err)
}
return func() error {
@ -264,12 +263,12 @@ func WaitForInterrupt() {
// New makes a new context with a "~" as the prefix. cmds must be a pointer to a
// struct with a *Context field. Example:
//
// type Commands struct {
// Ctx *Context
// }
// type Commands struct {
// Ctx *Context
// }
//
// cmds := &Commands{}
// c, err := bot.New(session, cmds)
// cmds := &Commands{}
// c, err := bot.New(session, cmds)
//
// The default prefix is "~", which means commands must start with "~" followed
// by the command name in the first argument, else it will be ignored.
@ -297,7 +296,7 @@ func New(s *state.State, cmd interface{}) (*Context, error) {
}
if err := ctx.InitCommands(ctx); err != nil {
return nil, errors.Wrap(err, "failed to initialize with given cmds")
return nil, fmt.Errorf("failed to initialize with given cmds: %w", err)
}
return ctx, nil
@ -319,11 +318,10 @@ func (ctx *Context) Subcommands() []*Subcommand {
// FindMethod finds a method based on the struct and method name. The queried
// names will have their flags stripped.
//
// // Find a command from the main context:
// cmd := ctx.FindMethod("", "Method")
// // Find a command from a subcommand:
// cmd = ctx.FindMethod("Starboard", "Reset")
//
// // Find a command from the main context:
// cmd := ctx.FindMethod("", "Method")
// // Find a command from a subcommand:
// cmd = ctx.FindMethod("Starboard", "Reset")
func (ctx *Context) FindCommand(structName, methodName string) *MethodContext {
if structName == "" {
return ctx.Subcommand.FindCommand(methodName)
@ -361,7 +359,7 @@ func (ctx *Context) MustRegisterSubcommand(cmd interface{}, names ...string) *Su
func (ctx *Context) RegisterSubcommand(cmd interface{}, names ...string) (*Subcommand, error) {
s, err := NewSubcommand(cmd)
if err != nil {
return nil, errors.Wrap(err, "failed to add subcommand")
return nil, fmt.Errorf("failed to add subcommand: %w", err)
}
// Register the subcommand's name.
@ -377,7 +375,7 @@ func (ctx *Context) RegisterSubcommand(cmd interface{}, names ...string) (*Subco
}
if err := s.InitCommands(ctx); err != nil {
return nil, errors.Wrap(err, "failed to initialize subcommand")
return nil, fmt.Errorf("failed to initialize subcommand: %w", err)
}
// Check if the existing command name already exists. This could really be
@ -417,7 +415,7 @@ func (ctx *Context) Start() func() {
if ctx.stopFunc == nil {
cancel := ctx.State.AddHandler(func(v interface{}) {
if err := ctx.callCmd(v); err != nil {
ctx.ErrorLogger(errors.Wrap(err, "command error"))
ctx.ErrorLogger(fmt.Errorf("command error: %w", err))
}
})

View File

@ -1,6 +1,7 @@
package bot
import (
"errors"
"reflect"
"strings"
@ -8,7 +9,6 @@ import (
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/pkg/errors"
)
// Break is a non-fatal error that could be returned from middlewares to stop

View File

@ -1,9 +1,9 @@
package middlewares
import (
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/bot"
"github.com/diamondburned/arikawa/v3/utils/bot/extras/infer"
"github.com/diamondburned/arikawa/v3/discord"
)
func AdminOnly(ctx *bot.Context) func(interface{}) error {

View File

@ -1,12 +1,12 @@
package bot
import (
"errors"
"fmt"
"reflect"
"runtime"
"strings"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/gateway"
)
@ -44,21 +44,20 @@ func underline(word string) string {
// Subcommand is any form of command, which could be a top-level command or a
// subcommand.
//
// Allowed method signatures
// # Allowed method signatures
//
// These are the acceptable function signatures that would be parsed as commands
// or events. A return type <T> implies that return value will be ignored.
//
// func(*gateway.MessageCreateEvent, ...) (string, error)
// func(*gateway.MessageCreateEvent, ...) (*discord.Embed, error)
// func(*gateway.MessageCreateEvent, ...) (*api.SendMessageData, error)
// func(*gateway.MessageCreateEvent, ...) (T, error)
// func(*gateway.MessageCreateEvent, ...) error
// func(*gateway.MessageCreateEvent, ...)
// func(<AnyEvent>) (T, error)
// func(<AnyEvent>) error
// func(<AnyEvent>)
//
// func(*gateway.MessageCreateEvent, ...) (string, error)
// func(*gateway.MessageCreateEvent, ...) (*discord.Embed, error)
// func(*gateway.MessageCreateEvent, ...) (*api.SendMessageData, error)
// func(*gateway.MessageCreateEvent, ...) (T, error)
// func(*gateway.MessageCreateEvent, ...) error
// func(*gateway.MessageCreateEvent, ...)
// func(<AnyEvent>) (T, error)
// func(<AnyEvent>) error
// func(<AnyEvent>)
type Subcommand struct {
// Description is a string that's appended after the subcommand name in
// (*Context).Help().
@ -122,11 +121,11 @@ func NewSubcommand(cmd interface{}) (*Subcommand, error) {
sub := Subcommand{command: cmd}
if err := sub.reflectCommands(); err != nil {
return nil, errors.Wrap(err, "failed to reflect commands")
return nil, fmt.Errorf("failed to reflect commands: %w", err)
}
if err := sub.parseCommands(); err != nil {
return nil, errors.Wrap(err, "failed to parse commands")
return nil, fmt.Errorf("failed to parse commands: %w", err)
}
return &sub, nil
@ -148,9 +147,8 @@ func lowerFirstLetter(name string) string {
//
// There are two ways to use FindCommand:
//
// sub.FindCommand("MethodName")
// sub.FindCommand(thing.MethodName)
//
// sub.FindCommand("MethodName")
// sub.FindCommand(thing.MethodName)
func (sub *Subcommand) FindCommand(method interface{}) *MethodContext {
return sub.findMethod(method, false)
}
@ -181,9 +179,8 @@ func (sub *Subcommand) findMethod(method interface{}, inclEvents bool) *MethodCo
// runtimeMethodName returns the name of the method from the given method call.
// It is used as such:
//
// fmt.Println(methodName(t.Method_dash))
// // Output: main.T.Method_dash-fm
//
// fmt.Println(methodName(t.Method_dash))
// // Output: main.T.Method_dash-fm
func runtimeMethodName(v interface{}) string {
// https://github.com/diamondburned/arikawa/issues/146
@ -402,15 +399,15 @@ func (sub *Subcommand) parseCommands() error {
// methods, use a star (*). The given middleware argument can either be a
// function with one of the allowed methods or a *MiddlewareContext.
//
// Allowed function signatures
// # Allowed function signatures
//
// Below are the acceptable function signatures that would be parsed as a proper
// middleware. A return value of type T will be ignored. If the given function
// is invalid, then this method will panic.
//
// func(<AnyEvent>) (T, error)
// func(<AnyEvent>) error
// func(<AnyEvent>)
// func(<AnyEvent>) (T, error)
// func(<AnyEvent>) error
// func(<AnyEvent>)
//
// Note that although technically all of the above function signatures are
// acceptable, one should almost always return only an error.

View File

@ -2,7 +2,9 @@ package main
import (
"bytes"
_ "embed"
"flag"
"fmt"
"go/format"
"log"
"os"
@ -11,10 +13,6 @@ import (
"strings"
"text/template"
"unicode"
_ "embed"
"github.com/pkg/errors"
)
var (
@ -110,7 +108,7 @@ var reEventStruct = regexp.MustCompile(eventStructRegex)
func (r *registry) CrawlFile(name string) error {
f, err := os.ReadFile(name)
if err != nil {
return errors.Wrap(err, "failed to read file")
return fmt.Errorf("failed to read file: %w", err)
}
for _, match := range reEventStruct.FindAllSubmatch(f, -1) {

View File

@ -2,14 +2,13 @@ package main
import (
"bytes"
_ "embed"
"flag"
"go/format"
"log"
"os"
"path/filepath"
"text/template"
_ "embed"
)
type data struct {

View File

@ -1,15 +1,15 @@
// Package handler handles incoming Gateway events. It reflects the function's
// first argument and caches that for use in each event.
//
// Performance
// # Performance
//
// Each call to the event would take 167 ns/op for roughly each handler. Scaling
// that up to 100 handlers is roughly the same as multiplying 167 ns by 100,
// which gives 16700 ns or 0.0167 ms.
//
// BenchmarkReflect-8 7260909 167 ns/op
// BenchmarkReflect-8 7260909 167 ns/op
//
// Usage
// # Usage
//
// Handler's usage is mostly similar to Discordgo, in that AddHandler expects a
// function with only one argument or an event channel. For more information,
@ -18,11 +18,10 @@ package handler
import (
"context"
"errors"
"fmt"
"reflect"
"sync"
"github.com/pkg/errors"
)
// Handler is a container for command handlers. A zero-value instance is a valid
@ -125,15 +124,15 @@ func (h *Handler) ChanFor(fn func(interface{}) bool) (out <-chan interface{}, ca
// handler when called. A handler type is either a single-argument no-return
// function or a channel.
//
// Function
// # Function
//
// A handler can be a function with a single argument that is the expected event
// type. It must not have any returns or any other number of arguments.
//
// // An example of a valid function handler.
// h.AddHandler(func(*gateway.MessageCreateEvent) {})
// // An example of a valid function handler.
// h.AddHandler(func(*gateway.MessageCreateEvent) {})
//
// Channel
// # Channel
//
// A handler can also be a channel. The underlying type that the channel wraps
// around will be the event type. As such, the type rules are the same as
@ -146,10 +145,9 @@ func (h *Handler) ChanFor(fn func(interface{}) bool) (out <-chan interface{}, ca
// When the rm callback that is returned is called, it will also guarantee that
// all blocking sends will be cancelled. This helps prevent dangling goroutines.
//
// // An example of a valid channel handler.
// ch := make(chan *gateway.MessageCreateEvent)
// h.AddHandler(ch)
//
// // An example of a valid channel handler.
// ch := make(chan *gateway.MessageCreateEvent)
// h.AddHandler(ch)
func (h *Handler) AddHandler(handler interface{}) (rm func()) {
rm, err := h.addHandler(handler, false)
if err != nil {
@ -210,7 +208,7 @@ func (h *Handler) addHandler(fn interface{}, sync bool) (rm func(), err error) {
// Reflect the handler
r, err := newHandler(fn, sync)
if err != nil {
return nil, errors.Wrap(err, "handler reflect failed")
return nil, fmt.Errorf("handler reflect failed: %w", err)
}
var id int

View File

@ -5,12 +5,11 @@ package httputil
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"time"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/utils/httputil/httpdriver"
"github.com/diamondburned/arikawa/v3/utils/json"
)
@ -213,7 +212,7 @@ func (c *Client) request(
fn(q, nil)
}
doErr = errors.Wrap(err, "failed to apply http request options")
doErr = fmt.Errorf("failed to apply http request options: %w", err)
return
}
@ -239,7 +238,7 @@ func (c *Client) request(
}
if onRespErr != nil {
doErr = errors.Wrap(onRespErr, "OnResponse handler failed")
doErr = fmt.Errorf("OnResponse handler failed: %w", onRespErr)
return
}

View File

@ -1,6 +1,7 @@
package sendpart
import (
"fmt"
"io"
"mime/multipart"
"net/url"
@ -8,7 +9,6 @@ import (
"github.com/diamondburned/arikawa/v3/utils/httputil"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// File represents a file to be uploaded to Discord.
@ -80,11 +80,11 @@ func Write(body *multipart.Writer, item interface{}, files []File) error {
// Encode the JSON body first
w, err := body.CreateFormField("payload_json")
if err != nil {
return errors.Wrap(err, "failed to create bodypart for JSON")
return fmt.Errorf("failed to create bodypart for JSON: %w", err)
}
if err := json.EncodeStream(w, item); err != nil {
return errors.Wrap(err, "failed to encode JSON")
return fmt.Errorf("failed to encode JSON: %w", err)
}
for i, file := range files {
@ -92,11 +92,11 @@ func Write(body *multipart.Writer, item interface{}, files []File) error {
w, err := body.CreateFormFile("file"+num, file.Name)
if err != nil {
return errors.Wrap(err, "failed to create bodypart for "+num)
return fmt.Errorf("failed to create bodypart for %q: %w", num, err)
}
if _, err := io.Copy(w, file.Reader); err != nil {
return errors.Wrap(err, "failed to write for file "+num)
return fmt.Errorf("failed to write for file %q: %w", num, err)
}
}

View File

@ -2,11 +2,11 @@ package ws
import (
"context"
"fmt"
"io"
"net/http"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// Codec holds the codec states for Websocket implementations to share with the
@ -107,7 +107,7 @@ func (c *Codec) send(ctx context.Context, ch chan<- Op, op Op) error {
func newErrOp(err error, wrap string) Op {
if wrap != "" {
err = errors.Wrap(err, wrap)
err = fmt.Errorf("%s: %w", wrap, err)
}
ev := &BackgroundErrorEvent{

View File

@ -3,6 +3,7 @@ package ws
import (
"compress/zlib"
"context"
"errors"
"fmt"
"io"
"net/http"
@ -10,7 +11,6 @@ import (
"time"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
)
const rwBufferSize = 1 << 15 // 32KB
@ -99,7 +99,7 @@ func (c *Conn) Dial(ctx context.Context, addr string) (<-chan Op, error) {
conn, _, err := c.dialer.DialContext(ctx, addr, c.codec.Headers)
if err != nil {
return nil, errors.Wrap(err, "failed to dial WS")
return nil, fmt.Errorf("failed to dial WS: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
@ -270,12 +270,12 @@ func (state *loopState) handle(ctx context.Context, opCh chan<- Op) error {
if state.zlib == nil {
z, err := zlib.NewReader(r)
if err != nil {
return errors.Wrap(err, "failed to create a zlib reader")
return fmt.Errorf("failed to create a zlib reader: %w", err)
}
state.zlib = z
} else {
if err := state.zlib.(zlib.Resetter).Reset(r, nil); err != nil {
return errors.Wrap(err, "failed to reset zlib reader")
return fmt.Errorf("failed to reset zlib reader: %w", err)
}
}
@ -284,7 +284,7 @@ func (state *loopState) handle(ctx context.Context, opCh chan<- Op) error {
}
if err := state.codec.DecodeInto(ctx, r, &state.buf, opCh); err != nil {
return errors.Wrap(err, "error distributing event")
return fmt.Errorf("error distributing event: %w", err)
}
return nil

View File

@ -2,13 +2,13 @@ package ws
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/diamondburned/arikawa/v3/internal/lazytime"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// ConnectionError is given to the user if the gateway fails to connect to the
@ -178,7 +178,7 @@ func (g *Gateway) Send(ctx context.Context, data Event) error {
b, err := json.Marshal(op)
if err != nil {
return errors.Wrap(err, "failed to encode payload")
return fmt.Errorf("failed to encode payload: %w", err)
}
// WS should already be thread-safe.
@ -304,7 +304,7 @@ func (g *Gateway) SendError(err error) {
// SendErrorWrap is a convenient function over SendError.
func (g *Gateway) SendErrorWrap(err error, message string) {
g.SendError(errors.Wrap(err, message))
g.SendError(fmt.Errorf("%s: %w", message, err))
}
func (g *Gateway) spin(ctx context.Context, h Handler) {
@ -391,7 +391,7 @@ func (g *Gateway) spin(ctx context.Context, h Handler) {
// Ensure that we've reconnected successfully. Exit otherwise.
if g.srcOp == nil {
err = errors.Wrap(err, "failed to reconnect after max attempts")
err = fmt.Errorf("failed to reconnect after max attempts: %w", err)
g.SendError(ConnectionError{err})
return
}

View File

@ -2,11 +2,11 @@ package ws
import (
"context"
"errors"
"fmt"
"sync"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/pkg/errors"
)
// OpCode is the type for websocket Op codes. Op codes less than 0 are

View File

@ -4,10 +4,10 @@ package ws
import (
"context"
"fmt"
"log"
"sync"
"github.com/pkg/errors"
"golang.org/x/time/rate"
)
@ -54,7 +54,7 @@ func NewCustomWebsocket(conn Connection, addr string) *Websocket {
func (ws *Websocket) Dial(ctx context.Context) (<-chan Op, error) {
if err := ws.dialLimiter.Wait(ctx); err != nil {
// Expired, fatal error
return nil, errors.Wrap(err, "failed to wait for dial rate limiter")
return nil, fmt.Errorf("failed to wait for dial rate limiter: %w", err)
}
ws.mutex.Lock()
@ -81,7 +81,7 @@ func (ws *Websocket) Send(ctx context.Context, b []byte) error {
if err := sendLimiter.Wait(ctx); err != nil {
WSDebug("Send rate limiter timed out.")
return errors.Wrap(err, "SendLimiter failed")
return fmt.Errorf("SendLimiter failed: %w", err)
}
WSDebug("Send has passed the rate limiting.")

View File

@ -2,20 +2,19 @@ package voice
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/diamondburned/arikawa/v3/state"
"github.com/diamondburned/arikawa/v3/utils/handler"
"github.com/diamondburned/arikawa/v3/utils/ws/ophandler"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/gateway"
"github.com/diamondburned/arikawa/v3/internal/moreatomic"
"github.com/diamondburned/arikawa/v3/session"
"github.com/diamondburned/arikawa/v3/state"
"github.com/diamondburned/arikawa/v3/utils/handler"
"github.com/diamondburned/arikawa/v3/utils/ws"
"github.com/diamondburned/arikawa/v3/utils/ws/ophandler"
"github.com/diamondburned/arikawa/v3/voice/udp"
"github.com/diamondburned/arikawa/v3/voice/voicegateway"
)
@ -106,7 +105,7 @@ type Session struct {
func NewSession(state MainSession) (*Session, error) {
u, err := state.Me()
if err != nil {
return nil, errors.Wrap(err, "failed to get me")
return nil, fmt.Errorf("failed to get me: %w", err)
}
return NewSessionCustom(state, u.ID), nil
@ -201,7 +200,7 @@ func (s *Session) updateState(ev *gateway.VoiceStateUpdateEvent) {
// Speaking.
func (s *Session) JoinChannelAndSpeak(ctx context.Context, chID discord.ChannelID, mute, deaf bool) error {
if err := s.JoinChannel(ctx, chID, mute, deaf); err != nil {
return errors.Wrap(err, "cannot join channel")
return fmt.Errorf("cannot join channel: %w", err)
}
return s.Speaking(ctx, voicegateway.Microphone)
}
@ -219,7 +218,7 @@ func (s *Session) JoinChannel(ctx context.Context, chID discord.ChannelID, mute,
var err error
ch, err = s.session.Channel(chID)
if err != nil {
return errors.Wrap(err, "invalid channel ID")
return fmt.Errorf("invalid channel ID: %w", err)
}
}
@ -308,7 +307,7 @@ func (s *Session) JoinChannel(ctx context.Context, chID discord.ChannelID, mute,
case <-timer.C:
continue
case <-ctx.Done():
return errors.Wrap(err, "cannot ask Discord for events")
return fmt.Errorf("cannot ask Discord for events: %w", err)
}
}
@ -328,12 +327,12 @@ func (s *Session) askDiscord(
// https://discord.com/developers/docs/topics/voice-connections#retrieving-voice-server-information
// Send a Voice State Update event to the gateway.
if err := s.session.SendGateway(ctx, data); err != nil {
return errors.Wrap(err, "failed to send Voice State Update event")
return fmt.Errorf("failed to send Voice State Update event: %w", err)
}
// Wait for 2 replies. The above command should reply with these 2 events.
if err := s.waitForIncoming(ctx, chs); err != nil {
return errors.Wrap(err, "failed to wait for needed gateway events")
return fmt.Errorf("failed to wait for needed gateway events: %w", err)
}
return nil
@ -381,7 +380,7 @@ func (s *Session) reconnectCtx(ctx context.Context) error {
ws.WSDebug("Sending stop handle.")
if err := s.udpManager.Pause(ctx); err != nil {
return errors.Wrap(err, "cannot pause UDP manager")
return fmt.Errorf("cannot pause UDP manager: %w", err)
}
defer func() {
if !s.udpManager.Continue() {
@ -410,7 +409,7 @@ func (s *Session) reconnectCtx(ctx context.Context) error {
// Emit the error. It's fine to do this here since this is the only
// place that can error out.
s.Handler.Call(&ReconnectError{err})
return errors.Wrap(err, "cannot wait for event sequence from voice gateway")
return fmt.Errorf("cannot wait for event sequence from voice gateway: %w", err)
}
// Start dispatching.
@ -431,12 +430,12 @@ func (s *Session) spinGateway(ctx context.Context, gwch <-chan ws.Op) error {
return ctx.Err()
case ev, ok := <-gwch:
if !ok {
return errors.Wrap(s.gateway.LastError(), "voice gateway error")
return fmt.Errorf("voice gateway error: %w", s.gateway.LastError())
}
switch data := ev.Data.(type) {
case *ws.CloseEvent:
return errors.Wrap(err, "voice gateway error")
return fmt.Errorf("voice gateway error: %w", err)
case *voicegateway.ReadyEvent:
ws.WSDebug("Got ready from voice gateway, SSRC:", data.SSRC)
@ -444,7 +443,7 @@ func (s *Session) spinGateway(ctx context.Context, gwch <-chan ws.Op) error {
// Prepare the UDP voice connection.
conn, err = s.udpManager.Dial(ctx, data.Addr(), data.SSRC)
if err != nil {
return errors.Wrap(err, "failed to open voice UDP connection")
return fmt.Errorf("failed to open voice UDP connection: %w", err)
}
if err := s.gateway.Send(ctx, &voicegateway.SelectProtocolCommand{
@ -455,7 +454,7 @@ func (s *Session) spinGateway(ctx context.Context, gwch <-chan ws.Op) error {
Mode: Protocol,
},
}); err != nil {
return errors.Wrap(err, "failed to send SelectProtocolCommand")
return fmt.Errorf("failed to send SelectProtocolCommand: %w", err)
}
case *voicegateway.SessionDescriptionEvent:
@ -545,7 +544,7 @@ func (s *Session) Leave(ctx context.Context) error {
}
if sendErr != nil {
return errors.Wrap(sendErr, "failed to update voice state")
return fmt.Errorf("failed to update voice state: %w", sendErr)
}
return nil
@ -559,7 +558,7 @@ func (s *Session) cancelGateway(ctx context.Context) error {
// Wait for the previous gateway to finish closing up, but make sure to
// bail if the context expires.
if err := ophandler.WaitForDone(ctx, s.gwDone); err != nil {
return errors.Wrap(err, "cannot wait for gateway to close")
return fmt.Errorf("cannot wait for gateway to close: %w", err)
}
}

View File

@ -2,6 +2,8 @@ package voice
import (
"context"
"errors"
"fmt"
"log"
"math/rand"
"os"
@ -20,7 +22,6 @@ import (
"github.com/diamondburned/arikawa/v3/voice/testdata"
"github.com/diamondburned/arikawa/v3/voice/udp"
"github.com/diamondburned/arikawa/v3/voice/voicegateway"
"github.com/pkg/errors"
)
func TestMain(m *testing.M) {
@ -165,7 +166,7 @@ func raceMe(t *testing.T, wrapErr string, fn func() error) {
wgr.Wait()
if err != nil {
t.Fatal("race test failed:", errors.Wrap(err, wrapErr))
t.Fatal("race test failed:", fmt.Errorf("%s: %w", wrapErr, err))
}
}

View File

@ -2,10 +2,9 @@ package testdata
import (
"encoding/binary"
"fmt"
"io"
"os"
"github.com/pkg/errors"
)
const Nico = "testdata/nico.dca"
@ -15,7 +14,7 @@ const Nico = "testdata/nico.dca"
func WriteOpus(w io.Writer, file string) error {
f, err := os.Open(file)
if err != nil {
return errors.Wrap(err, "failed to open "+file)
return fmt.Errorf("failed to open %s: %w", file, err)
}
defer f.Close()
@ -26,7 +25,7 @@ func WriteOpus(w io.Writer, file string) error {
if err == io.EOF {
return nil
}
return errors.Wrap(err, "failed to read "+file)
return fmt.Errorf("failed to read %s: %w", file, err)
}
// Read the integer
@ -35,7 +34,7 @@ func WriteOpus(w io.Writer, file string) error {
// Copy the frame.
_, err = io.CopyN(w, f, framelen)
if err != nil && err != io.EOF {
return errors.Wrap(err, "failed to write")
return fmt.Errorf("failed to write: %w", err)
}
}
}

View File

@ -4,12 +4,13 @@ import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"sync"
"time"
"github.com/pkg/errors"
"golang.org/x/crypto/nacl/secretbox"
)
@ -86,7 +87,7 @@ func DialConnectionCustom(
// Create a new UDP connection.
conn, err := dialer.DialContext(ctx, "udp", addr)
if err != nil {
return nil, errors.Wrap(err, "failed to dial host")
return nil, fmt.Errorf("failed to dial host: %w", err)
}
// https://discord.com/developers/docs/topics/voice-connections#ip-discovery
@ -97,7 +98,7 @@ func DialConnectionCustom(
_, err = conn.Write(ssrcBuffer[:])
if err != nil {
return nil, errors.Wrap(err, "failed to write SSRC buffer")
return nil, fmt.Errorf("failed to write SSRC buffer: %w", err)
}
var ipBuffer [74]byte
@ -105,7 +106,7 @@ func DialConnectionCustom(
// ReadFull makes sure to read all 74 bytes.
_, err = io.ReadFull(conn, ipBuffer[:])
if err != nil {
return nil, errors.Wrap(err, "failed to read IP buffer")
return nil, fmt.Errorf("failed to read IP buffer: %w", err)
}
ipbody := ipBuffer[8:72]
@ -155,15 +156,15 @@ func DialConnectionCustom(
// be consistent with th given frameDuration. For the right combination, refer
// to the Valid Parameters section below.
//
// Valid Parameters
// # Valid Parameters
//
// The following table lists the recommended parameters for these variables.
//
// +---------+-----+-----+------+------+
// | Mode | 10 | 20 | 40 | 60 |
// +---------+-----+-----+------+------+
// | ts incr | 480 | 960 | 1920 | 2880 |
// +---------+-----+-----+------+------+
// +---------+-----+-----+------+------+
// | Mode | 10 | 20 | 40 | 60 |
// +---------+-----+-----+------+------+
// | ts incr | 480 | 960 | 1920 | 2880 |
// +---------+-----+-----+------+------+
//
// Note that audio mode is omitted, as it is not recommended. For the full
// table, refer to the IETF RFC7587 section 4.2 link above.
@ -222,7 +223,7 @@ func (c *Connection) Write(b []byte) (int, error) {
case <-c.frequency.C:
// ok
case <-c.stopFreq:
return 0, errors.Wrap(net.ErrClosed, "frequency ticker stopped")
return 0, fmt.Errorf("frequency ticker stopped: %w", net.ErrClosed)
}
_, err := c.conn.Write(toSend)

View File

@ -2,11 +2,12 @@ package udp
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/diamondburned/arikawa/v3/utils/ws"
"github.com/pkg/errors"
)
// ErrManagerClosed is returned when a Manager that is already closed is dialed,
@ -152,7 +153,7 @@ func (m *Manager) Dial(ctx context.Context, addr string, ssrc uint32) (*Connecti
if err != nil {
// Unlock if we failed.
<-m.connLock
return nil, errors.Wrap(err, "failed to dial")
return nil, fmt.Errorf("failed to dial: %w", err)
}
if m.frequency > 0 && m.timeIncr > 0 {

View File

@ -11,12 +11,11 @@ package voicegateway
import (
"context"
"errors"
"strings"
"sync"
"time"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/ws"
)