mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-11-15 00:25:56 +00:00
Bot: Added automatic Intents detection from handlers
This commit adds automatic Intents detection into package bot. When the Start function is used, the intents will be OR'd after running the options callback. This commit also breaks the old "AddIntent" methods to rename them to "AddIntents" for correctness.
This commit is contained in:
parent
ef48d686cd
commit
9899f6073b
|
|
@ -2,8 +2,24 @@ package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/diamondburned/arikawa/v2/gateway"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// eventIntents maps event pointer types to intents.
|
||||||
|
var eventIntents = map[reflect.Type]gateway.Intents{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for event, intent := range gateway.EventIntents {
|
||||||
|
fn, ok := gateway.EventCreator[event]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
eventIntents[reflect.TypeOf(fn())] = intent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type command struct {
|
type command struct {
|
||||||
value reflect.Value // Func
|
value reflect.Value // Func
|
||||||
event reflect.Type
|
event reflect.Type
|
||||||
|
|
@ -26,6 +42,15 @@ func (c *command) call(arg0 interface{}, argv ...reflect.Value) (interface{}, er
|
||||||
return callWith(c.value, arg0, argv...)
|
return callWith(c.value, arg0, argv...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intents returns the command's intents from the event.
|
||||||
|
func (c *command) intents() gateway.Intents {
|
||||||
|
intents, ok := eventIntents[c.event]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return intents
|
||||||
|
}
|
||||||
|
|
||||||
func callWith(caller reflect.Value, arg0 interface{}, argv ...reflect.Value) (interface{}, error) {
|
func callWith(caller reflect.Value, arg0 interface{}, argv ...reflect.Value) (interface{}, error) {
|
||||||
var callargs = make([]reflect.Value, 0, 1+len(argv))
|
var callargs = make([]reflect.Value, 0, 1+len(argv))
|
||||||
|
|
||||||
|
|
|
||||||
18
bot/ctx.go
18
bot/ctx.go
|
|
@ -165,6 +165,8 @@ func Start(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.Gateway.AddIntents(c.DeriveIntents())
|
||||||
|
|
||||||
cancel := c.Start()
|
cancel := c.Start()
|
||||||
|
|
||||||
if err := s.Open(); err != nil {
|
if err := s.Open(); err != nil {
|
||||||
|
|
@ -229,10 +231,10 @@ func New(s *state.State, cmd interface{}) (*Context, error) {
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddIntent adds the given Gateway Intent into the Gateway. This is a
|
// AddIntents adds the given Gateway Intent into the Gateway. This is a
|
||||||
// convenient function that calls Gateway's AddIntent.
|
// convenient function that calls Gateway's AddIntent.
|
||||||
func (ctx *Context) AddIntent(i gateway.Intents) {
|
func (ctx *Context) AddIntents(i gateway.Intents) {
|
||||||
ctx.Gateway.AddIntent(i)
|
ctx.Gateway.AddIntents(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subcommands returns the slice of subcommands. To add subcommands, use
|
// Subcommands returns the slice of subcommands. To add subcommands, use
|
||||||
|
|
@ -444,3 +446,13 @@ func IndentLines(input string) string {
|
||||||
}
|
}
|
||||||
return strings.Join(lines, "\n")
|
return strings.Join(lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeriveIntents derives all possible gateway intents from this context and all
|
||||||
|
// its subcommands' method handlers and middlewares.
|
||||||
|
func (ctx *Context) DeriveIntents() gateway.Intents {
|
||||||
|
var intents = ctx.Subcommand.DeriveIntents()
|
||||||
|
for _, subcmd := range ctx.subcommands {
|
||||||
|
intents |= subcmd.DeriveIntents()
|
||||||
|
}
|
||||||
|
return intents
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,21 @@ func TestContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("derive intents", func(t *testing.T) {
|
||||||
|
intents := ctx.DeriveIntents()
|
||||||
|
|
||||||
|
assertIntents := func(target gateway.Intents, name string) {
|
||||||
|
if !intents.Has(target) {
|
||||||
|
t.Error("Derived intents do not have", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertIntents(gateway.IntentGuildMessages, "guild messages")
|
||||||
|
assertIntents(gateway.IntentDirectMessages, "direct messages")
|
||||||
|
assertIntents(gateway.IntentGuildMessageTyping, "guild typing")
|
||||||
|
assertIntents(gateway.IntentDirectMessageTyping, "direct message typing")
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("typing event", func(t *testing.T) {
|
t.Run("typing event", func(t *testing.T) {
|
||||||
typing := &gateway.TypingStartEvent{}
|
typing := &gateway.TypingStartEvent{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,10 @@ func (sub *Subcommand) NeedsName() {
|
||||||
sub.Command = lowerFirstLetter(sub.StructName)
|
sub.Command = lowerFirstLetter(sub.StructName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lowerFirstLetter(name string) string {
|
||||||
|
return strings.ToLower(string(name[0])) + name[1:]
|
||||||
|
}
|
||||||
|
|
||||||
// FindCommand finds the MethodContext. It panics if methodName is not found.
|
// FindCommand finds the MethodContext. It panics if methodName is not found.
|
||||||
func (sub *Subcommand) FindCommand(methodName string) *MethodContext {
|
func (sub *Subcommand) FindCommand(methodName string) *MethodContext {
|
||||||
for _, c := range sub.Commands {
|
for _, c := range sub.Commands {
|
||||||
|
|
@ -413,6 +417,23 @@ func (sub *Subcommand) AddAliases(commandName string, aliases ...string) {
|
||||||
command.Aliases = append(command.Aliases, aliases...)
|
command.Aliases = append(command.Aliases, aliases...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lowerFirstLetter(name string) string {
|
// DeriveIntents derives all possible gateway intents from the method handlers
|
||||||
return strings.ToLower(string(name[0])) + name[1:]
|
// and middlewares.
|
||||||
|
func (sub *Subcommand) DeriveIntents() gateway.Intents {
|
||||||
|
var intents gateway.Intents
|
||||||
|
|
||||||
|
for _, event := range sub.Events {
|
||||||
|
intents |= event.intents()
|
||||||
|
}
|
||||||
|
for _, command := range sub.Commands {
|
||||||
|
intents |= command.intents()
|
||||||
|
}
|
||||||
|
if sub.plumbed != nil {
|
||||||
|
intents |= sub.plumbed.intents()
|
||||||
|
}
|
||||||
|
for _, middleware := range sub.globalmws {
|
||||||
|
intents |= middleware.intents()
|
||||||
|
}
|
||||||
|
|
||||||
|
return intents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func NewGatewayWithIntents(token string, intents ...Intents) (*Gateway, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, intent := range intents {
|
for _, intent := range intents {
|
||||||
g.AddIntent(intent)
|
g.AddIntents(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
return g, nil
|
return g, nil
|
||||||
|
|
@ -154,9 +154,9 @@ func NewCustomGateway(gatewayURL, token string) *Gateway {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddIntent adds a Gateway Intent before connecting to the Gateway. As
|
// AddIntents adds a Gateway Intent before connecting to the Gateway. As such,
|
||||||
// such, this function will only work before Open() is called.
|
// this function will only work before Open() is called.
|
||||||
func (g *Gateway) AddIntent(i Intents) {
|
func (g *Gateway) AddIntents(i Intents) {
|
||||||
g.Identifier.Intents |= i
|
g.Identifier.Intents |= i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package gateway
|
package gateway
|
||||||
|
|
||||||
|
import "github.com/diamondburned/arikawa/v2/discord"
|
||||||
|
|
||||||
// Intents for the new Discord API feature, documented at
|
// Intents for the new Discord API feature, documented at
|
||||||
// https://discordapp.com/developers/docs/topics/gateway#gateway-intents.
|
// https://discordapp.com/developers/docs/topics/gateway#gateway-intents.
|
||||||
type Intents uint32
|
type Intents uint32
|
||||||
|
|
@ -28,3 +30,15 @@ var PrivilegedIntents = []Intents{
|
||||||
IntentGuildPresences,
|
IntentGuildPresences,
|
||||||
IntentGuildMembers,
|
IntentGuildMembers,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has returns true if i has the given intents.
|
||||||
|
func (i Intents) Has(intents Intents) bool {
|
||||||
|
return discord.HasFlag(uint64(i), uint64(intents))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrivileged returns true for each of the boolean that indicates the type of
|
||||||
|
// the privilege.
|
||||||
|
func (i Intents) IsPrivileged() (presences, member bool) {
|
||||||
|
// Keep this in sync with PrivilegedIntents.
|
||||||
|
return i.Has(IntentGuildPresences), i.Has(IntentGuildMembers)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue