*: Linting and typo fixes (#134)

* Linting and typo fixes

* Linting and typo fixes

* revert comma fix
This commit is contained in:
Maximilian von Lindern 2020-07-30 01:29:01 +02:00 committed by diamondburned
parent 8baf8ee84b
commit 1585797b52
26 changed files with 116 additions and 117 deletions

View File

@ -3,7 +3,7 @@
[![Pipeline status](https://gitlab.com/diamondburned/arikawa/badges/master/pipeline.svg?style=flat-square)](https://gitlab.com/diamondburned/arikawa/pipelines ) [![Pipeline status](https://gitlab.com/diamondburned/arikawa/badges/master/pipeline.svg?style=flat-square)](https://gitlab.com/diamondburned/arikawa/pipelines )
[![ Coverage](https://gitlab.com/diamondburned/arikawa/badges/master/coverage.svg?style=flat-square)](https://gitlab.com/diamondburned/arikawa/commits/master ) [![ Coverage](https://gitlab.com/diamondburned/arikawa/badges/master/coverage.svg?style=flat-square)](https://gitlab.com/diamondburned/arikawa/commits/master )
[![ Report Card](https://goreportcard.com/badge/github.com/diamondburned/arikawa?style=flat-square )](https://goreportcard.com/report/github.com/diamondburned/arikawa) [![ Report Card](https://goreportcard.com/badge/github.com/diamondburned/arikawa?style=flat-square )](https://goreportcard.com/report/github.com/diamondburned/arikawa)
[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue?style=flat-square )](https://godoc.org/github.com/diamondburned/arikawa ) [![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue?style=flat-square )](https://pkg.go.dev/github.com/diamondburned/arikawa )
[![ Examples](https://img.shields.io/badge/Example-__example%2F-blueviolet?style=flat-square )](https://github.com/diamondburned/arikawa/tree/master/_example ) [![ Examples](https://img.shields.io/badge/Example-__example%2F-blueviolet?style=flat-square )](https://github.com/diamondburned/arikawa/tree/master/_example )
[![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23arikawa-%237289da?style=flat-square)](https://discord.gg/7jSf85J ) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23arikawa-%237289da?style=flat-square)](https://discord.gg/7jSf85J )
[![ Hime Arikawa](https://img.shields.io/badge/Hime-Arikawa-ea75a2?style=flat-square )](https://hime-goto.fandom.com/wiki/Hime_Arikawa ) [![ Hime Arikawa](https://img.shields.io/badge/Hime-Arikawa-ea75a2?style=flat-square )](https://hime-goto.fandom.com/wiki/Hime_Arikawa )
@ -15,7 +15,7 @@ A Golang library for the Discord API.
### [Simple](https://github.com/diamondburned/arikawa/tree/master/_example/simple) ### [Simple](https://github.com/diamondburned/arikawa/tree/master/_example/simple)
Simple bot example without any state. All it does is logging messages sent into Simple bot example without any state. All it does is logging messages sent into
the console. Run with `BOT_TOKEN="TOKEN" go run .` the console. Run with `BOT_TOKEN="TOKEN" go run .`.
### [Undeleter](https://github.com/diamondburned/arikawa/tree/master/_example/undeleter) ### [Undeleter](https://github.com/diamondburned/arikawa/tree/master/_example/undeleter)
@ -24,8 +24,8 @@ everything, including messages. It detects when someone deletes a message,
logging the content into the console. logging the content into the console.
This example demonstrates the PreHandler feature of this library. PreHandler This example demonstrates the PreHandler feature of this library. PreHandler
calls all handlers that are registered (separately from session), calling them calls all handlers that are registered (separately from the session), calling
before the state is updated. them before the state is updated.
### [Advanced Bot](https://github.com/diamondburned/arikawa/tree/master/_example/advanced_bot) ### [Advanced Bot](https://github.com/diamondburned/arikawa/tree/master/_example/advanced_bot)
@ -34,7 +34,7 @@ that's built-in. The router turns exported struct methods into commands, its
arguments into command arguments, and more. arguments into command arguments, and more.
The library has a pretty detailed documentation available in [GoDoc The library has a pretty detailed documentation available in [GoDoc
Reference](https://godoc.org/github.com/diamondburned/arikawa/bot). Reference](https://pkg.go.dev/github.com/diamondburned/arikawa/bot).
## Comparison: Why not discordgo? ## Comparison: Why not discordgo?
@ -66,7 +66,7 @@ things in the state, which is useful for keeping it updated.
## Testing ## Testing
The package includes integration tests that require `$BOT_TOKEN`. To run these The package includes integration tests that require `$BOT_TOKEN`. To run these
tests, do tests, do:
```sh ```sh
export BOT_TOKEN="<BOT_TOKEN>" export BOT_TOKEN="<BOT_TOKEN>"

View File

@ -26,22 +26,22 @@ func (bot *Bot) Setup(sub *bot.Subcommand) {
} }
// Help prints the default help message. // Help prints the default help message.
func (bot *Bot) Help(m *gateway.MessageCreateEvent) (string, error) { func (bot *Bot) Help(*gateway.MessageCreateEvent) (string, error) {
return bot.Ctx.Help(), nil return bot.Ctx.Help(), nil
} }
// Add demonstrates the usage of typed arguments. Run it with "~add 1 2". // Add demonstrates the usage of typed arguments. Run it with "~add 1 2".
func (bot *Bot) Add(m *gateway.MessageCreateEvent, a, b int) (string, error) { func (bot *Bot) Add(_ *gateway.MessageCreateEvent, a, b int) (string, error) {
return fmt.Sprintf("%d + %d = %d", a, b, a+b), nil return fmt.Sprintf("%d + %d = %d", a, b, a+b), nil
} }
// Ping is a simple ping example, perhaps the most simple you could make it. // Ping is a simple ping example, perhaps the most simple you could make it.
func (bot *Bot) Ping(m *gateway.MessageCreateEvent) (string, error) { func (bot *Bot) Ping(*gateway.MessageCreateEvent) (string, error) {
return "Pong!", nil return "Pong!", nil
} }
// Say demonstrates how arguments.Flag could be used without the flag library. // Say demonstrates how arguments.Flag could be used without the flag library.
func (bot *Bot) Say(m *gateway.MessageCreateEvent, f bot.RawArguments) (string, error) { func (bot *Bot) Say(_ *gateway.MessageCreateEvent, f bot.RawArguments) (string, error) {
if f != "" { if f != "" {
return string(f), nil return string(f), nil
} }
@ -95,7 +95,7 @@ func (bot *Bot) Repeat(m *gateway.MessageCreateEvent) (string, error) {
// Embed is a simple embed creator. Its purpose is to demonstrate the usage of // Embed is a simple embed creator. Its purpose is to demonstrate the usage of
// the ParseContent interface, as well as using the stdlib flag package. // the ParseContent interface, as well as using the stdlib flag package.
func (bot *Bot) Embed(m *gateway.MessageCreateEvent, f arguments.Flag) (*discord.Embed, error) { func (bot *Bot) Embed(_ *gateway.MessageCreateEvent, f arguments.Flag) (*discord.Embed, error) {
fs := arguments.NewFlagSet() fs := arguments.NewFlagSet()
var ( var (

View File

@ -27,7 +27,7 @@ func (d *Debug) Setup(sub *bot.Subcommand) {
// Manually set the usage for each function. // Manually set the usage for each function.
sub.ChangeCommandInfo("GOOS", "GOOS", "Prints the current operating system") sub.ChangeCommandInfo("GOOS", "GOOS", "Prints the current operating system")
sub.ChangeCommandInfo("GC", "GC", "Triggers the garbage collecto") sub.ChangeCommandInfo("GC", "GC", "Triggers the garbage collector")
sub.ChangeCommandInfo("Goroutines", "", "Prints the current number of Goroutines") sub.ChangeCommandInfo("Goroutines", "", "Prints the current number of Goroutines")
sub.Hide("Die") sub.Hide("Die")
@ -35,7 +35,7 @@ func (d *Debug) Setup(sub *bot.Subcommand) {
} }
// ~go goroutines // ~go goroutines
func (d *Debug) Goroutines(m *gateway.MessageCreateEvent) (string, error) { func (d *Debug) Goroutines(*gateway.MessageCreateEvent) (string, error) {
return fmt.Sprintf( return fmt.Sprintf(
"goroutines: %d", "goroutines: %d",
runtime.NumGoroutine(), runtime.NumGoroutine(),
@ -43,12 +43,12 @@ func (d *Debug) Goroutines(m *gateway.MessageCreateEvent) (string, error) {
} }
// ~go GOOS // ~go GOOS
func (d *Debug) GOOS(m *gateway.MessageCreateEvent) (string, error) { func (d *Debug) GOOS(*gateway.MessageCreateEvent) (string, error) {
return strings.Title(runtime.GOOS), nil return strings.Title(runtime.GOOS), nil
} }
// ~go GC // ~go GC
func (d *Debug) GC(m *gateway.MessageCreateEvent) (string, error) { func (d *Debug) GC(*gateway.MessageCreateEvent) (string, error) {
runtime.GC() runtime.GC()
return "Done.", nil return "Done.", nil
} }

View File

@ -13,10 +13,10 @@ import (
var ( var (
BaseEndpoint = "https://discord.com" BaseEndpoint = "https://discord.com"
APIVersion = "6" Version = "6"
APIPath = "/api/v" + APIVersion Path = "/api/v" + Version
Endpoint = BaseEndpoint + APIPath + "/" Endpoint = BaseEndpoint + Path + "/"
EndpointGateway = Endpoint + "gateway" EndpointGateway = Endpoint + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot" EndpointGatewayBot = EndpointGateway + "/bot"
) )
@ -34,7 +34,7 @@ func NewClient(token string) *Client {
func NewCustomClient(token string, httpClient *httputil.Client) *Client { func NewCustomClient(token string, httpClient *httputil.Client) *Client {
ses := Session{ ses := Session{
Limiter: rate.NewLimiter(APIPath), Limiter: rate.NewLimiter(Path),
Token: token, Token: token,
UserAgent: UserAgent, UserAgent: UserAgent,
} }

View File

@ -87,10 +87,10 @@ type MoveChannelData struct {
// MoveChannel modifies the position of channels in the guild. // MoveChannel modifies the position of channels in the guild.
// //
// Requires MANAGE_CHANNELS. // Requires MANAGE_CHANNELS.
func (c *Client) MoveChannel(guildID discord.GuildID, datum []MoveChannelData) error { func (c *Client) MoveChannel(guildID discord.GuildID, data []MoveChannelData) error {
return c.FastRequest( return c.FastRequest(
"PATCH", "PATCH",
EndpointGuilds+guildID.String()+"/channels", httputil.WithJSONBody(datum), EndpointGuilds+guildID.String()+"/channels", httputil.WithJSONBody(data),
) )
} }
@ -193,7 +193,7 @@ func (c *Client) EditChannelPermission(
// role in a channel. Only usable for guild channels. // role in a channel. Only usable for guild channels.
// //
// Requires the MANAGE_ROLES permission. // Requires the MANAGE_ROLES permission.
func (c *Client) DeleteChannelPermission(channelID, overwriteID discord.Snowflake) error { func (c *Client) DeleteChannelPermission(channelID discord.ChannelID, overwriteID discord.Snowflake) error {
return c.FastRequest( return c.FastRequest(
"DELETE", "DELETE",
EndpointChannels+channelID.String()+"/permissions/"+overwriteID.String(), EndpointChannels+channelID.String()+"/permissions/"+overwriteID.String(),

View File

@ -18,8 +18,8 @@ func NewCustomEmoji(id discord.EmojiID, name string) Emoji {
// Emojis returns a list of emoji objects for the given guild. // Emojis returns a list of emoji objects for the given guild.
func (c *Client) Emojis(guildID discord.GuildID) ([]discord.Emoji, error) { func (c *Client) Emojis(guildID discord.GuildID) ([]discord.Emoji, error) {
var emjs []discord.Emoji var e []discord.Emoji
return emjs, c.RequestJSON(&emjs, "GET", EndpointGuilds+guildID.String()+"/emojis") return e, c.RequestJSON(&e, "GET", EndpointGuilds+guildID.String()+"/emojis")
} }
// Emoji returns an emoji object for the given guild and emoji IDs. // Emoji returns an emoji object for the given guild and emoji IDs.

View File

@ -28,9 +28,8 @@ type Limiter struct {
Prefix string Prefix string
global *int64 // atomic guarded, unixnano global *int64 // atomic guarded, unixnano
buckets sync.Map buckets sync.Map
globalRate time.Duration
} }
type CustomRateLimit struct { type CustomRateLimit struct {
@ -43,7 +42,6 @@ type bucket struct {
custom *CustomRateLimit custom *CustomRateLimit
remaining uint64 remaining uint64
limit uint
reset time.Time reset time.Time
lastReset time.Time // only for custom lastReset time.Time // only for custom
@ -102,7 +100,7 @@ func (l *Limiter) Acquire(ctx context.Context, path string) error {
if b.remaining == 0 && b.reset.After(time.Now()) { if b.remaining == 0 && b.reset.After(time.Now()) {
// out of turns, gotta wait // out of turns, gotta wait
sleep = b.reset.Sub(time.Now()) sleep = time.Until(b.reset)
} else { } else {
// maybe global rate limit has it // maybe global rate limit has it
now := time.Now() now := time.Now()

View File

@ -4,7 +4,6 @@ import (
"io" "io"
"mime/multipart" "mime/multipart"
"strconv" "strconv"
"strings"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -15,8 +14,6 @@ import (
const AttachmentSpoilerPrefix = "SPOILER_" const AttachmentSpoilerPrefix = "SPOILER_"
var quoteEscaper = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
// AllowedMentions is a whitelist of mentions for a message. // AllowedMentions is a whitelist of mentions for a message.
// https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object // https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object
// //

View File

@ -115,7 +115,7 @@ var ShellwordsEscaper = strings.NewReplacer(
var nilV = reflect.Value{} var nilV = reflect.Value{}
func newArgument(t reflect.Type, variadic bool) (*Argument, error) { func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
// Allow array types if varidic is true. // Allow array types if variadic is true.
if variadic && t.Kind() == reflect.Slice { if variadic && t.Kind() == reflect.Slice {
t = t.Elem() t = t.Elem()
} }
@ -128,7 +128,7 @@ func newArgument(t reflect.Type, variadic bool) (*Argument, error) {
ptr = true ptr = true
} }
// This shouldn't be varidic. // This shouldn't be variadic.
if !variadic && typeI.Implements(typeICusP) { if !variadic && typeI.Implements(typeICusP) {
mt, _ := typeI.MethodByName("CustomParse") mt, _ := typeI.MethodByName("CustomParse")

View File

@ -7,11 +7,12 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/pkg/errors"
"github.com/diamondburned/arikawa/api" "github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/bot/extras/shellwords" "github.com/diamondburned/arikawa/bot/extras/shellwords"
"github.com/diamondburned/arikawa/gateway" "github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/state" "github.com/diamondburned/arikawa/state"
"github.com/pkg/errors"
) )
// Prefixer checks a message if it starts with the desired prefix. By default, // Prefixer checks a message if it starts with the desired prefix. By default,
@ -181,7 +182,7 @@ func Start(
// Wait blocks until SIGINT. // Wait blocks until SIGINT.
func Wait() { func Wait() {
sigs := make(chan os.Signal) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt) signal.Notify(sigs, os.Interrupt)
<-sigs <-sigs
} }
@ -249,13 +250,13 @@ func (ctx *Context) Subcommands() []*Subcommand {
// // Find a command from a subcommand: // // Find a command from a subcommand:
// cmd = ctx.FindMethod("Starboard", "Reset") // cmd = ctx.FindMethod("Starboard", "Reset")
// //
func (ctx *Context) FindCommand(structname, methodname string) *MethodContext { func (ctx *Context) FindCommand(structName, methodName string) *MethodContext {
if structname == "" { if structName == "" {
return ctx.Subcommand.FindCommand(methodname) return ctx.Subcommand.FindCommand(methodName)
} }
for _, sub := range ctx.subcommands { for _, sub := range ctx.subcommands {
if sub.StructName == structname { if sub.StructName == structName {
return sub.FindCommand(methodname) return sub.FindCommand(methodName)
} }
} }
return nil return nil
@ -268,8 +269,8 @@ func (ctx *Context) MustRegisterSubcommand(cmd interface{}) *Subcommand {
return ctx.MustRegisterSubcommandCustom(cmd, "") return ctx.MustRegisterSubcommandCustom(cmd, "")
} }
// MustReisterSubcommandCustom works similarly to MustRegisterSubcommand, but // MustRegisterSubcommandCustom works similarly to MustRegisterSubcommand, but
// takeks an extra argument for a command name override. // takes an extra argument for a command name override.
func (ctx *Context) MustRegisterSubcommandCustom(cmd interface{}, name string) *Subcommand { func (ctx *Context) MustRegisterSubcommandCustom(cmd interface{}, name string) *Subcommand {
s, err := ctx.RegisterSubcommandCustom(cmd, name) s, err := ctx.RegisterSubcommandCustom(cmd, name)
if err != nil { if err != nil {
@ -314,8 +315,8 @@ func (ctx *Context) RegisterSubcommandCustom(cmd interface{}, name string) (*Sub
return s, nil return s, nil
} }
// Start adds itself into the discordgo Session handlers. This needs to be run. // Start adds itself into the session handlers. This needs to be run. The
// The returned function is a delete function, which removes itself from the // returned function is a delete function, which removes itself from the
// Session handlers. // Session handlers.
func (ctx *Context) Start() func() { func (ctx *Context) Start() func() {
return ctx.State.AddHandler(func(v interface{}) { return ctx.State.AddHandler(func(v interface{}) {

View File

@ -117,7 +117,7 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
return nil return nil
} }
// trim the prefix before splitting, this way multi-words prefices work // trim the prefix before splitting, this way multi-words prefixes work
content := mc.Content[len(pf):] content := mc.Content[len(pf):]
if content == "" { if content == "" {
@ -226,7 +226,7 @@ func (ctx *Context) callMessageCreate(mc *gateway.MessageCreateEvent, value refl
vars := make([]reflect.Value, 0, len(arguments)) vars := make([]reflect.Value, 0, len(arguments))
// Parse the rest with variadic arguments. Go's reflect states that // Parse the rest with variadic arguments. Go's reflect states that
// varidic parameters will automatically be copied, which is good. // variadic parameters will automatically be copied, which is good.
for i := 0; len(arguments) > 0; i++ { for i := 0; len(arguments) > 0; i++ {
v, err := last.fn(arguments[0]) v, err := last.fn(arguments[0])
if err != nil { if err != nil {

View File

@ -30,11 +30,11 @@ func (h *hasPlumb) Plumber(_ *gateway.MessageCreateEvent, c RawArguments) error
} }
func TestSubcommandPlumb(t *testing.T) { func TestSubcommandPlumb(t *testing.T) {
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
c, err := New(state, &testc{}) c, err := New(s, &testc{})
if err != nil { if err != nil {
t.Fatal("Failed to create new context:", err) t.Fatal("Failed to create new context:", err)
} }
@ -78,11 +78,11 @@ func (h *onlyPlumb) Plumber(_ *gateway.MessageCreateEvent, c RawArguments) error
} }
func TestSubcommandOnlyPlumb(t *testing.T) { func TestSubcommandOnlyPlumb(t *testing.T) {
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
c, err := New(state, &testc{}) c, err := New(s, &testc{})
if err != nil { if err != nil {
t.Fatal("Failed to create new context:", err) t.Fatal("Failed to create new context:", err)
} }

View File

@ -50,7 +50,7 @@ func (t *testc) Custom(_ *gateway.MessageCreateEvent, c *ArgumentParts) {
func (t *testc) Variadic(_ *gateway.MessageCreateEvent, c ...*customParsed) { func (t *testc) Variadic(_ *gateway.MessageCreateEvent, c ...*customParsed) {
t.Return <- c[len(c)-1] t.Return <- c[len(c)-1]
} }
func (t *testc) TrailCustom(_ *gateway.MessageCreateEvent, s string, c ArgumentParts) { func (t *testc) TrailCustom(_ *gateway.MessageCreateEvent, _ string, c ArgumentParts) {
t.Return <- c t.Return <- c
} }
func (t *testc) Content(_ *gateway.MessageCreateEvent, c RawArguments) { func (t *testc) Content(_ *gateway.MessageCreateEvent, c RawArguments) {
@ -64,11 +64,11 @@ func (t *testc) OnTyping(*gateway.TypingStartEvent) {
} }
func TestNewContext(t *testing.T) { func TestNewContext(t *testing.T) {
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
c, err := New(state, &testc{}) c, err := New(s, &testc{})
if err != nil { if err != nil {
t.Fatal("Failed to create new context:", err) t.Fatal("Failed to create new context:", err)
} }
@ -80,12 +80,12 @@ func TestNewContext(t *testing.T) {
func TestContext(t *testing.T) { func TestContext(t *testing.T) {
var given = &testc{} var given = &testc{}
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
Handler: handler.New(), Handler: handler.New(),
} }
s, err := NewSubcommand(given) sub, err := NewSubcommand(given)
if err != nil { if err != nil {
t.Fatal("Failed to create subcommand:", err) t.Fatal("Failed to create subcommand:", err)
} }
@ -94,8 +94,8 @@ func TestContext(t *testing.T) {
Name: "arikawa/bot test", Name: "arikawa/bot test",
Description: "Just a test.", Description: "Just a test.",
Subcommand: s, Subcommand: sub,
State: state, State: s,
ParseArgs: DefaultArgsParser(), ParseArgs: DefaultArgsParser(),
} }
@ -105,11 +105,11 @@ func TestContext(t *testing.T) {
} }
if given.Ctx == nil { if given.Ctx == nil {
t.Fatal("given's Context field is nil") t.Fatal("given'sub Context field is nil")
} }
if given.Ctx.State.Store == nil { if given.Ctx.State.Store == nil {
t.Fatal("given's State is nil") t.Fatal("given'sub State is nil")
} }
}) })
@ -167,11 +167,11 @@ func TestContext(t *testing.T) {
ctx.HasPrefix = NewPrefix("~") ctx.HasPrefix = NewPrefix("~")
var ( var (
strings = "hacka doll no. 3" send = "hacka doll no. 3"
expects = []string{"hacka", "doll", "no.", "3"} expects = []string{"hacka", "doll", "no.", "3"}
) )
if err := expect(ctx, given, expects, "~send "+strings); err.Error() != "oh no" { if err := expect(ctx, given, expects, "~send "+send); err.Error() != "oh no" {
t.Fatal("Unexpected error:", err) t.Fatal("Unexpected error:", err)
} }
}) })
@ -355,26 +355,26 @@ func sendMsg(ctx *Context, given *testc, into interface{}, content string) (call
} }
func BenchmarkConstructor(b *testing.B) { func BenchmarkConstructor(b *testing.B) {
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = New(state, &testc{}) _, _ = New(s, &testc{})
} }
} }
func BenchmarkCall(b *testing.B) { func BenchmarkCall(b *testing.B) {
var given = &testc{} var given = &testc{}
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
s, _ := NewSubcommand(given) sub, _ := NewSubcommand(given)
var ctx = &Context{ var ctx = &Context{
Subcommand: s, Subcommand: sub,
State: state, State: s,
HasPrefix: NewPrefix("~"), HasPrefix: NewPrefix("~"),
ParseArgs: DefaultArgsParser(), ParseArgs: DefaultArgsParser(),
} }
@ -394,15 +394,15 @@ func BenchmarkCall(b *testing.B) {
func BenchmarkHelp(b *testing.B) { func BenchmarkHelp(b *testing.B) {
var given = &testc{} var given = &testc{}
var state = &state.State{ var s = &state.State{
Store: state.NewDefaultStore(nil), Store: state.NewDefaultStore(nil),
} }
s, _ := NewSubcommand(given) sub, _ := NewSubcommand(given)
var ctx = &Context{ var ctx = &Context{
Subcommand: s, Subcommand: sub,
State: state, State: s,
HasPrefix: NewPrefix("~"), HasPrefix: NewPrefix("~"),
ParseArgs: DefaultArgsParser(), ParseArgs: DefaultArgsParser(),
} }

View File

@ -2,18 +2,20 @@ package arguments
import ( import (
"testing" "testing"
"github.com/diamondburned/arikawa/discord"
) )
func TestChannelMention(t *testing.T) { func TestChannelMention(t *testing.T) {
test := new(ChannelMention) test := new(ChannelMention)
str := "<#123123>" str := "<#123123>"
id := 123123 var id discord.ChannelID = 123123
if err := test.Parse(str); err != nil { if err := test.Parse(str); err != nil {
t.Fatal("Expected", id, "error:", err) t.Fatal("Expected", id, "error:", err)
} }
if id := test.ID(); id != id { if actualID := test.ID(); actualID != id {
t.Fatal("Expected", id, "got", id) t.Fatal("Expected", id, "got", id)
} }
@ -25,13 +27,13 @@ func TestChannelMention(t *testing.T) {
func TestUserMention(t *testing.T) { func TestUserMention(t *testing.T) {
test := new(UserMention) test := new(UserMention)
str := "<@123123>" str := "<@123123>"
id := 123123 var id discord.UserID = 123123
if err := test.Parse(str); err != nil { if err := test.Parse(str); err != nil {
t.Fatal("Expected", id, "error:", err) t.Fatal("Expected", id, "error:", err)
} }
if id := test.ID(); id != id { if actualID := test.ID(); actualID != id {
t.Fatal("Expected", id, "got", id) t.Fatal("Expected", id, "got", id)
} }
@ -43,13 +45,13 @@ func TestUserMention(t *testing.T) {
func TestRoleMention(t *testing.T) { func TestRoleMention(t *testing.T) {
test := new(RoleMention) test := new(RoleMention)
str := "<@&123123>" str := "<@&123123>"
id := 123123 var id discord.RoleID = 123123
if err := test.Parse(str); err != nil { if err := test.Parse(str); err != nil {
t.Fatal("Expected", id, "error:", err) t.Fatal("Expected", id, "error:", err)
} }
if id := test.ID(); id != id { if actualID := test.ID(); actualID != id {
t.Fatal("Expected", id, "got", id) t.Fatal("Expected", id, "got", id)
} }

View File

@ -172,7 +172,7 @@ func (s *mockStore) Guild(id discord.GuildID) (*discord.Guild, error) {
}, nil }, nil
} }
func (s *mockStore) Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error) { func (s *mockStore) Member(_ discord.GuildID, userID discord.UserID) (*discord.Member, error) {
return &discord.Member{ return &discord.Member{
User: discord.User{ID: userID}, User: discord.User{ID: userID},
RoleIDs: []discord.RoleID{discord.RoleID(userID)}, RoleIDs: []discord.RoleID{discord.RoleID(userID)},

View File

@ -10,7 +10,7 @@ type ErrParse struct {
} }
func Parse(line string) ([]string, error) { func Parse(line string) ([]string, error) {
args := []string{} var args []string
buf := "" buf := ""
var escaped, doubleQuoted, singleQuoted bool var escaped, doubleQuoted, singleQuoted bool
backtick := "" backtick := ""

View File

@ -4,29 +4,21 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/diamondburned/arikawa/api"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/diamondburned/arikawa/gateway"
) )
var ( var (
typeMessageCreate = reflect.TypeOf((*gateway.MessageCreateEvent)(nil)) typeMessageCreate = reflect.TypeOf((*gateway.MessageCreateEvent)(nil))
typeMessageUpdate = reflect.TypeOf((*gateway.MessageUpdateEvent)(nil)) typeMessageUpdate = reflect.TypeOf((*gateway.MessageUpdateEvent)(nil))
typeString = reflect.TypeOf("")
typeEmbed = reflect.TypeOf((*discord.Embed)(nil))
typeSend = reflect.TypeOf((*api.SendMessageData)(nil))
typeSubcmd = reflect.TypeOf((*Subcommand)(nil))
typeIError = reflect.TypeOf((*error)(nil)).Elem() typeIError = reflect.TypeOf((*error)(nil)).Elem()
typeIManP = reflect.TypeOf((*ManualParser)(nil)).Elem() typeIManP = reflect.TypeOf((*ManualParser)(nil)).Elem()
typeICusP = reflect.TypeOf((*CustomParser)(nil)).Elem() typeICusP = reflect.TypeOf((*CustomParser)(nil)).Elem()
typeIParser = reflect.TypeOf((*Parser)(nil)).Elem() typeIParser = reflect.TypeOf((*Parser)(nil)).Elem()
typeIUsager = reflect.TypeOf((*Usager)(nil)).Elem() typeIUsager = reflect.TypeOf((*Usager)(nil)).Elem()
typeSetupFn = methodType((*CanSetup)(nil), "Setup") typeSetupFn = methodType((*CanSetup)(nil), "Setup")
typeHelpFn = methodType((*CanHelp)(nil), "Help")
) )
func methodType(iface interface{}, name string) reflect.Type { func methodType(iface interface{}, name string) reflect.Type {

View File

@ -64,8 +64,8 @@ type UserFlags uint32
const NoFlag UserFlags = 0 const NoFlag UserFlags = 0
const ( const (
DiscordEmployee UserFlags = 1 << iota Employee UserFlags = 1 << iota
DiscordPartner Partner
HypeSquadEvents HypeSquadEvents
BugHunterLvl1 BugHunterLvl1
_ _

View File

@ -36,16 +36,16 @@ var (
ErrWSMaxTries = errors.New("max tries reached") ErrWSMaxTries = errors.New("max tries reached")
) )
// GatewayBotData contains the GatewayURL as well as extra metadata on how to // BotData contains the GatewayURL as well as extra metadata on how to
// shard bots. // shard bots.
type GatewayBotData struct { type BotData struct {
URL string `json:"url"` URL string `json:"url"`
Shards int `json:"shards,omitempty"` Shards int `json:"shards,omitempty"`
StartLimit *SessionStartLimit `json:"session_start_limit"` StartLimit *SessionStartLimit `json:"session_start_limit"`
} }
// SessionStartLimit is the information on the current session start limit. It's // SessionStartLimit is the information on the current session start limit. It's
// used in GatewayBotData. // used in BotData.
type SessionStartLimit struct { type SessionStartLimit struct {
Total int `json:"total"` Total int `json:"total"`
Remaining int `json:"remaining"` Remaining int `json:"remaining"`
@ -54,7 +54,7 @@ type SessionStartLimit struct {
// URL asks Discord for a Websocket URL to the Gateway. // URL asks Discord for a Websocket URL to the Gateway.
func URL() (string, error) { func URL() (string, error) {
var g GatewayBotData var g BotData
return g.URL, httputil.NewClient().RequestJSON( return g.URL, httputil.NewClient().RequestJSON(
&g, "GET", &g, "GET",
@ -64,8 +64,8 @@ func URL() (string, error) {
// BotURL fetches the Gateway URL along with extra metadata. The token // BotURL fetches the Gateway URL along with extra metadata. The token
// passed in will NOT be prefixed with Bot. // passed in will NOT be prefixed with Bot.
func BotURL(token string) (*GatewayBotData, error) { func BotURL(token string) (*BotData, error) {
var g *GatewayBotData var g *BotData
return g, httputil.NewClient().RequestJSON( return g, httputil.NewClient().RequestJSON(
&g, "GET", &g, "GET",
@ -214,7 +214,7 @@ func (g *Gateway) Reconnect() {
// ReconnectCtx attempts to reconnect until context expires. If context cannot // ReconnectCtx attempts to reconnect until context expires. If context cannot
// expire, then the gateway will try to reconnect forever. // expire, then the gateway will try to reconnect forever.
func (g *Gateway) ReconnectCtx(ctx context.Context) error { func (g *Gateway) ReconnectCtx(ctx context.Context) (err error) {
wsutil.WSDebug("Reconnecting...") wsutil.WSDebug("Reconnecting...")
// Guarantee the gateway is already closed. Ignore its error, as we're // Guarantee the gateway is already closed. Ignore its error, as we're
@ -222,18 +222,27 @@ func (g *Gateway) ReconnectCtx(ctx context.Context) error {
g.Close() g.Close()
for i := 1; ; i++ { for i := 1; ; i++ {
select {
case <-ctx.Done():
return err
default:
}
wsutil.WSDebug("Trying to dial, attempt", i) wsutil.WSDebug("Trying to dial, attempt", i)
// Condition: err == ErrInvalidSession: // Condition: err == ErrInvalidSession:
// If the connection is rate limited (documented behavior): // If the connection is rate limited (documented behavior):
// https://discordapp.com/developers/docs/topics/gateway#rate-limiting // https://discordapp.com/developers/docs/topics/gateway#rate-limiting
if err := g.OpenContext(ctx); err != nil { // make sure we don't overwrite our last error
return errors.Wrap(err, "failed to open gateway") if err = g.OpenContext(ctx); err != nil {
g.ErrorLog(err)
continue
} }
wsutil.WSDebug("Started after attempt:", i) wsutil.WSDebug("Started after attempt:", i)
return nil
return
} }
} }
@ -246,7 +255,7 @@ func (g *Gateway) Open() error {
return g.OpenContext(ctx) return g.OpenContext(ctx)
} }
// OpenContext connects to the Websocket and authenticates it. Yuo should // OpenContext connects to the Websocket and authenticates it. You should
// usually use this function over Start(). The given context provides // usually use this function over Start(). The given context provides
// cancellation and timeout. // cancellation and timeout.
func (g *Gateway) OpenContext(ctx context.Context) error { func (g *Gateway) OpenContext(ctx context.Context) error {

View File

@ -84,7 +84,7 @@ func (g *Gateway) HandleOP(op *wsutil.OP) error {
fn, ok := EventCreator[op.EventName] fn, ok := EventCreator[op.EventName]
if !ok { if !ok {
return fmt.Errorf( return fmt.Errorf(
"Unknown event %s: %s", "unknown event %s: %s",
op.EventName, string(op.Data), op.EventName, string(op.Data),
) )
} }

View File

@ -41,7 +41,7 @@ type UserSettings struct {
DeveloperMode bool `json:"developer_mode"` DeveloperMode bool `json:"developer_mode"`
DetectPlatformAccounts bool `json:"detect_platform_accounts"` DetectPlatformAccounts bool `json:"detect_platform_accounts"`
StreamNotification bool `json:"stream_notification_enabled"` StreamNotification bool `json:"stream_notification_enabled"`
AccessibilityDetection bool `json:"allow_accessbility_detection"` AccessibilityDetection bool `json:"allow_accessibility_detection"`
ContactSync bool `json:"contact_sync_enabled"` ContactSync bool `json:"contact_sync_enabled"`
NativePhoneIntegration bool `json:"native_phone_integration_enabled"` NativePhoneIntegration bool `json:"native_phone_integration_enabled"`
@ -71,10 +71,10 @@ type UserSettings struct {
type UserGuildSettings struct { type UserGuildSettings struct {
GuildID discord.GuildID `json:"guild_id"` GuildID discord.GuildID `json:"guild_id"`
SupressEveryone bool `json:"suppress_everyone"` SuppressEveryone bool `json:"suppress_everyone"`
SupressRoles bool `json:"suppress_roles"` SuppressRoles bool `json:"suppress_roles"`
Muted bool `json:"muted"` Muted bool `json:"muted"`
MobilePush bool `json:"mobile_push"` MobilePush bool `json:"mobile_push"`
MessageNotifications UserNotification `json:"message_notifications"` MessageNotifications UserNotification `json:"message_notifications"`
ChannelOverrides []SettingsChannelOverride `json:"channel_overrides"` ChannelOverrides []SettingsChannelOverride `json:"channel_overrides"`

View File

@ -83,7 +83,7 @@ type State struct {
// List of channels with few messages, so it doesn't bother hitting the API // List of channels with few messages, so it doesn't bother hitting the API
// again. // again.
fewMessages map[discord.ChannelID]struct{} fewMessages map[discord.ChannelID]struct{}
fewMutex sync.Mutex fewMutex *sync.Mutex
// unavailableGuilds is a set of discord.GuildIDs of guilds that became // unavailableGuilds is a set of discord.GuildIDs of guilds that became
// unavailable when already connected to the gateway, i.e. sent in a // unavailable when already connected to the gateway, i.e. sent in a
@ -129,7 +129,7 @@ func NewFromSession(s *session.Session, store Store) (*State, error) {
Handler: handler.New(), Handler: handler.New(),
StateLog: func(err error) {}, StateLog: func(err error) {},
fewMessages: map[discord.ChannelID]struct{}{}, fewMessages: map[discord.ChannelID]struct{}{},
fewMutex: sync.Mutex{}, fewMutex: new(sync.Mutex),
unavailableGuilds: moreatomic.NewGuildIDSet(), unavailableGuilds: moreatomic.NewGuildIDSet(),
unreadyGuilds: moreatomic.NewGuildIDSet(), unreadyGuilds: moreatomic.NewGuildIDSet(),
} }

View File

@ -180,7 +180,7 @@ func (s *State) onEvent(iface interface{}) {
case *gateway.MessageDeleteBulkEvent: case *gateway.MessageDeleteBulkEvent:
for _, id := range ev.IDs { for _, id := range ev.IDs {
if err := s.Store.MessageRemove(ev.ChannelID, id); err != nil { if err := s.Store.MessageRemove(ev.ChannelID, id); err != nil {
s.stateErr(err, "failed to delete bulk meessages in state") s.stateErr(err, "failed to delete bulk messages in state")
} }
} }

View File

@ -158,9 +158,9 @@ func (c *Conn) readLoop() {
} }
func (c *Conn) writeLoop() { func (c *Conn) writeLoop() {
// Closig c.writes would break the loop immediately. // Closing c.writes would break the loop immediately.
for bytes := range c.writes { for b := range c.writes {
c.errors <- c.Conn.WriteMessage(websocket.TextMessage, bytes) c.errors <- c.Conn.WriteMessage(websocket.TextMessage, b)
} }
// Quick deadline: // Quick deadline:

View File

@ -54,7 +54,7 @@ func AssertEvent(ev Event, code OPCode, v interface{}) (*OP, error) {
if op.Code != code { if op.Code != code {
return op, fmt.Errorf( return op, fmt.Errorf(
"Unexpected OP Code: %d, expected %d (%s)", "unexpected OP Code: %d, expected %d (%s)",
op.Code, code, op.Data, op.Code, code, op.Data,
) )
} }

View File

@ -27,7 +27,7 @@ from the **Discord Gateway**.
which will be used to create a new `*heart.PacemakerLoop` and start sending heartbeats to the **Discord Voice Gateway**. which will be used to create a new `*heart.PacemakerLoop` and start sending heartbeats to the **Discord Voice Gateway**.
* Afterwards, an [Identify Command](https://discordapp.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload) * Afterwards, an [Identify Command](https://discordapp.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload)
or [Resume Command](https://discordapp.com/developers/docs/topics/voice-connections#resuming-voice-connection-example-resume-connection-payload) or [Resume Command](https://discordapp.com/developers/docs/topics/voice-connections#resuming-voice-connection-example-resume-connection-payload)
is sent to the **Discord Voice Gateway** depending on whether or not the **library** is reconnecting. is sent to the **Discord Voice Gateway** depending on whether the **library** is reconnecting.
--- ---