diff --git a/README.md b/README.md index 00c3b18..9cbb5e0 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ Every struct uses [fieldalignment](https://pkg.go.dev/golang.org/x/tools/go/anal ### Storage -Disgo adds **6.5 MB** to a compiled binary. +Disgo adds **5 MB** to a compiled binary. ### Contributing diff --git a/_contribution/CONTRIBUTING.md b/_contribution/CONTRIBUTING.md index 013b73d..a3df449 100644 --- a/_contribution/CONTRIBUTING.md +++ b/_contribution/CONTRIBUTING.md @@ -25,7 +25,7 @@ The repository contains a [README](/README.md), [Examples](/_examples/), [Code G | shard | Sharding Manager. | | tools | Utility Tools. | -_A [bundler](https://pkg.go.dev/golang.org/x/tools/cmd/bundle) is used to package the API into a `disgo` package (`disgo.go`)_. +_A **bundler** is used to package the API into a `disgo` package (`disgo.go`)_. #### Structs @@ -52,9 +52,7 @@ Comments follow [Effective Go](https://golang.org/doc/effective_go#commentary) a #### Static Code Analysis -Disgo uses [golangci-lint](https://github.com/golangci/golangci-lint) in order to statically analyze code. You can install golangci-lint with `go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2`. If you receive a `diff` error _(while running)_, you must add a `diff` tool in your PATH. There is one located in the `Git` bin. - -If you receive `File is not ... with -...`, use `golangci-lint run --disable-all --no-config -Egofmt --fix`. +Disgo uses [golangci-lint](https://github.com/golangci/golangci-lint) in order to statically analyze code. You can install golangci-lint with `go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2`. If you receive a `diff` error _(while running)_, you must add a `diff` tool in your PATH. There is one located in the `Git/bin` directory. | Directory | Command | Description | | :-------- | :---------------------------- | :------------------------------------------------- | @@ -64,6 +62,8 @@ If you receive `File is not ... with -...`, use `golangci-lint run --disable-all | `shard` | `golangci-lint run ./shard` | Perform static code analysis on the Shard Manager. | | `tools` | `golangci-lint run ./tools` | Perform static code analysis on the Tools Module. | + _If you receive `File is not ... with -...`, use `golangci-lint run --disable-all --no-config -Egofmt --fix` or ignore it._ + #### Fieldalignment Disgo [fieldaligns](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment) bundled code to save memory. @@ -80,15 +80,11 @@ Integration tests are used to ensure functionality between the API Wrapper and D #### Running Tests -Use `go test` to run the tests in the current directory. Use `go test ./` to run tests in a given directory (from the current directory). Use [Github Action Workflow Files](/.github/workflows/) to find the correct test command for a module. +Use `go test` to run the tests in the current directory. Use `go test ./` to run tests in a given directory (from the current directory). Use [Github Action Workflow Files](/.github/workflows/) to find the correct test command and environment variables for a module. # Roadmap -Disgo is **STABLE**. Here are the steps required in order to complete it. - -1. Bundle Disgo (with `fieldalignment`) _[v10.0.0]_. - -The following additional features are being implemented. +Disgo is **STABLE**. The following additional features are being implemented. 1. Voice Connections ([UDP Decision](/_contribution/libraries/), [Audio Processing using Opus](https://discord.com/developers/docs/topics/voice-connections#encrypting-and-sending-voice)) 2. [Sharding](https://github.com/switchupcb/disgo/issues/26) diff --git a/_examples/command/autocomplete/main.go b/_examples/command/autocomplete/main.go index d0c7ad4..d194a26 100644 --- a/_examples/command/autocomplete/main.go +++ b/_examples/command/autocomplete/main.go @@ -6,8 +6,8 @@ import ( "os" "strings" + "github.com/switchupcb/disgo" tools "github.com/switchupcb/disgo/tools" - disgo "github.com/switchupcb/disgo/wrapper" ) // Environment Variables diff --git a/_examples/command/followup/main.go b/_examples/command/followup/main.go index ba139b0..019966d 100644 --- a/_examples/command/followup/main.go +++ b/_examples/command/followup/main.go @@ -6,8 +6,8 @@ import ( "os" "time" + "github.com/switchupcb/disgo" "github.com/switchupcb/disgo/tools" - disgo "github.com/switchupcb/disgo/wrapper" ) // Environment Variables diff --git a/_examples/command/localization/main.go b/_examples/command/localization/main.go index a062050..d6fcceb 100644 --- a/_examples/command/localization/main.go +++ b/_examples/command/localization/main.go @@ -5,8 +5,8 @@ import ( "log" "os" + "github.com/switchupcb/disgo" "github.com/switchupcb/disgo/tools" - disgo "github.com/switchupcb/disgo/wrapper" ) // Environment Variables diff --git a/_examples/command/main.go b/_examples/command/main.go index d85edd7..751599b 100644 --- a/_examples/command/main.go +++ b/_examples/command/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "syscall" - disgo "github.com/switchupcb/disgo/wrapper" + "github.com/switchupcb/disgo" ) // Environment Variables diff --git a/_examples/command/subcommand/main.go b/_examples/command/subcommand/main.go index f0c0aa0..a7f09f0 100644 --- a/_examples/command/subcommand/main.go +++ b/_examples/command/subcommand/main.go @@ -8,8 +8,8 @@ import ( "strconv" "syscall" + "github.com/switchupcb/disgo" "github.com/switchupcb/disgo/tools" - disgo "github.com/switchupcb/disgo/wrapper" ) // Environment Variables diff --git a/_examples/go.mod b/_examples/go.mod index 66bb160..6624201 100644 --- a/_examples/go.mod +++ b/_examples/go.mod @@ -9,11 +9,11 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect - github.com/goccy/go-json v0.9.11 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/gorilla/schema v1.2.0 // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/compress v1.15.12 // indirect github.com/switchupcb/websocket v1.8.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.41.0 // indirect + github.com/valyala/fasthttp v1.43.0 // indirect golang.org/x/sync v0.1.0 // indirect ) diff --git a/_examples/go.sum b/_examples/go.sum index d53df6a..630d498 100644 --- a/_examples/go.sum +++ b/_examples/go.sum @@ -6,8 +6,7 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= @@ -17,8 +16,8 @@ github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlI github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= github.com/switchupcb/disgo v0.0.0-20220726210903-501dcb40b012 h1:8K0Cs/qWX0p21TH6WYeb9ihYT+nLzabfsGyfm/g/Xv4= github.com/switchupcb/disgo v0.0.0-20220726210903-501dcb40b012/go.mod h1:Wl43EK7HOIj+qYkKGY7bfmhHcs4kOamgHeMk8ZujROQ= github.com/switchupcb/disgo/tools v0.0.0-20220727073006-e0f01397d626 h1:M9XQfGcnMXzlAXWFzxTLnwY65Y0K4VD4LlsyPt55MSQ= @@ -27,8 +26,7 @@ github.com/switchupcb/websocket v1.8.8 h1:0x7RIs90NJ8YggqcLdKeb/LTofJ1BY79n784pk github.com/switchupcb/websocket v1.8.8/go.mod h1:HdhyzCLfOFPrBv+QNcnDSbv8L8rfJ7ZCulrBKZJHip0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= -github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/fasthttp v1.43.0 h1:Gy4sb32C98fbzVWZlTM1oTMdLWGyvxR03VhM6cBIU4g= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= diff --git a/_examples/image/avatar/main.go b/_examples/image/avatar/main.go index aa6bbf1..14c34f9 100644 --- a/_examples/image/avatar/main.go +++ b/_examples/image/avatar/main.go @@ -8,8 +8,8 @@ import ( "net/http" "os" + "github.com/switchupcb/disgo" "github.com/switchupcb/disgo/tools" - disgo "github.com/switchupcb/disgo/wrapper" ) // Environment Variables diff --git a/_examples/message/send/file.go b/_examples/message/send/file.go index 20b13dc..d969cbc 100644 --- a/_examples/message/send/file.go +++ b/_examples/message/send/file.go @@ -7,7 +7,7 @@ import ( "os" "path" - disgo "github.com/switchupcb/disgo/wrapper" + "github.com/switchupcb/disgo" ) // getFile returns a disgo.File for usage in a message. diff --git a/_examples/message/send/main.go b/_examples/message/send/main.go index f5f78d8..0d99a66 100644 --- a/_examples/message/send/main.go +++ b/_examples/message/send/main.go @@ -5,7 +5,7 @@ import ( "log" "os" - disgo "github.com/switchupcb/disgo/wrapper" + "github.com/switchupcb/disgo" ) // Environment Variables diff --git a/_gen/README.md b/_gen/README.md index fcd4327..3e6265e 100644 --- a/_gen/README.md +++ b/_gen/README.md @@ -4,7 +4,19 @@ Disgo uses generators to easily update and maintain over 10,000 lines of code. ## Build -Use `go build -o gen` to build the executable file for the generator. This may require you to set the `GOWORK` environment variable to `off`. +Use `go build -o gen` from the [`./_gen`](/_gen) directory to build the executable file for the generator. This may require you to set the `GOWORK` environment variable to `off`. + +### Dependencies + +_The following dependencies are used to download and unzip the latest version of [`dasgo`](https://github.com/switchupcb/dasgo) to `./gen/input/dasgo-10` (git-ignored)._ + +- [curl](https://curl.se/): [download](https://curl.se/download.html) +- [`unzip`](https://linux.die.net/man/1/unzip) + +_The following dependencies are used during code generation._ + +- [`xstruct`](/tools/xstruct.exe) +- [copygen](https://github.com/switchupcb/copygen): `go install github.com/switchupcb/copygen@latest` ## Dasgo @@ -21,9 +33,20 @@ Disgo sources Discord API objects from [dasgo](https://github.com/switchupcb/das Disgo generates code for features using [copygen](https://github.com/switchupcb/copygen). **This requires corresponding `setup.go` files to be updated.** Use the `diff` from Git to update those files accordingly. -| Step | Description | -| :----------- | :----------------------------------------------------------------- | -| `send.go` | Uses copygen to generate request `Send()` functions. | -| `handle.go` | Uses copygen to generate request **event handling** functionality. | -| `command.go` | Uses copygen to generate request `Command()` functions. | -| Clean | Cleans the generated code. | \ No newline at end of file +| Step | Description | +| :------------- | :----------------------------------------------------------------- | +| `send.go` | Uses copygen to generate request `Send()` functions. | +| `handle.go` | Uses copygen to generate request **event handling** functionality. | +| `sendevent.go` | Uses copygen to generate request `SendEvent()` functions. | +| Clean | Cleans the generated code. | + +# Bundle + +## Build + +A bundler is used to package the API Wrapper into the `disgo` package (`disgo.go`). Use `go build` from the [`./_gen/bundle`](/_gen/bundle) directory to build the executable file for the bundler. This may require you to set the `GOWORK` environment variable to `off`. + +### Dependencies + +- [bundle](https://pkg.go.dev/golang.org/x/tools/cmd/bundle): `go install golang.org/x/tools/cmd/bundle@latest` +- [fieldalignment](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment): `go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest` \ No newline at end of file diff --git a/_gen/bundle/main.go b/_gen/bundle/main.go new file mode 100644 index 0000000..044f622 --- /dev/null +++ b/_gen/bundle/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "flag" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/switchupcb/disgo/_gen/bundle/tools" +) + +var ( + showFieldaligned = flag.Bool("f", false, "Use -f to showcase the output from the fieldalignment tool.") +) + +const ( + exeDir = "_gen/bundle" + bundlePath = "disgo.go" + pkg = "package disgo" + filemodewrite = 0644 +) + +func main() { + if err := check(); err != nil { + fmt.Printf("%v", err) + os.Exit(1) + } + + flag.Parse() + + // disgo generation + if err := generate(); err != nil { + fmt.Printf("%v", err) + os.Exit(1) + } +} + +// check checks that the current working directory is `disgo/_gen/bundle`. +func check() error { + cwd, err := os.Getwd() + if err != nil { + return fmt.Errorf("error getting the current working directory: %w", err) + } + + cwdDir := filepath.Dir(cwd) + base := filepath.Base(cwdDir) + "/" + filepath.Base(cwd) + if base != exeDir && filepath.Base(filepath.Dir(cwdDir)) != "disgo" { + return fmt.Errorf("This executable must be run from disgo/" + exeDir) + } + + return nil +} + +// generate generates the disgo bundle. +func generate() error { + if err := os.Chdir("../../"); err != nil { + return fmt.Errorf("chdir: %w", err) + } + + // clear the bundled file. + bundle := `//go:generate bundle -o disgo.go -dst . -pkg disgo -prefix "" ./wrapper` + cleared := strings.Join([]string{bundle, pkg}, "\n") + if err := os.WriteFile(bundlePath, []byte(cleared), filemodewrite); err != nil { + return fmt.Errorf("clear: %w", err) + } + + bundlegen := exec.Command("go", "generate") + std, err := bundlegen.CombinedOutput() + if err != nil { + return fmt.Errorf("bundle (go generate): %v", string(std)) + } + + // fix the imports of the bundle. + if err := tools.Imports(bundlePath); err != nil { + return fmt.Errorf("imports: %w", err) + } + + // fieldalign the bundle (until there is nothing else to fieldalign). + var fieldalignmentOutput []byte + for i := 0; i < 5; i++ { + fieldalignment := exec.Command("fieldalignment", "-fix", bundlePath) + std, err = fieldalignment.CombinedOutput() + if err != nil && err.Error() == "exit status 3" { + fieldalignmentOutput = append(fieldalignmentOutput, std...) + fmt.Printf("WARNING (fieldalignment): %v\n", err) + fmt.Println("running fieldalignment again...\n") + + continue + + } else if err != nil { + return fmt.Errorf("fieldalignment: %v", err) + } + + fieldalignmentOutput = append(fieldalignmentOutput, std...) + + if i == 4 { + return fmt.Errorf("fieldalignment: more calls to fieldalignment were required.") + } + + break + } + + if *showFieldaligned { + fmt.Println(string(fieldalignmentOutput)) + } + + // add removed comments to the bundle. + if err := tools.Replace(bundlePath); err != nil { + return fmt.Errorf("replace: %w", err) + } + + return nil +} diff --git a/_gen/bundle/tools/imports.go b/_gen/bundle/tools/imports.go new file mode 100644 index 0000000..5dfbb4f --- /dev/null +++ b/_gen/bundle/tools/imports.go @@ -0,0 +1,50 @@ +package tools + +import ( + "fmt" + "go/format" + "os" + "strings" +) + +const ( + filemodewrite = 0644 +) + +var ( + // skip represents a set of imports to remove. + skip = map[string]bool{ + `"encoding/json"`: true, + } +) + +// Imports fixes the imports of the bundler. +func Imports(filepath string) error { + data, err := os.ReadFile(filepath) + if err != nil { + return fmt.Errorf("error reading generated %v file: %w", filepath, err) + } + + var output []byte + + content := string(data) + for _, line := range strings.Split(content, "\n") { + if skip[strings.TrimSpace(line)] { + continue + } + + output = append(output, []byte(line+"\n")...) + } + + // gofmt + fmtdata, err := format.Source(output) + if err != nil { + return fmt.Errorf("error formatting generated code: %w", err) + } + + if err = os.WriteFile(filepath, fmtdata, filemodewrite); err != nil { + return fmt.Errorf("error writing file: %w", err) + } + + return nil +} diff --git a/_gen/bundle/tools/replace.go b/_gen/bundle/tools/replace.go new file mode 100644 index 0000000..ab60b7d --- /dev/null +++ b/_gen/bundle/tools/replace.go @@ -0,0 +1,123 @@ +package tools + +import ( + "fmt" + "go/format" + "io/ioutil" + "os" + "path" + "strings" +) + +const ( + replacedDir = "_gen/bundle/tools/replaced" + boundary = "\n---\n" +) + +var ( + bundleWarning = `// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.` + generateWarning = `//go:generate bundle -o disgo.go -dst . -pkg disgo -prefix "" ./wrapper` + bundlerWarning = []byte(`// Code generated by github.com/switchupcb/disgo/_gen/tools/bundle. DO NOT EDIT.` + "\n") +) + +// Replace replaces fields that have comments removed after being field aligned. +func Replace(filepath string) error { + // replaced represents a map of fieldaligned structs (with comments removed) + // to fieldaligned structs (with comments added back). + replaced, err := initialize(replacedDir, boundary) + if err != nil { + return fmt.Errorf("initialize: %w", err) + } + + // load the bundle's content. + data, err := os.ReadFile(filepath) + if err != nil { + return fmt.Errorf("error reading generated %v file: %w", filepath, err) + } + + // strip the bundle's lines (in order to perform a comparison). + content := strip(data) + + // replace the fieldaligned structs (without comments). + for fieldaligned, fixed := range replaced { + content = strings.Replace(content, fieldaligned, fixed, 1) + } + + content = strings.Replace(content, bundleWarning, "", 1) + content = strings.Replace(content, generateWarning, "", 1) + + // gofmt + contentdata := []byte(content) + fmtdata, err := format.Source(contentdata) + if err != nil { + if err = os.WriteFile(filepath, contentdata, filemodewrite); err != nil { + return fmt.Errorf("error writing file %w", err) + } + + return fmt.Errorf("error formatting generated code: %w", err) + } + + var output []byte + output = append(output, bundlerWarning...) + output = append(output, fmtdata...) + + if err = os.WriteFile(filepath, output, filemodewrite); err != nil { + return fmt.Errorf("error writing file %w", err) + } + + return nil +} + +// initialize initializes the replaced map by reading the files in the given directory. +// +// A boundary is used to determine the key and field. +func initialize(dir, boundary string) (map[string]string, error) { + files, err := ioutil.ReadDir(dir) + if err != nil { + return nil, fmt.Errorf("%w", err) + } + + output := make(map[string]string, len(files)) + for _, file := range files { + filepath := path.Join(dir, file.Name()) + data, err := os.ReadFile(filepath) + if err != nil { + return nil, fmt.Errorf("error reading replaced %v file: %w", filepath, err) + } + + // strip the file's lines (in order to perform a comparison). + content := strip(data) + + fields := strings.Split(content, boundary) + output[fields[0]] = fields[1] + } + + return output, nil +} + +var ( + newline = byte('\n') +) + +// strip strips the lines of the given data. +func strip(data []byte) string { + var stripped strings.Builder + + var line []byte + for _, b := range data { + if b == newline { + stripped.WriteString(strings.TrimSpace(string(line))) + stripped.WriteByte(newline) + + line = []byte{} + + continue + } + + line = append(line, b) + } + + stripped.WriteString(strings.TrimSpace(string(line))) + + return stripped.String() +} diff --git a/_gen/bundle/tools/replaced/gateway b/_gen/bundle/tools/replaced/gateway new file mode 100644 index 0000000..41657c0 --- /dev/null +++ b/_gen/bundle/tools/replaced/gateway @@ -0,0 +1,32 @@ +type Gateway struct { + RateLimiter RateLimiter + IntentSet map[BitFlag]bool + GatewayPresenceUpdate *GatewayPresenceUpdate + Intents BitFlag +} +--- +type Gateway struct { + // RateLimiter represents an object that provides rate limit functionality. + RateLimiter RateLimiter + + // Intents represents a Discord Gateway Intent. + // + // You must specify a Gateway Intent in order to receive specific information from an event. + // + // https://discord.com/developers/docs/topics/gateway#gateway-intents + IntentSet map[BitFlag]bool + + // GatewayPresenceUpdate represents the presence or status update of a bot. + // + // GatewayPresenceUpdate is used when the bot connects to a session. + // + // https://discord.com/developers/docs/topics/gateway#update-presence + GatewayPresenceUpdate *GatewayPresenceUpdate + + // Intents represents a Discord Gateway Intent. + // + // You must specify a Gateway Intent in order to receive specific information from an event. + // + // https://discord.com/developers/docs/topics/gateway#gateway-intents + Intents BitFlag +} diff --git a/_gen/bundle/tools/replaced/getguildauditlog b/_gen/bundle/tools/replaced/getguildauditlog new file mode 100644 index 0000000..5bb44e5 --- /dev/null +++ b/_gen/bundle/tools/replaced/getguildauditlog @@ -0,0 +1,17 @@ +type GetGuildAuditLog struct { + GuildID string `url:"-"` + UserID string `url:"user_id,omitempty"` + Before string `url:"before,omitempty"` + Limit int `url:"limit,omitempty"` + ActionType Flag `url:"action_type,omitempty"` +} +--- +type GetGuildAuditLog struct { + GuildID string `url:"-"` + + // https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events + UserID string `url:"user_id,omitempty"` + Before string `url:"before,omitempty"` + Limit int `url:"limit,omitempty"` + ActionType Flag `url:"action_type,omitempty"` +} diff --git a/_gen/bundle/tools/replaced/getguildwidgetimage b/_gen/bundle/tools/replaced/getguildwidgetimage new file mode 100644 index 0000000..50f131c --- /dev/null +++ b/_gen/bundle/tools/replaced/getguildwidgetimage @@ -0,0 +1,12 @@ +type GetGuildWidgetImage struct { + Style *string `url:"style,omitempty"` + GuildID string `url:"-"` +} +--- +type GetGuildWidgetImage struct { + // Widget Style Options + // https://discord.com/developers/docs/resources/guild#get-guild-widget-image-widget-style-options + Style *string `url:"style,omitempty"` + + GuildID string `url:"-"` +} diff --git a/_gen/bundle/tools/replaced/guild b/_gen/bundle/tools/replaced/guild new file mode 100644 index 0000000..d5b0897 --- /dev/null +++ b/_gen/bundle/tools/replaced/guild @@ -0,0 +1,93 @@ +type Guild struct { + RulesChannelID *string `json:"rules_channel_id"` + WelcomeScreen *WelcomeScreen `json:"welcome_screen,omitempty"` + Icon *string `json:"icon"` + IconHash **string `json:"icon_hash,omitempty"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Owner *bool `json:"owner,omitempty"` + ApproximatePresenceCount *int `json:"approximate_presence_count,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Region **string `json:"region,omitempty"` + ApproximateMemberCount *int `json:"approximate_member_count,omitempty"` + MaxVideoChannelUsers *int `json:"max_video_channel_users,omitempty"` + WidgetEnabled *bool `json:"widget_enabled,omitempty"` + WidgetChannelID **string `json:"widget_channel_id,omitempty"` + PublicUpdatesChannelID *string `json:"public_updates_channel_id"` + PremiumSubscriptionCount *int `json:"premium_subscription_count,omitempty"` + ApplicationID *string `json:"application_id"` + Banner *string `json:"banner"` + Description *string `json:"description"` + VanityUrl *string `json:"vanity_url_code"` + MaxPresences **int `json:"max_presences,omitempty"` + MaxMembers *int `json:"max_members,omitempty"` + SystemChannelID *string `json:"system_channel_id"` + AfkChannelID *string `json:"afk_channel_id"` + Unavailable *bool `json:"unavailable,omitempty"` + OwnerID string `json:"owner_id"` + ID string `json:"id"` + Name string `json:"name"` + PreferredLocale string `json:"preferred_locale"` + Emojis []*Emoji `json:"emojis"` + Roles []*Role `json:"roles"` + Stickers []*Sticker `json:"stickers,omitempty"` + Features []*string `json:"features"` + AfkTimeout int `json:"afk_timeout"` + SystemChannelFlags BitFlag `json:"system_channel_flags"` + DefaultMessageNotifications Flag `json:"default_message_notifications"` + PremiumTier Flag `json:"premium_tier"` + ExplicitContentFilter Flag `json:"explicit_content_filter"` + NSFWLevel Flag `json:"nsfw_level"` + MFALevel Flag `json:"mfa_level"` + PremiumProgressBarEnabled bool `json:"premium_progress_bar_enabled"` + VerificationLevel Flag `json:"verification_level"` +} +--- +type Guild struct { + RulesChannelID *string `json:"rules_channel_id"` + WelcomeScreen *WelcomeScreen `json:"welcome_screen,omitempty"` + Icon *string `json:"icon"` + IconHash **string `json:"icon_hash,omitempty"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Owner *bool `json:"owner,omitempty"` + ApproximatePresenceCount *int `json:"approximate_presence_count,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Region **string `json:"region,omitempty"` + ApproximateMemberCount *int `json:"approximate_member_count,omitempty"` + MaxVideoChannelUsers *int `json:"max_video_channel_users,omitempty"` + WidgetEnabled *bool `json:"widget_enabled,omitempty"` + WidgetChannelID **string `json:"widget_channel_id,omitempty"` + PublicUpdatesChannelID *string `json:"public_updates_channel_id"` + PremiumSubscriptionCount *int `json:"premium_subscription_count,omitempty"` + ApplicationID *string `json:"application_id"` + Banner *string `json:"banner"` + Description *string `json:"description"` + VanityUrl *string `json:"vanity_url_code"` + MaxPresences **int `json:"max_presences,omitempty"` + MaxMembers *int `json:"max_members,omitempty"` + SystemChannelID *string `json:"system_channel_id"` + AfkChannelID *string `json:"afk_channel_id"` + + // Unavailable Guild Object + // https://discord.com/developers/docs/resources/guild#unavailable-guild-object + Unavailable *bool `json:"unavailable,omitempty"` + + OwnerID string `json:"owner_id"` + ID string `json:"id"` + Name string `json:"name"` + PreferredLocale string `json:"preferred_locale"` + Emojis []*Emoji `json:"emojis"` + Roles []*Role `json:"roles"` + Stickers []*Sticker `json:"stickers,omitempty"` + Features []*string `json:"features"` + AfkTimeout int `json:"afk_timeout"` + SystemChannelFlags BitFlag `json:"system_channel_flags"` + DefaultMessageNotifications Flag `json:"default_message_notifications"` + PremiumTier Flag `json:"premium_tier"` + ExplicitContentFilter Flag `json:"explicit_content_filter"` + NSFWLevel Flag `json:"nsfw_level"` + MFALevel Flag `json:"mfa_level"` + PremiumProgressBarEnabled bool `json:"premium_progress_bar_enabled"` + VerificationLevel Flag `json:"verification_level"` +} diff --git a/_gen/bundle/tools/replaced/message b/_gen/bundle/tools/replaced/message new file mode 100644 index 0000000..019176f --- /dev/null +++ b/_gen/bundle/tools/replaced/message @@ -0,0 +1,77 @@ +type Message struct { + Timestamp time.Time `json:"timestamp"` + WebhookID *string `json:"webhook_id,omitempty"` + Author *User `json:"author"` + Position *int `json:"position,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + EditedTimestamp *time.Time `json:"edited_timestamp"` + Thread *Channel `json:"thread"` + Interaction *Interaction `json:"interaction"` + ReferencedMessage **Message `json:"referenced_message,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + ApplicationID *string `json:"application_id,omitempty"` + Application *Application `json:"application,omitempty"` + Activity *MessageActivity `json:"activity,omitempty"` + Nonce *Nonce `json:"nonce,omitempty"` + Member *GuildMember `json:"member,omitempty"` + ChannelID string `json:"channel_id"` + ID string `json:"id"` + Content string `json:"content"` + Stickers []*Sticker `json:"stickers"` + Attachments []*Attachment `json:"attachments"` + MentionChannels []*ChannelMention `json:"mention_channels,omitempty"` + MentionRoles []*string `json:"mention_roles"` + Mentions []*User `json:"mentions"` + Reactions []*Reaction `json:"reactions,omitempty"` + Embeds []*Embed `json:"embeds"` + Components []Component `json:"components"` + StickerItems []*StickerItem `json:"sticker_items"` + MentionEveryone bool `json:"mention_everyone"` + TTS bool `json:"tts"` + Type Flag `json:"type"` + Pinned bool `json:"pinned"` +} +--- +type Message struct { + Timestamp time.Time `json:"timestamp"` + WebhookID *string `json:"webhook_id,omitempty"` + Author *User `json:"author"` + Position *int `json:"position,omitempty"` + + // MessageCreate Event Extra Field + // https://discord.com/developers/docs/topics/gateway-events#message-create + GuildID *string `json:"guild_id,omitempty"` + + EditedTimestamp *time.Time `json:"edited_timestamp"` + Thread *Channel `json:"thread"` + Interaction *Interaction `json:"interaction"` + ReferencedMessage **Message `json:"referenced_message,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + ApplicationID *string `json:"application_id,omitempty"` + Application *Application `json:"application,omitempty"` + Activity *MessageActivity `json:"activity,omitempty"` + Nonce *Nonce `json:"nonce,omitempty"` + + // MessageCreate Event Extra Field + // https://discord.com/developers/docs/topics/gateway-events#message-create + Member *GuildMember `json:"member,omitempty"` + + ChannelID string `json:"channel_id"` + ID string `json:"id"` + Content string `json:"content"` + Stickers []*Sticker `json:"stickers"` + Attachments []*Attachment `json:"attachments"` + MentionChannels []*ChannelMention `json:"mention_channels,omitempty"` + MentionRoles []*string `json:"mention_roles"` + Mentions []*User `json:"mentions"` + Reactions []*Reaction `json:"reactions,omitempty"` + Embeds []*Embed `json:"embeds"` + Components []Component `json:"components"` + StickerItems []*StickerItem `json:"sticker_items"` + MentionEveryone bool `json:"mention_everyone"` + TTS bool `json:"tts"` + Type Flag `json:"type"` + Pinned bool `json:"pinned"` +} diff --git a/_gen/bundle/tools/replaced/session b/_gen/bundle/tools/replaced/session new file mode 100644 index 0000000..6eb9340 --- /dev/null +++ b/_gen/bundle/tools/replaced/session @@ -0,0 +1,41 @@ +type Session struct { + Context context.Context + manager *manager + Conn *websocket.Conn + heartbeat *heartbeat + Endpoint string + ID string + Seq int64 + sync.RWMutex +} +--- +type Session struct { + // Context carries request-scoped data for the Discord Gateway Connection. + // + // Context is also used as a signal for the Session's goroutines. + Context context.Context + + // manager represents a manager of a Session's goroutines. + manager *manager + + // Conn represents a connection to the Discord Gateway. + Conn *websocket.Conn + + // heartbeat contains the fields required to implement the heartbeat mechanism. + heartbeat *heartbeat + + // Endpoint represents the endpoint that is used to reconnect to the Gateway. + Endpoint string + + // ID represents the session ID of the Session. + ID string + + // Seq represents the last sequence number received by the client. + // + // https://discord.com/developers/docs/topics/gateway#heartbeat + Seq int64 + + // RWMutex is used to protect the Session's variables from data races + // by providing transactional functionality. + sync.RWMutex +} diff --git a/_gen/main.go b/_gen/main.go index 850091d..5ce1935 100644 --- a/_gen/main.go +++ b/_gen/main.go @@ -77,7 +77,7 @@ func main() { func check() error { cwd, err := os.Getwd() if err != nil { - return fmt.Errorf("error getting the current working directory.\n%w", err) + return fmt.Errorf("error getting the current working directory: %w", err) } if filepath.Base(cwd) != exeDir && filepath.Base(filepath.Dir(cwd)) != "disgo" { @@ -163,24 +163,24 @@ func generate() error { } // send - sendgen := exec.Command("copygen", "-yml", "wrapper/copygen/requests/setup.yml", "-xm") + sendgen := exec.Command("copygen", "-yml", "_gen/tools/copygen/requests/setup.yml", "-xm") std, err := sendgen.CombinedOutput() if err != nil { return fmt.Errorf("copygen error (send): %v", string(std)) } // event handling - handlegen := exec.Command("copygen", "-yml", "wrapper/copygen/events/setup.yml", "-xm") + handlegen := exec.Command("copygen", "-yml", "_gen/tools/copygen/events/setup.yml", "-xm") std, err = handlegen.CombinedOutput() if err != nil { return fmt.Errorf("copygen error (handle): %v", string(std)) } - // commands - commandgen := exec.Command("copygen", "-yml", "wrapper/copygen/commands/setup.yml", "-xm") - std, err = commandgen.CombinedOutput() + // sendevents + sendeventgen := exec.Command("copygen", "-yml", "_gen/tools/copygen/sendevents/setup.yml", "-xm") + std, err = sendeventgen.CombinedOutput() if err != nil { - return fmt.Errorf("copygen error (command): %v", string(std)) + return fmt.Errorf("copygen error (sendevents): %v", string(std)) } // reset diff --git a/_gen/tools/clean.go b/_gen/tools/clean.go index 3d9429d..e2baef5 100644 --- a/_gen/tools/clean.go +++ b/_gen/tools/clean.go @@ -27,7 +27,7 @@ func Clean(code []byte) ([]byte, error) { content := []byte(file.String()) fmtdata, err := format.Source(content) if err != nil { - return content, fmt.Errorf("an error occurred while formatting the generated code.\n%w", err) + return content, fmt.Errorf("clean: error formatting generated code: %w", err) } return fmtdata, nil diff --git a/wrapper/copygen/events/README.md b/_gen/tools/copygen/events/README.md similarity index 88% rename from wrapper/copygen/events/README.md rename to _gen/tools/copygen/events/README.md index e1f0722..88fb274 100644 --- a/wrapper/copygen/events/README.md +++ b/_gen/tools/copygen/events/README.md @@ -14,7 +14,7 @@ type Hello struct { 2. Define the event name in [dasgo `events.go`](https://github.com/switchupcb/dasgo/blob/main/dasgo/events.go). -3. Define the return values in [`copygen/events/setup.go`](/wrapper/copygen/events/setup.go). +3. Define the return values in [`copygen/events/setup.go`](/_gen/tools/copygen/events/setup.go). ```go // Copygen defines the functions that will be generated. type Copygen interface { diff --git a/wrapper/copygen/events/setup.go b/_gen/tools/copygen/events/setup.go similarity index 100% rename from wrapper/copygen/events/setup.go rename to _gen/tools/copygen/events/setup.go diff --git a/wrapper/copygen/commands/setup.yml b/_gen/tools/copygen/events/setup.yml similarity index 88% rename from wrapper/copygen/commands/setup.yml rename to _gen/tools/copygen/events/setup.yml index 18a5da9..9de9836 100644 --- a/wrapper/copygen/commands/setup.yml +++ b/_gen/tools/copygen/events/setup.yml @@ -1,7 +1,7 @@ # Define where the code will be generated. generated: setup: ./setup.go - output: ../../session_command.go + output: ../../../../wrapper/handle.go # Define the optional custom templates used to generate the file. template: ./template/generate.go diff --git a/wrapper/copygen/events/template/generate.go b/_gen/tools/copygen/events/template/generate.go similarity index 100% rename from wrapper/copygen/events/template/generate.go rename to _gen/tools/copygen/events/template/generate.go diff --git a/wrapper/copygen/requests/README.md b/_gen/tools/copygen/requests/README.md similarity index 91% rename from wrapper/copygen/requests/README.md rename to _gen/tools/copygen/requests/README.md index cf46ede..26c7425 100644 --- a/wrapper/copygen/requests/README.md +++ b/_gen/tools/copygen/requests/README.md @@ -18,7 +18,7 @@ type EditGlobalApplicationCommand struct { 2. Define the endpoint in [dasgo `endpoints.go`](https://github.com/switchupcb/dasgo/blob/main/dasgo/endpoints.go). -3. Define the return values in [`copygen/requests/setup.go`](/wrapper/copygen/requests/setup.go). +3. Define the return values in [`copygen/requests/setup.go`](/_gen/tools/copygen/requests/setup.go). ```go // Copygen defines the functions that will be generated. type Copygen interface { diff --git a/wrapper/copygen/requests/setup.go b/_gen/tools/copygen/requests/setup.go similarity index 100% rename from wrapper/copygen/requests/setup.go rename to _gen/tools/copygen/requests/setup.go diff --git a/wrapper/copygen/requests/setup.yml b/_gen/tools/copygen/requests/setup.yml similarity index 87% rename from wrapper/copygen/requests/setup.yml rename to _gen/tools/copygen/requests/setup.yml index d1eeb53..10f2aa8 100644 --- a/wrapper/copygen/requests/setup.yml +++ b/_gen/tools/copygen/requests/setup.yml @@ -1,7 +1,7 @@ # Define where the code will be generated. generated: setup: ./setup.go - output: ../../request_send.go + output: ../../../../wrapper/request_send.go # Define the optional custom templates used to generate the file. template: ./template/generate.go diff --git a/wrapper/copygen/requests/template/generate.go b/_gen/tools/copygen/requests/template/generate.go similarity index 100% rename from wrapper/copygen/requests/template/generate.go rename to _gen/tools/copygen/requests/template/generate.go diff --git a/wrapper/copygen/commands/setup.go b/_gen/tools/copygen/sendevents/setup.go similarity index 100% rename from wrapper/copygen/commands/setup.go rename to _gen/tools/copygen/sendevents/setup.go diff --git a/wrapper/copygen/events/setup.yml b/_gen/tools/copygen/sendevents/setup.yml similarity index 85% rename from wrapper/copygen/events/setup.yml rename to _gen/tools/copygen/sendevents/setup.yml index 71b61af..07fa09e 100644 --- a/wrapper/copygen/events/setup.yml +++ b/_gen/tools/copygen/sendevents/setup.yml @@ -1,7 +1,8 @@ # Define where the code will be generated. generated: setup: ./setup.go - output: ../../handle.go + output: ../../../../wrapper/session_command.go + # Define the optional custom templates used to generate the file. template: ./template/generate.go diff --git a/wrapper/copygen/commands/template/generate.go b/_gen/tools/copygen/sendevents/template/generate.go similarity index 100% rename from wrapper/copygen/commands/template/generate.go rename to _gen/tools/copygen/sendevents/template/generate.go diff --git a/_gen/tools/replace.go b/_gen/tools/replace.go index 4afa536..92d53aa 100644 --- a/_gen/tools/replace.go +++ b/_gen/tools/replace.go @@ -32,7 +32,7 @@ func TypeFix(data []byte) ([]byte, error) { contentdata := []byte(content) fmtdata, err := format.Source(contentdata) if err != nil { - return contentdata, fmt.Errorf("an error occurred while formatting the generated code.\n%w", err) + return contentdata, fmt.Errorf("typefix: error formatting generated code: %w", err) } return fmtdata, nil diff --git a/disgo.go b/disgo.go index b3c1e8c..ac64904 100644 --- a/disgo.go +++ b/disgo.go @@ -1,5 +1,17946 @@ -// Code generated by bundler -// DO NOT EDIT. +// Code generated by github.com/switchupcb/disgo/_gen/tools/bundle. DO NOT EDIT. +package disgo + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/base64" + "errors" + "fmt" + "io" + "mime/multipart" + "net/textproto" + "net/url" + "os" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + json "github.com/goccy/go-json" + "github.com/gorilla/schema" + "github.com/rs/xid" + "github.com/rs/zerolog" + "github.com/switchupcb/disgo/wrapper/socket" + "github.com/switchupcb/websocket" + "github.com/valyala/fasthttp" + "golang.org/x/sync/errgroup" +) + +// Default Configuration Values. +const ( + module = "github.com/switchupcb/disgo" + defaultUserAgent = "DiscordBot (https://" + module + ", v" + VersionDiscordAPI + ")" +) + +// Client represents a Discord Application. +type Client struct { + ApplicationID string + + // Authentication contains parameters required to authenticate the bot. + Authentication *Authentication + + // Authorization contains parameters required to authorize a client's access to resources. + Authorization *Authorization + + // Config represents parameters used to perform various actions by the client. + Config *Config + + // Handlers represents a bot's event handlers. + Handlers *Handlers + + // Sessions contains sessions a bot uses to interact with the Discord Gateway. + Sessions []*Session +} + +// Authentication represents authentication parameters required to authenticate the bot. +// https://discord.com/developers/docs/reference#authentication +type Authentication struct { + // Token represents the Authentication Token used to authenticate the bot. + Token string + + // TokenType represents the type of the Authentication Token. + TokenType string + + // Header represents a Token Authorization Header. + Header string +} + +// BotToken uses a given token to return a valid Authentication Object for a bot token type. +func BotToken(token string) *Authentication { + return &Authentication{ + Token: token, + TokenType: "Bot", + Header: "Bot " + token, + } +} + +// BearerToken uses a given token to return a valid Authentication Object for a bearer token type. +func BearerToken(token string) *Authentication { + return &Authentication{ + Token: token, + TokenType: "Bearer", + Header: "Bearer" + token, + } +} + +// Authorization represents authorization parameters required to authorize a client's access to resources. +type Authorization struct { + // ClientID represents the application's client_id. + ClientID string + + // ClientSecret represents the application's client_secret. + ClientSecret string + + // RedirectURI represents the registered URL of the application. + // + // The URL should be non-url-encoded (i.e "https://localhost"), + // NOT url-encoded (i.e "https%3A%2F%2Flocalhost"). + RedirectURI string + + // state represents the state parameter used to prevent CSRF and Clickjacking. + // https://discord.com/developers/docs/topics/oauth2#state-and-security + State string + + // prompt controls how the authorization flow handles existing authorizations. + Prompt string + + // Scopes represents a list of OAuth2 scopes. + Scopes []string +} + +// Config represents parameters used to perform various actions by the client. +type Config struct { + // Gateway holds configuration variables that pertain to the Discord Gateway. + Gateway Gateway + + // Request holds configuration variables that pertain to the Discord HTTP API. + Request Request +} + +// DefaultConfig returns a default client configuration. +func DefaultConfig() *Config { + c := new(Config) + c.Request = DefaultRequest() + c.Gateway = DefaultGateway() + + return c +} + +// Request represents Discord Request parameters used to perform various actions by the client. +type Request struct { + // RateLimiter represents an object that provides rate limit functionality. + RateLimiter RateLimiter + + // Client is used to send requests. + // + // Use Client to set a custom User-Agent in the HTTP Request Header. + // https://discord.com/developers/docs/reference#user-agent + // + // https://pkg.go.dev/github.com/valyala/fasthttp#Client + Client *fasthttp.Client + + // Timeout represents the amount of time a request will wait for a response. + Timeout time.Duration + + // Retries represents the number of times a request may be retried upon failure. + // + // A request is ONLY retried when a Bad Gateway or Rate Limit is encountered. + Retries int + + // RetryShared determines the behavior of a request when + // a (shared) per-resource rate limit is hit. + // + // set RetryShared to true (default) to retry a request (within the per-route rate limit) + // until it's successful or until it experiences a non-shared 429 status code. + RetryShared bool +} + +const ( + // defaultRequestTimeout represents the default amount of time to wait on a request. + defaultRequestTimeout = time.Second +) + +// DefaultRequest returns a Default Request configuration. +func DefaultRequest() Request { + // configure the client. + client := new(fasthttp.Client) + client.Name = defaultUserAgent + + // configure the rate limiter. + ratelimiter := &RateLimit{ //nolint:exhaustruct + ids: make(map[string]string, len(RouteIDs)), + buckets: make(map[string]*Bucket, len(RouteIDs)), + entries: make(map[string]int, len(RouteIDs)), + } + + ratelimiter.DefaultBucket = &Bucket{ //nolint:exhaustruct + Limit: 1, + } + + // https://discord.com/developers/docs/topics/rate-limits#global-rate-limit + ratelimiter.SetBucket( + GlobalRateLimitRouteID, &Bucket{ //nolint:exhaustruct + Limit: FlagGlobalRateLimitRequest, + Remaining: FlagGlobalRateLimitRequest, + }, + ) + + return Request{ + RateLimiter: ratelimiter, + Client: client, + Timeout: defaultRequestTimeout, + Retries: 1, + RetryShared: true, + } +} + +// Gateway represents Discord Gateway parameters used to perform various actions by the client. +type Gateway struct { + // RateLimiter represents an object that provides rate limit functionality. + RateLimiter RateLimiter + + // Intents represents a Discord Gateway Intent. + // + // You must specify a Gateway Intent in order to receive specific information from an event. + // + // https://discord.com/developers/docs/topics/gateway#gateway-intents + IntentSet map[BitFlag]bool + + // GatewayPresenceUpdate represents the presence or status update of a bot. + // + // GatewayPresenceUpdate is used when the bot connects to a session. + // + // https://discord.com/developers/docs/topics/gateway#update-presence + GatewayPresenceUpdate *GatewayPresenceUpdate + + // Intents represents a Discord Gateway Intent. + // + // You must specify a Gateway Intent in order to receive specific information from an event. + // + // https://discord.com/developers/docs/topics/gateway#gateway-intents + Intents BitFlag +} + +const ( + // totalIntents represents the total amount of Discord Intents. + totalIntents = 19 + + // totalGatewayBuckets represents the total amount of Discord Gateway Rate Limits. + totalGatewayBuckets = 2 +) + +// DefaultGateway returns a default Gateway configuration. +// +// Privileged Intents are disabled by default. +// https://discord.com/developers/docs/topics/gateway#privileged-intents +func DefaultGateway() Gateway { + // configure the rate limiter. + ratelimiter := &RateLimit{ //nolint:exhaustruct + ids: make(map[string]string, totalGatewayBuckets), + buckets: make(map[string]*Bucket, totalGatewayBuckets), + } + + ratelimiter.DefaultBucket = &Bucket{ //nolint:exhaustruct + Limit: 1, + } + + // https://discord.com/developers/docs/topics/gateway#rate-limiting + ratelimiter.SetBucket( + GlobalRateLimitRouteID, &Bucket{ //nolint:exhaustruct + Limit: FlagGlobalRateLimitGateway, + Remaining: FlagGlobalRateLimitGateway, + Expiry: time.Now().Add(FlagGlobalRateLimitGatewayInterval), + }, + ) + + // disable Privileged Intents. + // https://discord.com/developers/docs/topics/gateway#privileged-intents + intentSet := make(map[BitFlag]bool, totalIntents) + for privilegedIntent := range PrivilegedIntents { + intentSet[privilegedIntent] = true + } + + return Gateway{ + Intents: 0, + IntentSet: intentSet, + GatewayPresenceUpdate: new(GatewayPresenceUpdate), + RateLimiter: ratelimiter, + } +} + +// EnableIntent enables an intent. +// +// This function does NOT check whether the intent is already enabled. +// Use the Gateway.IntentSet to check whether the intent is already enabled. +func (g *Gateway) EnableIntent(intent BitFlag) { + g.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] = true + g.Intents |= intent +} + +// DisableIntent disables an intent. +// +// Disclaimer: The Bitwise OR operation (used) to add an intent is a DESTRUCTIVE operation. +// +// This means that it can NOT be reversed. As a result, this function will NOT remove +// an intent that is already enabled. +func (g Gateway) DisableIntent(intent BitFlag) { + g.IntentSet[intent] = true +} + +// Gateway Opcodes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes +const ( + FlagGatewayOpcodeDispatch = 0 + FlagGatewayOpcodeHeartbeat = 1 + FlagGatewayOpcodeIdentify = 2 + FlagGatewayOpcodePresenceUpdate = 3 + FlagGatewayOpcodeVoiceStateUpdate = 4 + FlagGatewayOpcodeResume = 6 + FlagGatewayOpcodeReconnect = 7 + FlagGatewayOpcodeRequestGuildMembers = 8 + FlagGatewayOpcodeInvalidSession = 9 + FlagGatewayOpcodeHello = 10 + FlagGatewayOpcodeHeartbeatACK = 11 +) + +// Gateway Close Event Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-close-event-codes +type GatewayCloseEventCode struct { + Description string + Explanation string + Code int + Reconnect bool +} + +var ( + FlagGatewayCloseEventCodeUnknownError = GatewayCloseEventCode{ + Code: 4000, + Description: "Unknown error", + Explanation: "We're not sure what went wrong. Try reconnecting?", + Reconnect: true, + } + + FlagGatewayCloseEventCodeUnknownOpcode = GatewayCloseEventCode{ + Code: 4001, + Description: "Unknown opcode", + Explanation: "You sent an invalid Gateway opcode or an invalid payload for an opcode. Don't do that!", + Reconnect: true, + } + + FlagGatewayCloseEventCodeDecodeError = GatewayCloseEventCode{ + Code: 4002, + Description: "Decode error", + Explanation: "You sent an invalid payload to us. Don't do that!", + Reconnect: true, + } + + FlagGatewayCloseEventCodeNotAuthenticated = GatewayCloseEventCode{ + Code: 4003, + Description: "Not authenticated", + Explanation: "You sent us a payload prior to identifying.", + Reconnect: true, + } + + FlagGatewayCloseEventCodeAuthenticationFailed = GatewayCloseEventCode{ + Code: 4004, + Description: "Authentication failed", + Explanation: "The account token sent with your identify payload is incorrect.", + Reconnect: false, + } + + FlagGatewayCloseEventCodeAlreadyAuthenticated = GatewayCloseEventCode{ + Code: 4005, + Description: "Already authenticated", + Explanation: "You sent more than one identify payload. Don't do that!", + Reconnect: true, + } + + FlagGatewayCloseEventCodeInvalidSeq = GatewayCloseEventCode{ + Code: 4007, + Description: "Invalid seq", + Explanation: "The sequence sent when resuming the session was invalid. Reconnect and start a new session.", + Reconnect: true, + } + + FlagGatewayCloseEventCodeRateLimited = GatewayCloseEventCode{ + Code: 4008, + Description: "Rate limited.", + Explanation: "You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this.", + Reconnect: true, + } + + FlagGatewayCloseEventCodeSessionTimed = GatewayCloseEventCode{ + Code: 4009, + Description: "Session timed out", + Explanation: "Your session timed out. Reconnect and start a new one.", + Reconnect: true, + } + + FlagGatewayCloseEventCodeInvalidShard = GatewayCloseEventCode{ + Code: 4010, + Description: "Invalid shard", + Explanation: "You sent us an invalid shard when identifying.", + Reconnect: false, + } + + FlagGatewayCloseEventCodeShardingRequired = GatewayCloseEventCode{ + Code: 4011, + Description: "Sharding required", + Explanation: "The session would have handled too many guilds - you are required to shard your connection in order to connect.", + Reconnect: false, + } + + FlagGatewayCloseEventCodeInvalidAPIVersion = GatewayCloseEventCode{ + Code: 4012, + Description: "Invalid API version", + Explanation: "You sent an invalid version for the gateway.", + Reconnect: false, + } + + FlagGatewayCloseEventCodeInvalidIntent = GatewayCloseEventCode{ + Code: 4013, + Description: "Invalid intent(s)", + Explanation: "You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value.", + Reconnect: false, + } + + FlagGatewayCloseEventCodeDisallowedIntent = GatewayCloseEventCode{ + Code: 4014, + Description: "Disallowed intent(s)", + Explanation: "You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not approved for.", + Reconnect: false, + } + + GatewayCloseEventCodes = map[int]*GatewayCloseEventCode{ + FlagGatewayCloseEventCodeUnknownError.Code: &FlagGatewayCloseEventCodeUnknownError, + FlagGatewayCloseEventCodeUnknownOpcode.Code: &FlagGatewayCloseEventCodeUnknownOpcode, + FlagGatewayCloseEventCodeDecodeError.Code: &FlagGatewayCloseEventCodeDecodeError, + FlagGatewayCloseEventCodeNotAuthenticated.Code: &FlagGatewayCloseEventCodeNotAuthenticated, + FlagGatewayCloseEventCodeAuthenticationFailed.Code: &FlagGatewayCloseEventCodeAuthenticationFailed, + FlagGatewayCloseEventCodeAlreadyAuthenticated.Code: &FlagGatewayCloseEventCodeAlreadyAuthenticated, + FlagGatewayCloseEventCodeInvalidSeq.Code: &FlagGatewayCloseEventCodeInvalidSeq, + FlagGatewayCloseEventCodeRateLimited.Code: &FlagGatewayCloseEventCodeRateLimited, + FlagGatewayCloseEventCodeSessionTimed.Code: &FlagGatewayCloseEventCodeSessionTimed, + FlagGatewayCloseEventCodeInvalidShard.Code: &FlagGatewayCloseEventCodeInvalidShard, + FlagGatewayCloseEventCodeInvalidAPIVersion.Code: &FlagGatewayCloseEventCodeInvalidAPIVersion, + FlagGatewayCloseEventCodeInvalidIntent.Code: &FlagGatewayCloseEventCodeInvalidIntent, + FlagGatewayCloseEventCodeDisallowedIntent.Code: &FlagGatewayCloseEventCodeDisallowedIntent, + } +) + +// Client Close Event Codes +// https://discord.com/developers/docs/topics/gateway#disconnections +var ( + FlagClientCloseEventCodeNormal = 1000 + FlagClientCloseEventCodeAway = 1001 + + // https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1 + FlagClientCloseEventCodeReconnect = 3000 +) + +// Voice Opcodes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-opcodes +const ( + FlagVoiceOpcodeIdentify = 0 + FlagVoiceOpcodeSelectProtocol = 1 + FlagVoiceOpcodeReadyServer = 2 + FlagVoiceOpcodeHeartbeat = 3 + FlagVoiceOpcodeSessionDescription = 4 + FlagVoiceOpcodeSpeaking = 5 + FlagVoiceOpcodeHeartbeatACK = 6 + FlagVoiceOpcodeResume = 7 + FlagVoiceOpcodeHello = 8 + FlagVoiceOpcodeResumed = 9 + FlagVoiceOpcodeClientDisconnect = 13 +) + +// Voice Close Event Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes +type VoiceCloseEventCode struct { + Description string + Explanation string + Code int +} + +var ( + FlagVoiceCloseEventCodeUnknownOpcode = VoiceCloseEventCode{ + Code: 4001, + Description: "Unknown opcode", + Explanation: "You sent an invalid opcode.", + } + + FlagVoiceCloseEventCodeFailedDecode = VoiceCloseEventCode{ + Code: 4002, + Description: "Failed to decode payload", + Explanation: "You sent a invalid payload in your identifying to the Gateway.", + } + + FlagVoiceCloseEventCodeNotAuthenticated = VoiceCloseEventCode{ + Code: 4003, + Description: "Not authenticated", + Explanation: "You sent a payload before identifying with the Gateway.", + } + + FlagVoiceCloseEventCodeAuthenticationFailed = VoiceCloseEventCode{ + Code: 4004, + Description: "Authentication failed", + Explanation: "The token you sent in your identify payload is incorrect.", + } + + FlagVoiceCloseEventCodeAlreadyAuthenticated = VoiceCloseEventCode{ + Code: 4005, + Description: "Already authenticated", + Explanation: "You sent more than one identify payload. Stahp.", + } + + FlagVoiceCloseEventCodeInvalidSession = VoiceCloseEventCode{ + Code: 4006, + Description: "Session no longer valid", + Explanation: "Your session is no longer valid.", + } + + FlagVoiceCloseEventCodeSessionTimeout = VoiceCloseEventCode{ + Code: 4009, + Description: "Session timeout", + Explanation: "Your session has timed out.", + } + + FlagVoiceCloseEventCodeServerNotFound = VoiceCloseEventCode{ + Code: 4011, + Description: "Server not found", + Explanation: "We can't find the server you're trying to connect to.", + } + + FlagVoiceCloseEventCodeUnknownProtocol = VoiceCloseEventCode{ + Code: 4012, + Description: "Unknown protocol", + Explanation: "We didn't recognize the protocol you sent.", + } + + FlagVoiceCloseEventCodeDisconnectedChannel = VoiceCloseEventCode{ + Code: 4014, + Description: "Disconnected", + Explanation: "Channel was deleted, you were kicked, voice server changed, or the main gateway session was dropped. Don't reconnect.", + } + + FlagVoiceCloseEventCodeVoiceServerCrash = VoiceCloseEventCode{ + Code: 4015, + Description: "Voice server crashed", + Explanation: "The server crashed. Our bad! Try resuming.", + } + + FlagVoiceCloseEventCodeUnknownEncryptionMode = VoiceCloseEventCode{ + Code: 4016, + Description: "Unknown encryption mode", + Explanation: "We didn't recognize your encryption.", + } + + VoiceCloseEventCodes = map[int]*VoiceCloseEventCode{ + FlagVoiceCloseEventCodeUnknownOpcode.Code: &FlagVoiceCloseEventCodeUnknownOpcode, + FlagVoiceCloseEventCodeFailedDecode.Code: &FlagVoiceCloseEventCodeFailedDecode, + FlagVoiceCloseEventCodeNotAuthenticated.Code: &FlagVoiceCloseEventCodeNotAuthenticated, + FlagVoiceCloseEventCodeAuthenticationFailed.Code: &FlagVoiceCloseEventCodeAuthenticationFailed, + FlagVoiceCloseEventCodeAlreadyAuthenticated.Code: &FlagVoiceCloseEventCodeAlreadyAuthenticated, + FlagVoiceCloseEventCodeInvalidSession.Code: &FlagVoiceCloseEventCodeInvalidSession, + FlagVoiceCloseEventCodeSessionTimeout.Code: &FlagVoiceCloseEventCodeSessionTimeout, + FlagVoiceCloseEventCodeServerNotFound.Code: &FlagVoiceCloseEventCodeServerNotFound, + FlagVoiceCloseEventCodeUnknownProtocol.Code: &FlagVoiceCloseEventCodeUnknownProtocol, + FlagVoiceCloseEventCodeDisconnectedChannel.Code: &FlagVoiceCloseEventCodeDisconnectedChannel, + FlagVoiceCloseEventCodeVoiceServerCrash.Code: &FlagVoiceCloseEventCodeVoiceServerCrash, + FlagVoiceCloseEventCodeUnknownEncryptionMode.Code: &FlagVoiceCloseEventCodeUnknownEncryptionMode, + } +) + +// HTTP Response Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#http-http-response-codes +const ( + FlagHTTPResponseCodeOK = 200 + FlagHTTPResponseCodeCREATED = 201 + FlagHTTPResponseCodeNOCONTENT = 204 + FlagHTTPResponseCodeNOTMODIFIED = 304 + FlagHTTPResponseCodeBADREQUEST = 400 + FlagHTTPResponseCodeUNAUTHORIZED = 401 + FlagHTTPResponseCodeFORBIDDEN = 403 + FlagHTTPResponseCodeNOTFOUND = 404 + FlagHTTPResponseCodeMETHODNOTALLOWED = 405 + FlagHTTPResponseCodeTOOMANYREQUESTS = 429 + FlagHTTPResponseCodeGATEWAYUNAVAILABLE = 502 + FlagHTTPResponseCodeSERVERERROR = 500 // 5xx (500 Not Guaranteed) +) + +var ( + HTTPResponseCodes = map[int]string{ + FlagHTTPResponseCodeOK: "The request completed successfully.", + FlagHTTPResponseCodeCREATED: "The entity was created successfully.", + FlagHTTPResponseCodeNOCONTENT: "The request completed successfully but returned no content.", + FlagHTTPResponseCodeNOTMODIFIED: "The entity was not modified (no action was taken).", + FlagHTTPResponseCodeBADREQUEST: "The request was improperly formatted, or the server couldn't understand it.", + FlagHTTPResponseCodeUNAUTHORIZED: "The Authorization header was missing or invalid.", + FlagHTTPResponseCodeFORBIDDEN: "The Authorization token you passed did not have permission to the resource.", + FlagHTTPResponseCodeNOTFOUND: "The resource at the location specified doesn't exist.", + FlagHTTPResponseCodeMETHODNOTALLOWED: "The HTTP method used is not valid for the location specified.", + FlagHTTPResponseCodeTOOMANYREQUESTS: "You are being rate limited, see Rate Limits.", + FlagHTTPResponseCodeGATEWAYUNAVAILABLE: "There was not a gateway available to process your request. Wait a bit and retry.", + FlagHTTPResponseCodeSERVERERROR: "The server had an error processing your request (these are rare).", + } +) + +// JSON Error Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes +var ( + JSONErrorCodes = map[int]string{ + 0: "General error (such as a malformed request body, amongst other things)", + 10001: "Unknown account", + 10002: "Unknown application", + 10003: "Unknown channel", + 10004: "Unknown guild", + 10005: "Unknown integration", + 10006: "Unknown invite", + 10007: "Unknown member", + 10008: "Unknown message", + 10009: "Unknown permission overwrite", + 10010: "Unknown provider", + 10011: "Unknown role", + 10012: "Unknown token", + 10013: "Unknown user", + 10014: "Unknown emoji", + 10015: "Unknown webhook", + 10016: "Unknown webhook service", + 10020: "Unknown session", + 10026: "Unknown ban", + 10027: "Unknown SKU", + 10028: "Unknown Store Listing", + 10029: "Unknown entitlement", + 10030: "Unknown build", + 10031: "Unknown lobby", + 10032: "Unknown branch", + 10033: "Unknown store directory layout", + 10036: "Unknown redistributable", + 10038: "Unknown gift code", + 10049: "Unknown stream", + 10050: "Unknown premium server subscribe cooldown", + 10057: "Unknown guild template", + 10059: "Unknown discoverable server category", + 10060: "Unknown sticker", + 10062: "Unknown interaction", + 10063: "Unknown application command", + 10065: "Unknown voice state", + 10066: "Unknown application command permissions", + 10067: "Unknown Stage Instance", + 10068: "Unknown Guild Member Verification Form", + 10069: "Unknown Guild Welcome Screen", + 10070: "Unknown Guild Scheduled Event", + 10071: "Unknown Guild Scheduled Event User", + 10087: "Unknown Tag", + 20001: "Bots cannot use this endpoint", + 20002: "Only bots can use this endpoint", + 20009: "Explicit content cannot be sent to the desired recipient(s)", + 20012: "You are not authorized to perform this action on this application", + 20016: "This action cannot be performed due to slowmode rate limit", + 20018: "Only the owner of this account can perform this action", + 20022: "This message cannot be edited due to announcement rate limits", + 20024: "The owner of this account is not old enough to join an NSFW server.", + 20028: "The channel you are writing has hit the write rate limit", + 20029: "The write action you are performing on the server has hit the write rate limit", + 20031: "Your Stage topic, server name, server description, or channel names contain words that are not allowed", + 20035: "Guild premium subscription level too low", + 30001: "Maximum number of guilds reached (100)", + 30002: "Maximum number of friends reached (1000)", + 30003: "Maximum number of pins reached for the channel (50)", + 30004: "Maximum number of recipients reached (10)", + 30005: "Maximum number of guild roles reached (250)", + 30007: "Maximum number of webhooks reached (10)", + 30008: "Maximum number of emojis reached", + 30010: "Maximum number of reactions reached (20)", + 30013: "Maximum number of guild channels reached (500)", + 30015: "Maximum number of attachments in a message reached (10)", + 30016: "Maximum number of invites reached (1000)", + 30018: "Maximum number of animated emojis reached", + 30019: "Maximum number of server members reached", + 30030: "Maximum number of server categories has been reached (5)", + 30031: "Guild already has a template", + 30032: "Maximum number of application commands reached", + 30033: "Max number of thread participants has been reached (1000)", + 30034: "Max number of daily application command creates has been reached (200)", + 30035: "Maximum number of bans for non-guild members have been exceeded", + 30037: "Maximum number of bans fetches has been reached", + 30038: "Maximum number of uncompleted guild scheduled events reached (100)", + 30039: "Maximum number of stickers reached", + 30040: "Maximum number of prune requests has been reached. Try again later", + 30042: "Maximum number of guild widget settings updates has been reached. Try again later", + 30046: "Maximum number of edits to messages older than 1 hour reached. Try again later", + 30047: "Maximum number of pinned threads in a forum channel has been reached", + 30048: "Maximum number of tags in a forum channel has been reached", + 30052: "Bitrate is too high for channel of this type", + 40001: "Unauthorized. Provide a valid token and try again", + 40002: "You need to verify your account in order to perform this action", + 40003: "You are opening direct messages too fast", + 40004: "Send messages has been temporarily disabled", + 40005: "Request entity too large. Try sending something smaller in size", + 40006: "This feature has been temporarily disabled server-side", + 40007: "The user is banned from this guild", + 40012: "Connection has been revoked", + 40032: "Target user is not connected to voice", + 40033: "This message has already been crossposted", + 40041: "An application command with that name already exists", + 40043: "Application interaction failed to send", + 40058: "Cannot send a message in a forum channel", + 40060: "Interaction has already been acknowledged", + 40061: "Tag names must be unique", + 40066: "There are no tags available that can be set by non-moderators", + 40067: "A tag is required to create a forum post in this channel", + 50001: "Missing access", + 50002: "Invalid account type", + 50003: "Cannot execute action on a DM channel", + 50004: "Guild widget disabled", + 50005: "Cannot edit a message authored by another user", + 50006: "Cannot send an empty message", + 50007: "Cannot send messages to this user", + 50008: "Cannot send messages in a non-text channel", + 50009: "Channel verification level is too high for you to gain access", + 50010: "OAuth2 application does not have a bot", + 50011: "OAuth2 application limit reached", + 50012: "Invalid OAuth2 state", + 50013: "You lack permissions to perform that action", + 50014: "Invalid authentication token provided", + 50015: "Note was too long", + 50016: "Provided too few or too many messages to delete. Must provide at least 2 and fewer than 100 messages to delete", + 50017: "Invalid MFA Level", + 50019: "A message can only be pinned to the channel it was sent in", + 50020: "Invite code was either invalid or taken", + 50021: "Cannot execute action on a system message", + 50024: "Cannot execute action on this channel type", + 50025: "Invalid OAuth2 access token provided", + 50026: "Missing required OAuth2 scope", + 50027: "Invalid webhook token provided", + 50028: "Invalid role", + 50033: "Invalid Recipient(s)", + 50034: "A message provided was too old to bulk delete", + 50035: "Invalid form body (returned for both application/json and multipart/form-data bodies), or invalid Content-Type provided", + 50036: "An invite was accepted to a guild the application's bot is not in", + 50039: "Invalid Activity Action", + 50041: "Invalid API version provided", + 50045: "File uploaded exceeds the maximum size", + 50046: "Invalid file uploaded", + 50054: "Cannot self-redeem this gift", + 50055: "Invalid Guild", + 50068: "Invalid message type", + 50070: "Payment source required to redeem gift", + 50073: "Cannot modify a system webhook", + 50074: "Cannot delete a channel required for Community guilds", + 50081: "Invalid sticker sent", + 50083: "Tried to perform an operation on an archived thread, such as editing a message or adding a user to the thread", + 50084: "Invalid thread notification settings", + 50085: "before value is earlier than the thread creation date", + 50086: "Community server channels must be text channels", + 50095: "This server is not available in your location", + 50097: "This server needs monetization enabled in order to perform this action", + 50101: "This server needs more boosts to perform this action", + 50109: "The request body contains invalid JSON.", + 50132: "Ownership cannot be transferred to a bot user", + 50138: "Failed to resize asset below the maximum size: 262144", + 50146: "Uploaded file not found.", + 50600: "You do not have permission to send this sticker.", + 60003: "Two factor is required for this operation", + 80004: "No users with DiscordTag exist", + 90001: "Reaction was blocked", + 110001: "Application not yet available. Try again later", + 130000: "API resource is currently overloaded. Try again a little later", + 150006: "The Stage is already open", + 160002: "Cannot reply without permission to read message history", + 160004: "A thread has already been created for this message", + 160005: "Thread is locked", + 160006: "Maximum number of active threads reached", + 160007: "Maximum number of active announcement threads reached", + 170001: "Invalid JSON for uploaded Lottie file", + 170002: "Uploaded Lotties cannot contain rasterized images such as PNG or JPEG", + 170003: "Sticker maximum framerate exceeded", + 170004: "Sticker frame count exceeds maximum of 1000 frames", + 170005: "Lottie animation maximum dimensions exceeded", + 170006: "Sticker frame rate is either too small or too large", + 170007: "Sticker animation duration exceeds maximum of 5 seconds", + 180000: "Cannot update a finished event", + 180002: "Failed to create stage needed for stage event", + 200000: "Message was blocked by automatic moderation", + 200001: "Title was blocked by automatic moderation", + 220001: "Webhooks posted to forum channels must have a thread_name or thread_id", + 220002: " Webhooks posted to forum channels cannot have both a thread_name and thread_id", + 220003: "Webhooks can only create threads in forum channels", + 240000: "Message blocked by harmful links filter", + } +) + +// RPC Error Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#rpc-rpc-error-codes +const ( + FlagRPCErrorCodeUnknownError = 1000 + FlagRPCErrorCodeInvalidPayload = 4000 + FlagRPCErrorCodeInvalidCommand = 4002 + FlagRPCErrorCodeInvalidGuild = 4003 + FlagRPCErrorCodeInvalidEvent = 4004 + FlagRPCErrorCodeInvalidChannel = 4005 + FlagRPCErrorCodeInvalidPermissions = 4006 + FlagRPCErrorCodeInvalidClientID = 4007 + FlagRPCErrorCodeInvalidOrigin = 4008 + FlagRPCErrorCodeInvalidToken = 4009 + FlagRPCErrorCodeInvalidUser = 4010 + FlagRPCErrorCodeOAuth2Error = 5000 + FlagRPCErrorCodeSelectChannelTimedOut = 5001 + FlagRPCErrorCodeGET_GUILDTimedOut = 5002 + FlagRPCErrorCodeSelectVoiceForceRequired = 5003 + FlagRPCErrorCodeCaptureShortcutAlreadyListening = 5004 +) + +// RPC Close Event Codes +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#rpc-rpc-close-event-codes +const ( + FlagRPCCloseEventCodeInvalidClientID = 4000 + FlagRPCCloseEventCodeInvalidOrigin = 4001 + FlagRPCCloseEventCodeRateLimited = 4002 + FlagRPCCloseEventCodeTokenRevoked = 4003 + FlagRPCCloseEventCodeInvalidVersion = 4004 + FlagRPCCloseEventCodeInvalidEncoding = 4005 +) + +// Flag represents an (unused) alias for a Discord API Flag ranging from 0 - 255. +type Flag uint8 + +// BitFlag represents an alias for a Discord API Bitwise Flag denoted by 1 << x. +type BitFlag uint64 + +// File represents a file attachment. +type File struct { + Name string + ContentType string + Data []byte +} + +// Nonce represents a Discord nonce (integer or string). +type Nonce string + +// Value represents a value (string, integer, or double). +type Value string + +// PointerIndicator represents a Dasgo double pointer value indicator. +type PointerIndicator uint8 + +const ( + // IsValueNothing indicates that the field was not provided. + // + // The double pointer is nil. + IsValueNothing PointerIndicator = 0 + + // IsValueNull indicates the the field was provided with a null value. + // + // The double pointer points to a nil pointer. + IsValueNull PointerIndicator = 1 + + // IsValueValid indicates that the field is a valid value. + // + // The double pointer points to a pointer that points to a value. + IsValueValid PointerIndicator = 2 +) + +// Gateway Events +// https://discord.com/developers/docs/topics/gateway#gateway-events +type Event interface{} + +// Gateway Event Names +// https://discord.com/developers/docs/topics/gateway-events +const ( + FlagGatewayEventNameHello = "HELLO" + FlagGatewayEventNameReady = "READY" + FlagGatewayEventNameResumed = "RESUMED" + FlagGatewayEventNameReconnect = "RECONNECT" + FlagGatewayEventNameInvalidSession = "INVALID_SESSION" + FlagGatewayEventNameApplicationCommandPermissionsUpdate = "APPLICATION_COMMAND_PERMISSIONS_UPDATE" + FlagGatewayEventNameAutoModerationRuleCreate = "AUTO_MODERATION_RULE_CREATE" + FlagGatewayEventNameAutoModerationRuleUpdate = "AUTO_MODERATION_RULE_UPDATE" + FlagGatewayEventNameAutoModerationRuleDelete = "AUTO_MODERATION_RULE_DELETE" + FlagGatewayEventNameAutoModerationActionExecution = "AUTO_MODERATION_ACTION_EXECUTION" + FlagGatewayEventNameChannelCreate = "CHANNEL_CREATE" + FlagGatewayEventNameChannelUpdate = "CHANNEL_UPDATE" + FlagGatewayEventNameChannelDelete = "CHANNEL_DELETE" + FlagGatewayEventNameChannelPinsUpdate = "CHANNEL_PINS_UPDATE" + FlagGatewayEventNameThreadCreate = "THREAD_CREATE" + FlagGatewayEventNameThreadUpdate = "THREAD_UPDATE" + FlagGatewayEventNameThreadDelete = "THREAD_DELETE" + FlagGatewayEventNameThreadListSync = "THREAD_LIST_SYNC" + FlagGatewayEventNameThreadMemberUpdate = "THREAD_MEMBER_UPDATE" + FlagGatewayEventNameThreadMembersUpdate = "THREAD_MEMBERS_UPDATE" + FlagGatewayEventNameGuildCreate = "GUILD_CREATE" + FlagGatewayEventNameGuildUpdate = "GUILD_UPDATE" + FlagGatewayEventNameGuildDelete = "GUILD_DELETE" + FlagGatewayEventNameGuildBanAdd = "GUILD_BAN_ADD" + FlagGatewayEventNameGuildBanRemove = "GUILD_BAN_REMOVE" + FlagGatewayEventNameGuildEmojisUpdate = "GUILD_EMOJIS_UPDATE" + FlagGatewayEventNameGuildStickersUpdate = "GUILD_STICKERS_UPDATE" + FlagGatewayEventNameGuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE" + FlagGatewayEventNameGuildMemberAdd = "GUILD_MEMBER_ADD" + FlagGatewayEventNameGuildMemberRemove = "GUILD_MEMBER_REMOVE" + FlagGatewayEventNameGuildMemberUpdate = "GUILD_MEMBER_UPDATE" + FlagGatewayEventNameGuildMembersChunk = "GUILD_MEMBERS_CHUNK" + FlagGatewayEventNameGuildRoleCreate = "GUILD_ROLE_CREATE" + FlagGatewayEventNameGuildRoleUpdate = "GUILD_ROLE_UPDATE" + FlagGatewayEventNameGuildRoleDelete = "GUILD_ROLE_DELETE" + FlagGatewayEventNameGuildScheduledEventCreate = "GUILD_SCHEDULED_EVENT_CREATE" + FlagGatewayEventNameGuildScheduledEventUpdate = "GUILD_SCHEDULED_EVENT_UPDATE" + FlagGatewayEventNameGuildScheduledEventDelete = "GUILD_SCHEDULED_EVENT_DELETE" + FlagGatewayEventNameGuildScheduledEventUserAdd = "GUILD_SCHEDULED_EVENT_USER_ADD" + FlagGatewayEventNameGuildScheduledEventUserRemove = "GUILD_SCHEDULED_EVENT_USER_REMOVE" + FlagGatewayEventNameIntegrationCreate = "INTEGRATION_CREATE" + FlagGatewayEventNameIntegrationUpdate = "INTEGRATION_UPDATE" + FlagGatewayEventNameIntegrationDelete = "INTEGRATION_DELETE" + FlagGatewayEventNameInteractionCreate = "INTERACTION_CREATE" + FlagGatewayEventNameInviteCreate = "INVITE_CREATE" + FlagGatewayEventNameInviteDelete = "INVITE_DELETE" + FlagGatewayEventNameMessageCreate = "MESSAGE_CREATE" + FlagGatewayEventNameMessageUpdate = "MESSAGE_UPDATE" + FlagGatewayEventNameMessageDelete = "MESSAGE_DELETE" + FlagGatewayEventNameMessageDeleteBulk = "MESSAGE_DELETE_BULK" + FlagGatewayEventNameMessageReactionAdd = "MESSAGE_REACTION_ADD" + FlagGatewayEventNameMessageReactionRemove = "MESSAGE_REACTION_REMOVE" + FlagGatewayEventNameMessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL" + FlagGatewayEventNameMessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI" + FlagGatewayEventNamePresenceUpdate = "PRESENCE_UPDATE" + FlagGatewayEventNameStageInstanceCreate = "STAGE_INSTANCE_CREATE" + FlagGatewayEventNameStageInstanceDelete = "STAGE_INSTANCE_DELETE" + FlagGatewayEventNameStageInstanceUpdate = "STAGE_INSTANCE_UPDATE" + FlagGatewayEventNameTypingStart = "TYPING_START" + FlagGatewayEventNameUserUpdate = "USER_UPDATE" + FlagGatewayEventNameVoiceStateUpdate = "VOICE_STATE_UPDATE" + FlagGatewayEventNameVoiceServerUpdate = "VOICE_SERVER_UPDATE" + FlagGatewayEventNameWebhooksUpdate = "WEBHOOKS_UPDATE" +) + +// Hello Structure +// https://discord.com/developers/docs/topics/gateway-events#hello-hello-structure +type Hello struct { + HeartbeatInterval int `json:"heartbeat_interval"` +} + +// Ready Event Fields +// https://discord.com/developers/docs/topics/gateway-events#ready-ready-event-fields +type Ready struct { + Application *Application `json:"application"` + User *User `json:"user"` + Shard *[2]int `json:"shard,omitempty"` + SessionID string `json:"session_id"` + ResumeGatewayURL string `json:"resume_gateway_url"` + Guilds []*Guild `json:"guilds"` + Version int `json:"v"` +} + +// Resumed +// https://discord.com/developers/docs/topics/gateway-events#resumed +type Resumed struct{} + +// Reconnect +// https://discord.com/developers/docs/topics/gateway-events#reconnect +type Reconnect struct{} + +// Invalid Session +// https://discord.com/developers/docs/topics/gateway-events#invalid-session +type InvalidSession struct { + Data bool `json:"d"` +} + +// Application Command Permissions Update +// https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update +type ApplicationCommandPermissionsUpdate struct { + *GuildApplicationCommandPermissions +} + +// Auto Moderation Rule Create +// https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create +type AutoModerationRuleCreate struct { + *AutoModerationRule +} + +// Auto Moderation Rule Update +// https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update +type AutoModerationRuleUpdate struct { + *AutoModerationRule +} + +// Auto Moderation Rule Delete +// https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete +type AutoModerationRuleDelete struct { + *AutoModerationRule +} + +// Auto Moderation Action Execution +// https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution +type AutoModerationActionExecution struct { + Action AutoModerationAction `json:"action"` + MessageID *string `json:"message_id,omitempty"` + MatchedKeyword *string `json:"matched_keyword"` + MatchedContent *string `json:"matched_content"` + ChannelID *string `json:"channel_id,omitempty"` + AlertSystemMessageID *string `json:"alert_system_message_id,omitempty"` + RuleID string `json:"rule_id"` + GuildID string `json:"guild_id"` + Content string `json:"content"` + UserID string `json:"user_id"` + RuleTriggerType Flag `json:"rule_trigger_type"` +} + +// Channel Create +// https://discord.com/developers/docs/topics/gateway-events#channel-create +type ChannelCreate struct { + *Channel +} + +// Channel Update +// https://discord.com/developers/docs/topics/gateway-events#channel-update +type ChannelUpdate struct { + *Channel +} + +// Channel Delete +// https://discord.com/developers/docs/topics/gateway-events#channel-delete +type ChannelDelete struct { + *Channel +} + +// Thread Create +// https://discord.com/developers/docs/topics/gateway-events#thread-create +type ThreadCreate struct { + *Channel + NewlyCreated *bool `json:"newly_created,omitempty"` +} + +// Thread Update +// https://discord.com/developers/docs/topics/gateway-events#thread-update +type ThreadUpdate struct { + *Channel +} + +// Thread Delete +// https://discord.com/developers/docs/topics/gateway-events#thread-delete +type ThreadDelete struct { + *Channel +} + +// Thread List Sync Event Fields +// https://discord.com/developers/docs/topics/gateway-events#thread-list-sync +type ThreadListSync struct { + GuildID string `json:"guild_id"` + ChannelIDs []string `json:"channel_ids,omitempty"` + Threads []*Channel `json:"threads"` + Members []*ThreadMember `json:"members"` +} + +// Thread Member Update +// https://discord.com/developers/docs/topics/gateway-events#thread-member-update +type ThreadMemberUpdate struct { + *ThreadMember + GuildID string `json:"guild_id"` +} + +// Thread Members Update +// https://discord.com/developers/docs/topics/gateway-events#thread-members-update +type ThreadMembersUpdate struct { + ID string `json:"id"` + GuildID string `json:"guild_id"` + AddedMembers []*ThreadMember `json:"added_members,omitempty"` + RemovedMembers []string `json:"removed_member_ids,omitempty"` + MemberCount int `json:"member_count"` +} + +// Channel Pins Update +// https://discord.com/developers/docs/topics/gateway-events#channel-pins-update +type ChannelPinsUpdate struct { + LastPinTimestamp **time.Time `json:"last_pin_timestamp,omitempty"` + GuildID string `json:"guild_id,omitempty"` + ChannelID string `json:"channel_id"` +} + +// Guild Create +// https://discord.com/developers/docs/topics/gateway-events#guild-create +type GuildCreate struct { + *Guild + + // https://discord.com/developers/docs/topics/threads#gateway-events + Threads []*Channel `json:"threads,omitempty"` +} + +// Guild Update +// https://discord.com/developers/docs/topics/gateway-events#guild-update +type GuildUpdate struct { + *Guild +} + +// Guild Delete +// https://discord.com/developers/docs/topics/gateway-events#guild-delete +type GuildDelete struct { + *Guild +} + +// Guild Ban Add +// https://discord.com/developers/docs/topics/gateway-events#guild-ban-add +type GuildBanAdd struct { + User *User `json:"user"` + GuildID string `json:"guild_id"` +} + +// Guild Ban Remove +// https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove +type GuildBanRemove struct { + User *User `json:"user"` + GuildID string `json:"guild_id"` +} + +// Guild Emojis Update +// https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update +type GuildEmojisUpdate struct { + GuildID string `json:"guild_id"` + Emojis []*Emoji `json:"emojis"` +} + +// Guild Stickers Update +// https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update +type GuildStickersUpdate struct { + GuildID string `json:"guild_id"` + Stickers []*Sticker `json:"stickers"` +} + +// Guild Integrations Update +// https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update +type GuildIntegrationsUpdate struct { + GuildID string `json:"guild_id"` +} + +// Guild Member Add +// https://discord.com/developers/docs/topics/gateway-events#guild-member-add +type GuildMemberAdd struct { + *GuildMember + GuildID string `json:"guild_id"` +} + +// Guild Member Remove +// https://discord.com/developers/docs/topics/gateway-events#guild-member-remove +type GuildMemberRemove struct { + User *User `json:"user"` + GuildID string `json:"guild_id"` +} + +// Guild Member Update +// https://discord.com/developers/docs/topics/gateway-events#guild-member-update +type GuildMemberUpdate struct { + *GuildMember +} + +// Guild Members Chunk +// https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk +type GuildMembersChunk struct { + Nonce *string `json:"nonce,omitempty"` + GuildID string `json:"guild_id"` + Members []*GuildMember `json:"members"` + Presences []*PresenceUpdate `json:"presences,omitempty"` + NotFound []string `json:"not_found,omitempty"` + ChunkIndex int `json:"chunk_index"` + ChunkCount int `json:"chunk_count"` +} + +// Guild Role Create +// https://discord.com/developers/docs/topics/gateway-events#guild-role-create +type GuildRoleCreate struct { + Role *Role `json:"role"` + GuildID string `json:"guild_id"` +} + +// Guild Role Update +// https://discord.com/developers/docs/topics/gateway-events#guild-role-update +type GuildRoleUpdate struct { + Role *Role `json:"role"` + GuildID string `json:"guild_id"` +} + +// Guild Role Delete +// https://discord.com/developers/docs/topics/gateway-events#guild-role-delete +type GuildRoleDelete struct { + GuildID string `json:"guild_id"` + RoleID string `json:"role_id"` +} + +// Guild Scheduled Event Create +// https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create +type GuildScheduledEventCreate struct { + *GuildScheduledEvent +} + +// Guild Scheduled Event Update +// https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update +type GuildScheduledEventUpdate struct { + *GuildScheduledEvent +} + +// Guild Scheduled Event Delete +// https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete +type GuildScheduledEventDelete struct { + *GuildScheduledEvent +} + +// Guild Scheduled Event User Add +// https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add +type GuildScheduledEventUserAdd struct { + GuildScheduledEventID string `json:"guild_scheduled_event_id"` + UserID string `json:"user_id"` + GuildID string `json:"guild_id"` +} + +// Guild Scheduled Event User Remove +// https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove +type GuildScheduledEventUserRemove struct { + GuildScheduledEventID string `json:"guild_scheduled_event_id"` + UserID string `json:"user_id"` + GuildID string `json:"guild_id"` +} + +// Integration Create +// https://discord.com/developers/docs/topics/gateway-events#integration-create +type IntegrationCreate struct { + *Integration + GuildID string `json:"guild_id"` +} + +// Integration Update +// https://discord.com/developers/docs/topics/gateway-events#integration-update +type IntegrationUpdate struct { + *Integration + GuildID string `json:"guild_id"` +} + +// Integration Delete +// https://discord.com/developers/docs/topics/gateway-events#integration-delete +type IntegrationDelete struct { + ApplicationID *string `json:"application_id,omitempty"` + IntegrationID string `json:"id"` + GuildID string `json:"guild_id"` +} + +// Interaction Create +// https://discord.com/developers/docs/topics/gateway-events#interaction-create +type InteractionCreate struct { + *Interaction +} + +// Invite Create +// https://discord.com/developers/docs/topics/gateway-events#invite-create +type InviteCreate struct { + CreatedAt time.Time `json:"created_at"` + TargetType *int `json:"target_user_type,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + Inviter *User `json:"inviter,omitempty"` + TargetUser *User `json:"target_user,omitempty"` + TargetApplication *Application `json:"target_application,omitempty"` + ChannelID string `json:"channel_id"` + Code string `json:"code"` + MaxAge int `json:"max_age"` + MaxUses int `json:"max_uses"` + Uses int `json:"uses"` + Temporary bool `json:"temporary"` +} + +// Invite Delete +// https://discord.com/developers/docs/topics/gateway-events#invite-delete +type InviteDelete struct { + ChannelID string `json:"channel_id"` + GuildID *string `json:"guild_id,omitempty"` + Code string `json:"code"` +} + +// Message Create +// https://discord.com/developers/docs/topics/gateway-events#message-create +type MessageCreate struct { + *Message +} + +// Message Update +// https://discord.com/developers/docs/topics/gateway-events#message-update +type MessageUpdate struct { + *Message +} + +// Message Delete +// https://discord.com/developers/docs/topics/gateway-events#message-delete +type MessageDelete struct { + GuildID *string `json:"guild_id,omitempty"` + MessageID string `json:"id"` + ChannelID string `json:"channel_id"` +} + +// Message Delete Bulk +// https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk +type MessageDeleteBulk struct { + GuildID *string `json:"guild_id,omitempty"` + ChannelID string `json:"channel_id"` + MessageIDs []string `json:"ids"` +} + +// Message Reaction Add +// https://discord.com/developers/docs/topics/gateway-events#message-reaction-add +type MessageReactionAdd struct { + GuildID *string `json:"guild_id,omitempty"` + Member *GuildMember `json:"member,omitempty"` + Emoji *Emoji `json:"emoji"` + UserID string `json:"user_id"` + ChannelID string `json:"channel_id"` + MessageID string `json:"message_id"` +} + +// Message Reaction Remove +// https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove +type MessageReactionRemove struct { + GuildID *string `json:"guild_id,omitempty"` + Emoji *Emoji `json:"emoji"` + UserID string `json:"user_id"` + ChannelID string `json:"channel_id"` + MessageID string `json:"message_id"` +} + +// Message Reaction Remove All +// https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all +type MessageReactionRemoveAll struct { + GuildID *string `json:"guild_id,omitempty"` + ChannelID string `json:"channel_id"` + MessageID string `json:"message_id"` +} + +// Message Reaction Remove Emoji +// https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-emoji +type MessageReactionRemoveEmoji struct { + GuildID *string `json:"guild_id,omitempty"` + Emoji *Emoji `json:"emoji"` + ChannelID string `json:"channel_id"` + MessageID string `json:"message_id"` +} + +// Presence Update Event Fields +// https://discord.com/developers/docs/topics/gateway-events#presence-update-presence-update-event-fields +type PresenceUpdate struct { + User *User `json:"user"` + ClientStatus *ClientStatus `json:"client_status"` + GuildID string `json:"guild_id"` + Status string `json:"status"` + Activities []*Activity `json:"activities"` +} + +// Stage Instance Create +// https://discord.com/developers/docs/topics/gateway-events#stage-instance-create +type StageInstanceCreate struct { + *StageInstance +} + +// Stage Instance Update +// https://discord.com/developers/docs/topics/gateway-events#stage-instance-update +type StageInstanceUpdate struct { + *StageInstance +} + +// Stage Instance Delete +// https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete +type StageInstanceDelete struct { + *StageInstance +} + +// Typing Start +// https://discord.com/developers/docs/topics/gateway-events#typing-start +type TypingStart struct { + Timestamp time.Time `json:"timestamp"` + GuildID *string `json:"guild_id,omitempty"` + Member *GuildMember `json:"member,omitempty"` + ChannelID string `json:"channel_id"` + UserID string `json:"user_id"` +} + +// User Update +// https://discord.com/developers/docs/topics/gateway-events#user-update +type UserUpdate struct { + *User +} + +// Voice State Update +// https://discord.com/developers/docs/topics/gateway-events#voice-state-update +type VoiceStateUpdate struct { + *VoiceState +} + +// Voice Server Update +// https://discord.com/developers/docs/topics/gateway-events#voice-server-update +type VoiceServerUpdate struct { + Endpoint *string `json:"endpoint"` + Token string `json:"token"` + GuildID string `json:"guild_id"` +} + +// Webhooks Update +// https://discord.com/developers/docs/topics/gateway-events#webhooks-update +type WebhooksUpdate struct { + GuildID string `json:"guild_id"` + ChannelID string `json:"channel_id"` +} + +// Gateway Payload Structure +// https://discord.com/developers/docs/topics/gateway-events#payload-structure +type GatewayPayload struct { + SequenceNumber *int64 `json:"s"` + EventName *string `json:"t"` + Data json.RawMessage `json:"d"` + Op int `json:"op"` +} + +// Gateway URL Query String Params +// https://discord.com/developers/docs/topics/gateway#connecting-gateway-url-query-string-params +type GatewayURLQueryString struct { + Compress *string `url:"compress,omitempty"` + Encoding string `url:"encoding"` + V int `url:"v"` +} + +// Session Start Limit Structure +// https://discord.com/developers/docs/topics/gateway#session-start-limit-object-session-start-limit-structure +type SessionStartLimit struct { + Total int `json:"total"` + Remaining int `json:"remaining"` + ResetAfter int `json:"reset_after"` + MaxConcurrency int `json:"max_concurrency"` +} + +// List of Intents +// https://discord.com/developers/docs/topics/gateway#list-of-intents +const ( + // GUILD_CREATE + // GUILD_UPDATE + // GUILD_DELETE + // GUILD_ROLE_CREATE + // GUILD_ROLE_UPDATE + // GUILD_ROLE_DELETE + // CHANNEL_CREATE + // CHANNEL_UPDATE + // CHANNEL_DELETE + // CHANNEL_PINS_UPDATE + // THREAD_CREATE + // THREAD_UPDATE + // THREAD_DELETE + // THREAD_LIST_SYNC + // THREAD_MEMBER_UPDATE + // THREAD_MEMBERS_UPDATE * + // STAGE_INSTANCE_CREATE + // STAGE_INSTANCE_UPDATE + // STAGE_INSTANCE_DELETE + FlagIntentGUILDS BitFlag = 1 << 0 + + // GUILD_MEMBER_ADD + // GUILD_MEMBER_UPDATE + // GUILD_MEMBER_REMOVE + // THREAD_MEMBERS_UPDATE * + FlagIntentGUILD_MEMBERS BitFlag = 1 << 1 + + // GUILD_BAN_ADD + // GUILD_BAN_REMOVE + FlagIntentGUILD_BANS BitFlag = 1 << 2 + + // GUILD_EMOJIS_UPDATE + // GUILD_STICKERS_UPDATE + FlagIntentGUILD_EMOJIS_AND_STICKERS BitFlag = 1 << 3 + + // GUILD_INTEGRATIONS_UPDATE + // INTEGRATION_CREATE + // INTEGRATION_UPDATE + // INTEGRATION_DELETE + FlagIntentGUILD_INTEGRATIONS BitFlag = 1 << 4 + + // WEBHOOKS_UPDATE + FlagIntentGUILD_WEBHOOKS BitFlag = 1 << 5 + + // INVITE_CREATE + // INVITE_DELETE + FlagIntentGUILD_INVITES BitFlag = 1 << 6 + + // VOICE_STATE_UPDATE + FlagIntentGUILD_VOICE_STATES BitFlag = 1 << 7 + + // PRESENCE_UPDATE + FlagIntentGUILD_PRESENCES BitFlag = 1 << 8 + + // MESSAGE_CREATE + // MESSAGE_UPDATE + // MESSAGE_DELETE + // MESSAGE_DELETE_BULK + FlagIntentGUILD_MESSAGES BitFlag = 1 << 9 + + // MESSAGE_REACTION_ADD + // MESSAGE_REACTION_REMOVE + // MESSAGE_REACTION_REMOVE_ALL + // MESSAGE_REACTION_REMOVE_EMOJI + FlagIntentGUILD_MESSAGE_REACTIONS BitFlag = 1 << 10 + + // TYPING_START + FlagIntentGUILD_MESSAGE_TYPING BitFlag = 1 << 11 + FlagIntentDIRECT_MESSAGE_TYPING BitFlag = 1 << 14 + + // MESSAGE_CREATE + // MESSAGE_UPDATE + // MESSAGE_DELETE + // CHANNEL_PINS_UPDATE + FlagIntentDIRECT_MESSAGES BitFlag = 1 << 12 + + // MESSAGE_REACTION_ADD + // MESSAGE_REACTION_REMOVE + // MESSAGE_REACTION_REMOVE_ALL + // MESSAGE_REACTION_REMOVE_EMOJI + FlagIntentDIRECT_MESSAGE_REACTIONS BitFlag = 1 << 13 + + FlagIntentMESSAGE_CONTENT BitFlag = 1 << 15 + + // GUILD_SCHEDULED_EVENT_CREATE + // GUILD_SCHEDULED_EVENT_UPDATE + // GUILD_SCHEDULED_EVENT_DELETE + // GUILD_SCHEDULED_EVENT_USER_ADD + // GUILD_SCHEDULED_EVENT_USER_REMOVE + FlagIntentGUILD_SCHEDULED_EVENTS BitFlag = 1 << 16 + + // AUTO_MODERATION_RULE_CREATE + // AUTO_MODERATION_RULE_UPDATE + // AUTO_MODERATION_RULE_DELETE + FlagIntentAUTO_MODERATION_CONFIGURATION BitFlag = 1 << 20 + + // AUTO_MODERATION_ACTION_EXECUTION + FlagIntentAUTO_MODERATION_EXECUTION BitFlag = 1 << 21 +) + +// Privileged Intents +// https://discord.com/developers/docs/topics/gateway#privileged-intents +var ( + PrivilegedIntents = map[BitFlag]bool{ + FlagIntentGUILD_PRESENCES: true, + FlagIntentGUILD_MEMBERS: true, + FlagIntentMESSAGE_CONTENT: true, + } +) + +// Gateway SendEvent +// https://discord.com/developers/docs/topics/gateway-events#send-events +type SendEvent interface{} + +// Gateway SendEvent Names +// https://discord.com/developers/docs/topics/gateway-events#send-events +const ( + FlagGatewaySendEventNameHeartbeat = "Heartbeat" + FlagGatewaySendEventNameIdentify = "Identify" + FlagGatewaySendEventNameUpdatePresence = "UpdatePresence" + FlagGatewaySendEventNameUpdateVoiceState = "UpdateVoiceState " + FlagGatewaySendEventNameResume = "Resume" + FlagGatewaySendEventNameRequestGuildMembers = "RequestGuildMembers" +) + +// Identify Structure +// https://discord.com/developers/docs/topics/gateway-events#identify-identify-structure +type Identify struct { + Compress *bool `json:"compress,omitempty"` + LargeThreshold *int `json:"large_threshold,omitempty"` + Shard *[2]int `json:"shard,omitempty"` + Presence *GatewayPresenceUpdate `json:"presence,omitempty"` + Properties IdentifyConnectionProperties `json:"properties"` + Token string `json:"token"` + Intents BitFlag `json:"intents"` +} + +// Identify Connection Properties +// https://discord.com/developers/docs/topics/gateway-events#identify-identify-connection-properties +type IdentifyConnectionProperties struct { + OS string `json:"os"` + Browser string `json:"browser"` + Device string `json:"device"` +} + +// Resume Structure +// https://discord.com/developers/docs/topics/gateway-events#resume-resume-structure +type Resume struct { + Token string `json:"token"` + SessionID string `json:"session_id"` + Seq int64 `json:"seq"` +} + +// Heartbeat +// https://discord.com/developers/docs/topics/gateway-events#heartbeat +type Heartbeat struct { + Data int64 `json:"d"` +} + +// Request Guild Members Structure +// https://discord.com/developers/docs/topics/gateway-events#request-guild-members-guild-request-members-structure +type RequestGuildMembers struct { + Query *string `json:"query,omitempty"` + Presences *bool `json:"presences,omitempty"` + Nonce *string `json:"nonce,omitempty"` + GuildID string `json:"guild_id"` + UserIDs []string `json:"user_ids,omitempty"` + Limit int `json:"limit"` +} + +// Gateway Voice State Update Structure +// https://discord.com/developers/docs/topics/gateway-events#update-voice-state-gateway-voice-state-update-structure +type GatewayVoiceStateUpdate struct { + ChannelID *string `json:"channel_id"` + GuildID string `json:"guild_id"` + SelfMute bool `json:"self_mute"` + SelfDeaf bool `json:"self_deaf"` +} + +// Gateway Presence Update Structure +// https://discord.com/developers/docs/topics/gateway-events#update-presence-gateway-presence-update-structure +type GatewayPresenceUpdate struct { + Since *int `json:"since"` + Status string `json:"status"` + Game []*Activity `json:"game"` + AFK bool `json:"afk"` +} + +// Status Types +// https://discord.com/developers/docs/topics/gateway#update-presence-status-types +const ( + FlagStatusTypeOnline = "online" + FlagStatusTypeDoNotDisturb = "dnd" + FlagStatusTypeAFK = "idle" + FlagStatusTypeInvisible = "invisible" + FlagStatusTypeOffline = "offline" +) + +// Rate Limit Headers +// https://discord.com/developers/docs/topics/rate-limits#header-format-rate-limit-header-examples +const ( + FlagRateLimitHeaderDate = "Date" + FlagRateLimitHeaderLimit = "X-RateLimit-Limit" + FlagRateLimitHeaderRemaining = "X-RateLimit-Remaining" + FlagRateLimitHeaderReset = "X-RateLimit-Reset" + FlagRateLimitHeaderResetAfter = "X-RateLimit-Reset-After" + FlagRateLimitHeaderBucket = "X-RateLimit-Bucket" + FlagRateLimitHeaderGlobal = "X-RateLimit-Global" + FlagRateLimitHeaderScope = "X-RateLimit-Scope" + FlagRateLimitHeaderRetryAfter = "Retry-After" +) + +// Rate Limit Header +// https://discord.com/developers/docs/topics/rate-limits#header-format +type RateLimitHeader struct { + Scope string `http:"X-RateLimit-Scope,omitempty"` + Bucket string `http:"X-RateLimit-Bucket,omitempty"` + Remaining int `http:"X-RateLimit-Remaining,omitempty"` + Reset float64 `http:"X-RateLimit-Reset,omitempty"` + ResetAfter float64 `http:"X-RateLimit-Reset-After,omitempty"` + Limit int `http:"X-RateLimit-Limit,omitempty"` + Global bool `http:"X-RateLimit-Global,omitempty"` +} + +// Rate Limit Scope Values +// https://discord.com/developers/docs/topics/rate-limits#header-format-rate-limit-header-examples +const ( + RateLimitScopeValueUser = "user" + RateLimitScopeValueGlobal = "global" + RateLimitScopeValueShared = "shared" +) + +// Rate Limit Response Structure +// https://discord.com/developers/docs/topics/rate-limits#exceeding-a-rate-limit-rate-limit-response-structure +type RateLimitResponse struct { + Message string `json:"message"` + RetryAfter float64 `json:"retry_after"` + Global bool `json:"global"` +} + +// Global Rate Limits +// https://discord.com/developers/docs/topics/rate-limits#global-rate-limit +const ( + // Global Rate Limit (Requests): 50 requests per second. + FlagGlobalRateLimitRequest = 50 + + // Global Rate Limit (Gateway): 120 commands per minute. + FlagGlobalRateLimitGateway = 120 + FlagGlobalRateLimitGatewayInterval = time.Minute + + // Global Rate Limit (Identify Command): Get Gateway Bot `max_concurrency + 1` per 5 Seconds. + FlagGlobalRateLimitIdentifyInterval = time.Second * 5 + + // Global Rate Limit (Identify Command): 1000 per day. + FlagGlobalRateLimitIdentifyDaily = 1000 + FlagGlobalRateLimitIdentifyDailyInterval = time.Hour * 24 +) + +// Invalid Request Limit (CloudFlare Bans) +// https://discord.com/developers/docs/topics/rate-limits#invalid-request-limit-aka-cloudflare-bans +const ( + // 10,000 requests per 10 minutes. + FlagInvalidRequestRateLimit = 10000 +) + +var ( + InvalidRateLimitRequests = map[int]string{ + FlagHTTPResponseCodeUNAUTHORIZED: HTTPResponseCodes[FlagHTTPResponseCodeUNAUTHORIZED], + FlagHTTPResponseCodeFORBIDDEN: HTTPResponseCodes[FlagHTTPResponseCodeFORBIDDEN], + FlagHTTPResponseCodeTOOMANYREQUESTS: HTTPResponseCodes[FlagHTTPResponseCodeTOOMANYREQUESTS], + } +) + +// Version +// https://discord.com/developers/docs/reference#api-versioning +const ( + VersionDiscordAPI = "10" +) + +// time.Time Format +// https://discord.com/developers/docs/reference#iso8601-datetime +const ( + TimestampFormatISO8601 = time.RFC3339 +) + +// Image Formats +// https://discord.com/developers/docs/reference#image-formatting-image-formats +const ( + ImageFormatJPEG = "JPEG" + ImageFormatPNG = "PNG" + ImageFormatWebP = "WebP" + ImageFormatGIF = "GIF" + ImageFormatLottie = "Lottie" +) + +// CDN Endpoint Exceptions +// https://discord.com/developers/docs/reference#image-formatting-cdn-endpoints +const ( + CDNEndpointAnimatedHashPrefix = "a_" + CDNEndpointUserDiscriminatorDivisor = 5 +) + +// Locales +// https://discord.com/developers/docs/reference#locales +const ( + FlagLocalesDanish = "da" + FlagLocalesGerman = "de" + FlagLocalesEnglishUK = "en-GB" + FlagLocalesEnglishUS = "en-US" + FlagLocalesSpanish = "es-ES" + FlagLocalesFrench = "fr" + FlagLocalesCroatian = "hr" + FlagLocalesItalian = "it" + FlagLocalesLithuanian = "lt" + FlagLocalesHungarian = "hu" + FlagLocalesDutch = "nl" + FlagLocalesNorwegian = "no" + FlagLocalesPolish = "pl" + FlagLocalesPortugueseBrazilian = "pt-BR" + FlagLocalesRomanian = "ro" + FlagLocalesFinnish = "fi" + FlagLocalesSwedish = "sv-SE" + FlagLocalesVietnamese = "vi" + FlagLocalesTurkish = "tr" + FlagLocalesCzech = "cs" + FlagLocalesGreek = "el" + FlagLocalesBulgarian = "bg" + FlagLocalesRussian = "ru" + FlagLocalesUkrainian = "uk" + FlagLocalesHindi = "hi" + FlagLocalesThai = "th" + FlagLocalesChineseChina = "zh-CN" + FlagLocalesJapanese = "ja" + FlagLocalesChineseTaiwan = "zh-TW" + FlagLocalesKorean = "ko" +) + +// Get Global Application Commands +// GET /applications/{application.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#get-global-application-commands +type GetGlobalApplicationCommands struct { + WithLocalizations *bool `url:"with_localizations,omitempty"` +} + +// Create Global Application Command +// POST /applications/{application.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#create-global-application-command +type CreateGlobalApplicationCommand struct { + DMPermission **bool `json:"dm_permission,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + Description *string `json:"description,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + DefaultMemberPermissions **string `json:"default_member_permissions,omitempty"` + Type *Flag `json:"type,omitempty"` + Name string `json:"name,omitempty"` + Options []*ApplicationCommandOption `json:"options,omitempty"` +} + +// Get Global Application Command +// GET /applications/{application.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#get-global-application-command +type GetGlobalApplicationCommand struct { + CommandID string +} + +// Edit Global Application Command +// PATCH /applications/{application.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#edit-global-application-command +type EditGlobalApplicationCommand struct { + DefaultMemberPermissions **string `json:"default_member_permissions,omitempty"` + Name *string `json:"name,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + Description *string `json:"description,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + DMPermission **bool `json:"dm_permission,omitempty"` + CommandID string `json:"-"` + Options []*ApplicationCommandOption `json:"options,omitempty"` +} + +// Delete Global Application Command +// DELETE /applications/{application.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#delete-global-application-command +type DeleteGlobalApplicationCommand struct { + CommandID string +} + +// Bulk Overwrite Global Application Commands +// PUT /applications/{application.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-global-application-commands +type BulkOverwriteGlobalApplicationCommands struct { + ApplicationCommands []*ApplicationCommand `json:"commands"` +} + +// Get Guild Application Commands +// GET /applications/{application.id}/guilds/{guild.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#get-guild-application-commands +type GetGuildApplicationCommands struct { + WithLocalizations *bool `url:"with_localizations,omitempty"` + GuildID string `url:"-"` +} + +// Create Guild Application Command +// POST /applications/{application.id}/guilds/{guild.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#create-guild-application-command +type CreateGuildApplicationCommand struct { + DefaultMemberPermissions **string `json:"default_member_permissions,omitempty"` + Type *Flag `json:"type,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + Description *string `json:"description,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + GuildID string `json:"-"` + Name string `json:"name"` + Options []*ApplicationCommandOption `json:"options,omitempty"` +} + +// Get Guild Application Command +// GET /applications/{application.id}/guilds/{guild.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command +type GetGuildApplicationCommand struct { + GuildID string + CommandID string +} + +// Edit Guild Application Command +// PATCH /applications/{application.id}/guilds/{guild.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#edit-guild-application-command +type EditGuildApplicationCommand struct { + DefaultMemberPermissions **string `json:"default_member_permissions,omitempty"` + Name *string `json:"name,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + Description *string `json:"description,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + GuildID string `json:"-"` + CommandID string `json:"-"` + Options []*ApplicationCommandOption `json:"options,omitempty"` +} + +// Delete Guild Application Command +// DELETE /applications/{application.id}/guilds/{guild.id}/commands/{command.id} +// https://discord.com/developers/docs/interactions/application-commands#delete-guild-application-command +type DeleteGuildApplicationCommand struct { + GuildID string + CommandID string +} + +// Bulk Overwrite Guild Application Commands +// PUT /applications/{application.id}/guilds/{guild.id}/commands +// https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-guild-application-commands +type BulkOverwriteGuildApplicationCommands struct { + GuildID string `json:"-"` + ApplicationCommands []*ApplicationCommand `json:"commands"` +} + +// Get Guild Application Command Permissions +// GET /applications/{application.id}/guilds/{guild.id}/commands/permissions +// https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions +type GetGuildApplicationCommandPermissions struct { + GuildID string +} + +// Get Application Command Permissions +// GET /applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions +// https://discord.com/developers/docs/interactions/application-commands#get-application-command-permissions +type GetApplicationCommandPermissions struct { + GuildID string + CommandID string +} + +// Edit Application Command Permissions +// PUT /applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions +// https://discord.com/developers/docs/interactions/application-commands#edit-application-command-permissions +type EditApplicationCommandPermissions struct { + GuildID string `json:"-"` + CommandID string `json:"-"` + Permissions []*ApplicationCommandPermissions `json:"permissions"` +} + +// Batch Edit Application Command Permissions +// PUT /applications/{application.id}/guilds/{guild.id}/commands/permissions +// https://discord.com/developers/docs/interactions/application-commands#batch-edit-application-command-permissions +type BatchEditApplicationCommandPermissions struct { + GuildID string +} + +// Create Interaction Response +// POST /interactions/{interaction.id}/{interaction.token}/callback +// https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response +type CreateInteractionResponse struct { + *InteractionResponse + InteractionID string + InteractionToken string +} + +// Get Original Interaction Response +// GET /webhooks/{application.id}/{interaction.token}/messages/@original +// https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response +type GetOriginalInteractionResponse struct { + ThreadID *string `url:"thread_id,omitempty"` + InteractionToken string `url:"-"` +} + +// Edit Original Interaction Response +// PATCH /webhooks/{application.id}/{interaction.token}/messages/@original +// https://discord.com/developers/docs/interactions/receiving-and-responding#edit-original-interaction-response +type EditOriginalInteractionResponse struct { + AllowedMentions **AllowedMentions `json:"allowed_mentions,omitempty" url:"-"` + ThreadID *string `json:"-" url:"thread_id,omitempty"` + Content **string `json:"content,omitempty" url:"-"` + Embeds *[]*Embed `json:"embeds,omitempty" url:"-"` + Components *[]Component `json:"components,omitempty" url:"-"` + Attachments *[]*Attachment `json:"attachments,omitempty" url:"-"` + ApplicationID string `json:"-" url:"-"` + InteractionToken string `json:"-" url:"-"` + Files []*File `json:"-" url:"-" dasgo:"files"` +} + +// Delete Original Interaction Response +// DELETE /webhooks/{application.id}/{interaction.token}/messages/@original +// https://discord.com/developers/docs/interactions/receiving-and-responding#delete-original-interaction-response +type DeleteOriginalInteractionResponse struct { + InteractionToken string +} + +// Create Followup Message +// POST /webhooks/{application.id}/{interaction.token} +// https://discord.com/developers/docs/interactions/receiving-and-responding#create-followup-message +type CreateFollowupMessage struct { + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty" url:"-"` + Flags *BitFlag `json:"flags,omitempty" url:"-"` + ThreadID *string `json:"-" url:"thread_id,omitempty"` + Content *string `json:"content,omitempty" url:"-"` + Username *string `json:"username,omitempty" url:"-"` + AvatarURL *string `json:"avatar_url,omitempty" url:"-"` + TTS *bool `json:"tts,omitempty" url:"-"` + ThreadName *string `json:"thread_name,omitempty" url:"-"` + ApplicationID string `json:"-" url:"-"` + InteractionToken string `json:"-" url:"-"` + Files []*File `json:"-" url:"-" dasgo:"files"` + Attachments []*Attachment `json:"attachments,omitempty" url:"-"` + Components []Component `json:"components,omitempty" url:"-"` + Embeds []*Embed `json:"embeds,omitempty" url:"-"` +} + +// Get Followup Message +// GET /webhooks/{application.id}/{interaction.token}/messages/{message.id} +// https://discord.com/developers/docs/interactions/receiving-and-responding#get-followup-message +type GetFollowupMessage struct { + ThreadID *string `url:"thread_id,omitempty"` + InteractionToken string `url:"-"` + MessageID string `url:"-"` +} + +// Edit Followup Message +// PATCH /webhooks/{application.id}/{interaction.token}/messages/{message.id} +// https://discord.com/developers/docs/interactions/receiving-and-responding#edit-followup-message +type EditFollowupMessage struct { + Components *[]Component `json:"components,omitempty" url:"-"` + AllowedMentions **AllowedMentions `json:"allowed_mentions,omitempty" url:"-"` + ThreadID *string `json:"-" url:"thread_id,omitempty"` + Content **string `json:"content,omitempty" url:"-"` + Embeds *[]*Embed `json:"embeds,omitempty" url:"-"` + Attachments *[]*Attachment `json:"attachments,omitempty" url:"-"` + InteractionToken string `json:"-" url:"-"` + ApplicationID string `json:"-" url:"-"` + MessageID string `json:"-" url:"-"` + Files []*File `json:"-" url:"-" dasgo:"files"` +} + +// Delete Followup Message +// DELETE /webhooks/{application.id}/{interaction.token}/messages/{message.id} +// https://discord.com/developers/docs/interactions/receiving-and-responding#delete-followup-message +type DeleteFollowupMessage struct { + InteractionToken string + MessageID string +} + +// Get Guild Audit Log +// GET /guilds/{guild.id}/audit-logs +// https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log +type GetGuildAuditLog struct { + GuildID string `url:"-"` + + // https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events + UserID string `url:"user_id,omitempty"` + Before string `url:"before,omitempty"` + Limit int `url:"limit,omitempty"` + ActionType Flag `url:"action_type,omitempty"` +} + +// List Auto Moderation Rules for Guild +// GET /guilds/{guild.id}/auto-moderation/rules +// https://discord.com/developers/docs/resources/auto-moderation#list-auto-moderation-rules-for-guild +type ListAutoModerationRulesForGuild struct { + GuildID string +} + +// Get Auto Moderation Rule +// GET /guilds/{guild.id}/auto-moderation/rules/{auto_moderation_rule.id} +// https://discord.com/developers/docs/resources/auto-moderation#get-auto-moderation-rule +type GetAutoModerationRule struct { + GuildID string + AutoModerationRuleID string +} + +// Create Auto Moderation Rule +// POST /guilds/{guild.id}/auto-moderation/rules +// https://discord.com/developers/docs/resources/auto-moderation#create-auto-moderation-rule +type CreateAutoModerationRule struct { + Enabled *bool `json:"enabled,omitempty"` + TriggerMetadata *TriggerMetadata `json:"trigger_metadata,omitempty"` + Name string `json:"name"` + GuildID string `json:"-"` + ExemptChannels []string `json:"exempt_channels,omitempty"` + Actions []*AutoModerationAction `json:"actions"` + ExemptRoles []string `json:"exempt_roles,omitempty"` + TriggerType Flag `json:"trigger_type"` + EventType Flag `json:"event_type"` +} + +// Modify Auto Moderation Rule +// PATCH /guilds/{guild.id}/auto-moderation/rules/{auto_moderation_rule.id} +// https://discord.com/developers/docs/resources/auto-moderation#modify-auto-moderation-rule +type ModifyAutoModerationRule struct { + GuildID string `json:"-"` + AutoModerationRuleID string `json:"-"` + Name *string `json:"name,omitempty"` + EventType *Flag `json:"event_type,omitempty"` + TriggerType *Flag `json:"trigger_type,omitempty"` + TriggerMetadata *TriggerMetadata `json:"trigger_metadata,omitempty"` + Actions []*AutoModerationAction `json:"actions,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + ExemptRoles []string `json:"exempt_roles,omitempty"` + ExemptChannels []string `json:"exempt_channels,omitempty"` +} + +// Delete Auto Moderation Rule +// DELETE /guilds/{guild.id}/auto-moderation/rules/{auto_moderation_rule.id} +// https://discord.com/developers/docs/resources/auto-moderation#delete-auto-moderation-rule +type DeleteAutoModerationRule struct { + GuildID string + AutoModerationRuleID string +} + +// Get Channel +// GET /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#get-channel +type GetChannel struct { + ChannelID string +} + +// Modify Channel +// PATCH /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#modify-channel +type ModifyChannel struct { + ChannelID string +} + +// Modify Channel Group DM +// PATCH /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#modify-channel-json-params-group-dm +type ModifyChannelGroupDM struct { + Name *string `json:"name,omitempty"` + Icon *string `json:"icon,omitempty"` + ChannelID string `json:"-"` +} + +// Modify Channel Guild +// PATCH /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#modify-channel-json-params-guild-channel +type ModifyChannelGuild struct { + DefaultSortOrder **int `json:"default_sort_order,omitempty"` + Name *string `json:"name,omitempty"` + Type *Flag `json:"type,omitempty"` + Position **int `json:"position,omitempty"` + Topic **string `json:"topic,omitempty"` + NSFW **bool `json:"nsfw,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + Bitrate **int `json:"bitrate,omitempty"` + UserLimit **int `json:"user_limit,omitempty"` + PermissionOverwrites *[]*PermissionOverwrite `json:"permission_overwrites,omitempty"` + ParentID **string `json:"parent_id,omitempty"` + RTCRegion **string `json:"rtc_region,omitempty"` + VideoQualityMode **Flag `json:"video_quality_mode,omitempty"` + DefaultAutoArchiveDuration **int `json:"default_auto_archive_duration,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` + DefaultReactionEmoji **DefaultReaction `json:"default_reaction_emoji,omitempty"` + ChannelID string `json:"-"` + AvailableTags []*ForumTag `json:"available_tags,omitempty"` +} + +// Modify Channel +// PATCH /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#modify-channel-json-params-thread +type ModifyChannelThread struct { + ChannelID string `json:"-"` + Name *string `json:"name,omitempty"` + Archived *bool `json:"archived,omitempty"` + AutoArchiveDuration *int `json:"auto_archive_duration,omitempty"` + Locked *bool `json:"locked,omitempty"` + Invitable *bool `json:"invitable,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + AppliedTags []string `json:"applied_tags,omitempty"` +} + +// Delete/Close Channel +// DELETE /channels/{channel.id} +// https://discord.com/developers/docs/resources/channel#deleteclose-channel +type DeleteCloseChannel struct { + ChannelID string +} + +// Get Channel Messages +// GET /channels/{channel.id}/messages +// https://discord.com/developers/docs/resources/channel#get-channel-messages +type GetChannelMessages struct { + Around *string `url:"around,omitempty"` + Before *string `url:"before,omitempty"` + After *string `url:"after,omitempty"` + Limit *Flag `url:"limit,omitempty"` + ChannelID string `url:"-"` +} + +// Get Channel Message +// GET /channels/{channel.id}/messages/{message.id} +// https://discord.com/developers/docs/resources/channel#get-channel-message +type GetChannelMessage struct { + ChannelID string + MessageID string +} + +// Create Message +// POST /channels/{channel.id}/messages +// https://discord.com/developers/docs/resources/channel#create-message +type CreateMessage struct { + MessageReference *MessageReference `json:"message_reference,omitempty"` + Content *string `json:"content,omitempty"` + Nonce *Nonce `json:"nonce,omitempty"` + TTS *bool `json:"tts,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + ChannelID string `json:"-"` + Embeds []*Embed `json:"embeds,omitempty"` + Components []Component `json:"components,omitempty"` + StickerIDS []*string `json:"sticker_ids,omitempty"` + Files []*File `json:"-" dasgo:"files,omitempty"` + Attachments []*Attachment `json:"attachments,omitempty"` +} + +// Crosspost Message +// POST /channels/{channel.id}/messages/{message.id}/crosspost +// https://discord.com/developers/docs/resources/channel#crosspost-message +type CrosspostMessage struct { + ChannelID string + MessageID string +} + +// Create Reaction +// PUT /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me +// https://discord.com/developers/docs/resources/channel#create-reaction +type CreateReaction struct { + ChannelID string + MessageID string + Emoji string +} + +// Delete Own Reaction +// DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me +// https://discord.com/developers/docs/resources/channel#delete-own-reaction +type DeleteOwnReaction struct { + ChannelID string + MessageID string + Emoji string +} + +// Delete User Reaction +// DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji}/{user.id} +// https://discord.com/developers/docs/resources/channel#delete-user-reaction +type DeleteUserReaction struct { + ChannelID string + MessageID string + Emoji string + UserID string +} + +// Get Reactions +// GET /channels/{channel.id}/messages/{message.id}/reactions/{emoji} +// https://discord.com/developers/docs/resources/channel#get-reactions +type GetReactions struct { + After *string `url:"after,omitempty"` + Limit *int `url:"limit,omitempty"` + ChannelID string `url:"-"` + MessageID string `url:"-"` + Emoji string `url:"-"` +} + +// Delete All Reactions +// DELETE /channels/{channel.id}/messages/{message.id}/reactions +// https://discord.com/developers/docs/resources/channel#delete-all-reactions +type DeleteAllReactions struct { + ChannelID string + MessageID string +} + +// Delete All Reactions for Emoji +// DELETE /channels/{channel.id}/messages/{message.id}/reactions/{emoji} +// https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji +type DeleteAllReactionsforEmoji struct { + ChannelID string + MessageID string + Emoji string +} + +// Edit Message +// PATCH /channels/{channel.id}/messages/{message.id} +// https://discord.com/developers/docs/resources/channel#edit-message +type EditMessage struct { + Components *[]Component `json:"components,omitempty"` + Content **string `json:"content,omitempty"` + Embeds *[]*Embed `json:"embeds,omitempty"` + Flags **BitFlag `json:"flags,omitempty"` + AllowedMentions **AllowedMentions `json:"allowed_mentions,omitempty"` + Attachments *[]*Attachment `json:"attachments,omitempty"` + MessageID string `json:"-"` + ChannelID string `json:"-"` + Files []*File `json:"-" dasgo:"files"` +} + +// Delete Message +// DELETE /channels/{channel.id}/messages/{message.id} +// https://discord.com/developers/docs/resources/channel#delete-message +type DeleteMessage struct { + ChannelID string + MessageID string +} + +// Bulk Delete Messages +// POST /channels/{channel.id}/messages/bulk-delete +// https://discord.com/developers/docs/resources/channel#bulk-delete-messages +type BulkDeleteMessages struct { + ChannelID string `json:"-"` + Messages []*string `json:"messages"` +} + +// Edit Channel Permissions +// PUT /channels/{channel.id}/permissions/{overwrite.id} +// https://discord.com/developers/docs/resources/channel#edit-channel-permissions +type EditChannelPermissions struct { + Allow **string `json:"allow,omitempty"` + Deny **string `json:"deny,omitempty"` + ChannelID string `json:"-"` + OverwriteID string `json:"-"` + Type Flag `json:"type"` +} + +// Get Channel Invites +// GET /channels/{channel.id}/invites +// https://discord.com/developers/docs/resources/channel#get-channel-invites +type GetChannelInvites struct { + ChannelID string +} + +// Create Channel Invite +// POST /channels/{channel.id}/invites +// https://discord.com/developers/docs/resources/channel#create-channel-invite +type CreateChannelInvite struct { + MaxAge *int `json:"max_age"` + MaxUses *int `json:"max_uses"` + ChannelID string `json:"-"` + TargetUserID string `json:"target_user_id"` + TargetApplicationID string `json:"target_application_id"` + Temporary bool `json:"temporary"` + Unique bool `json:"unique"` + TargetType Flag `json:"target_type"` +} + +// Delete Channel Permission +// DELETE /channels/{channel.id}/permissions/{overwrite.id} +// https://discord.com/developers/docs/resources/channel#delete-channel-permission +type DeleteChannelPermission struct { + ChannelID string + OverwriteID string +} + +// Follow Announcement Channel +// POST /channels/{channel.id}/followers +// https://discord.com/developers/docs/resources/channel#follow-announcement-channel +type FollowAnnouncementChannel struct { + ChannelID string `json:"-"` + WebhookChannelID string `json:"webhook_channel_id"` +} + +// Trigger Typing Indicator +// POST /channels/{channel.id}/typing +// https://discord.com/developers/docs/resources/channel#trigger-typing-indicator +type TriggerTypingIndicator struct { + ChannelID string +} + +// Get Pinned Messages +// GET /channels/{channel.id}/pins +// https://discord.com/developers/docs/resources/channel#get-pinned-messages +type GetPinnedMessages struct { + ChannelID string +} + +// Pin Message +// PUT /channels/{channel.id}/pins/{message.id} +// https://discord.com/developers/docs/resources/channel#pin-message +type PinMessage struct { + ChannelID string + MessageID string +} + +// Unpin Message +// DELETE /channels/{channel.id}/pins/{message.id} +// https://discord.com/developers/docs/resources/channel#unpin-message +type UnpinMessage struct { + ChannelID string + MessageID string +} + +// Group DM Add Recipient +// PUT /channels/{channel.id}/recipients/{user.id} +// https://discord.com/developers/docs/resources/channel#group-dm-add-recipient +type GroupDMAddRecipient struct { + Nickname *string `json:"nick"` + ChannelID string `json:"-"` + UserID string `json:"-"` + AccessToken string `json:"access_token"` +} + +// Group DM Remove Recipient +// DELETE /channels/{channel.id}/recipients/{user.id} +// https://discord.com/developers/docs/resources/channel#group-dm-remove-recipient +type GroupDMRemoveRecipient struct { + ChannelID string + UserID string +} + +// Start Thread from Message +// POST /channels/{channel.id}/messages/{message.id}/threads +// https://discord.com/developers/docs/resources/channel#start-thread-from-message +type StartThreadfromMessage struct { + AutoArchiveDuration *int `json:"auto_archive_duration,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + ChannelID string `json:"-"` + MessageID string `json:"-"` + Name string `json:"name"` +} + +// Start Thread without Message +// POST /channels/{channel.id}/threads +// https://discord.com/developers/docs/resources/channel#start-thread-without-message +type StartThreadwithoutMessage struct { + AutoArchiveDuration *int `json:"auto_archive_duration,omitempty"` + Type *Flag `json:"type,omitempty"` + Invitable *bool `json:"invitable,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + ChannelID string `json:"-"` + Name string `json:"name"` +} + +// Start Thread in Forum Channel +// POST /channels/{channel.id}/threads +// https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel +type StartThreadinForumChannel struct { + ChannelID string `json:"-"` + Name string `json:"name"` + AutoArchiveDuration *int `json:"auto_archive_duration,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + Message *ForumThreadMessageParams `json:"message"` + AppliedTags []string `json:"applied_tags,omitempty"` +} + +// Forum Thread Message Params Object +// https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel-forum-thread-message-params-object +type ForumThreadMessageParams struct { + Content *string `json:"content,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Components []Component `json:"components,omitempty"` + StickerIDS []*string `json:"sticker_ids,omitempty"` + Attachments []*Attachment `json:"attachments,omitempty"` + Files []*File `json:"-" dasgo:"files"` + Embeds []*Embed `json:"embeds,omitempty"` +} + +// Join Thread +// PUT /channels/{channel.id}/thread-members/@me +// https://discord.com/developers/docs/resources/channel#join-thread +type JoinThread struct { + ChannelID string +} + +// Add Thread Member +// PUT /channels/{channel.id}/thread-members/{user.id} +// https://discord.com/developers/docs/resources/channel#add-thread-member +type AddThreadMember struct { + ChannelID string + UserID string +} + +// Leave Thread +// DELETE /channels/{channel.id}/thread-members/@me +// https://discord.com/developers/docs/resources/channel#leave-thread +type LeaveThread struct { + ChannelID string +} + +// Remove Thread Member +// DELETE /channels/{channel.id}/thread-members/{user.id} +// https://discord.com/developers/docs/resources/channel#remove-thread-member +type RemoveThreadMember struct { + ChannelID string + UserID string +} + +// Get Thread Member +// GET /channels/{channel.id}/thread-members/{user.id} +// https://discord.com/developers/docs/resources/channel#get-thread-member +type GetThreadMember struct { + ChannelID string + UserID string +} + +// List Thread Members +// GET /channels/{channel.id}/thread-members +// https://discord.com/developers/docs/resources/channel#list-thread-members +type ListThreadMembers struct { + ChannelID string +} + +// List Public Archived Threads +// GET /channels/{channel.id}/threads/archived/public +// https://discord.com/developers/docs/resources/channel#list-public-archived-threads +type ListPublicArchivedThreads struct { + Before *time.Time `url:"before,omitempty"` + Limit *int `url:"limit,omitempty"` + ChannelID string `url:"-"` +} + +// List Private Archived Threads +// GET /channels/{channel.id}/threads/archived/private +// https://discord.com/developers/docs/resources/channel#list-private-archived-threads +type ListPrivateArchivedThreads struct { + Before *time.Time `url:"before,omitempty"` + Limit *int `url:"limit,omitempty"` + ChannelID string `url:"-"` +} + +// List Joined Private Archived Threads +// GET /channels/{channel.id}/users/@me/threads/archived/private +// https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads +type ListJoinedPrivateArchivedThreads struct { + Before *time.Time `url:"before,omitempty"` + Limit *int `url:"limit,omitempty"` + ChannelID string `url:"-"` +} + +// List Guild Emojis +// GET /guilds/{guild.id}/emojis +// https://discord.com/developers/docs/resources/emoji#list-guild-emojis +type ListGuildEmojis struct { + GuildID string +} + +// Get Guild Emoji +// GET /guilds/{guild.id}/emojis/{emoji.id} +// https://discord.com/developers/docs/resources/emoji#get-guild-emoji +type GetGuildEmoji struct { + GuildID string + EmojiID string +} + +// Create Guild Emoji +// POST /guilds/{guild.id}/emojis +// https://discord.com/developers/docs/resources/emoji#create-guild-emoji +type CreateGuildEmoji struct { + GuildID string `json:"-"` + Name string `json:"name"` + Image string `json:"image"` + Roles []*string `json:"roles"` +} + +// Modify Guild Emoji +// PATCH /guilds/{guild.id}/emojis/{emoji.id} +// https://discord.com/developers/docs/resources/emoji#modify-guild-emoji +type ModifyGuildEmoji struct { + Name *string `json:"name,omitempty"` + Roles *[]*string `json:"roles,omitempty"` + GuildID string `json:"-"` + EmojiID string `json:"-"` +} + +// Delete Guild Emoji +// DELETE /guilds/{guild.id}/emojis/{emoji.id} +// https://discord.com/developers/docs/resources/emoji#delete-guild-emoji +type DeleteGuildEmoji struct { + GuildID string + EmojiID string +} + +// Create Guild +// POST /guilds +// https://discord.com/developers/docs/resources/guild#create-guild +type CreateGuild struct { + Region **string `json:"region,omitempty"` + Icon *string `json:"icon,omitempty"` + VerificationLevel *Flag `json:"verification_level,omitempty"` + DefaultMessageNotifications *Flag `json:"default_message_notifications,omitempty"` + ExplicitContentFilter *Flag `json:"explicit_content_filter,omitempty"` + AfkChannelID *string `json:"afk_channel_id,omitempty"` + AfkTimeout *int `json:"afk_timeout,omitempty"` + SystemChannelID *string `json:"system_channel_id,omitempty"` + SystemChannelFlags *BitFlag `json:"system_channel_flags,omitempty"` + Name string `json:"name"` + Roles []*Role `json:"roles,omitempty"` + Channels []*Channel `json:"channels,omitempty"` +} + +// Get Guild +// GET /guilds/{guild.id} +// https://discord.com/developers/docs/resources/guild#get-guild +type GetGuild struct { + WithCounts *bool `url:"with_counts,omitempty"` + GuildID string `url:"-"` +} + +// Get Guild Preview +// GET /guilds/{guild.id}/preview +// https://discord.com/developers/docs/resources/guild#get-guild-preview +type GetGuildPreview struct { + GuildID string +} + +// Modify Guild +// PATCH /guilds/{guild.id} +// https://discord.com/developers/docs/resources/guild#modify-guild +type ModifyGuild struct { + PremiumProgressBarEnabled *bool `json:"premium_progress_bar_enabled,omitempty"` + Name *string `json:"name,omitempty"` + VerificationLevel **Flag `json:"verification_level,omitempty"` + DefaultMessageNotifications **Flag `json:"default_message_notifications,omitempty"` + ExplicitContentFilter **Flag `json:"explicit_content_filter,omitempty"` + AFKChannelID **string `json:"afk_channel_id,omitempty"` + Description **string `json:"description,omitempty"` + Icon **string `json:"icon,omitempty"` + PreferredLocale **string `json:"preferred_locale,omitempty"` + Splash **string `json:"splash,omitempty"` + DiscoverySplash **string `json:"discovery_splash,omitempty"` + Banner **string `json:"banner,omitempty"` + SystemChannelID **string `json:"system_channel_id,omitempty"` + SystemChannelFlags *BitFlag `json:"system_channel_flags,omitempty"` + RulesChannelID **string `json:"rules_channel_id,omitempty"` + PublicUpdatesChannelID **string `json:"public_updates_channel_id,omitempty"` + OwnerID string `json:"owner_id,omitempty"` + GuildID string `json:"-"` + Features []*string `json:"features,omitempty"` + AfkTimeout int `json:"afk_timeout,omitempty"` +} + +// Delete Guild +// DELETE /guilds/{guild.id} +// https://discord.com/developers/docs/resources/guild#delete-guild +type DeleteGuild struct { + GuildID string +} + +// Get Guild Channels +// GET /guilds/{guild.id}/channels +// https://discord.com/developers/docs/resources/guild#get-guild-channels +type GetGuildChannels struct { + GuildID string +} + +// Create Guild Channel +// POST /guilds/{guild.id}/channels +// https://discord.com/developers/docs/resources/guild#create-guild-channel +type CreateGuildChannel struct { + DefaultSortOrder **int `json:"default_sort_order,omitempty"` + AvailableTags *[]*ForumTag `json:"available_tags,omitempty"` + Type **Flag `json:"type,omitempty"` + Topic **string `json:"topic,omitempty"` + Bitrate **int `json:"bitrate,omitempty"` + UserLimit **int `json:"user_limit,omitempty"` + RateLimitPerUser **int `json:"rate_limit_per_user,omitempty"` + Position **int `json:"position,omitempty"` + PermissionOverwrites *[]*PermissionOverwrite `json:"permission_overwrites,omitempty"` + ParentID **string `json:"parent_id,omitempty"` + NSFW **bool `json:"nsfw,omitempty"` + RTCRegion **string `json:"rtc_region,omitempty"` + VideoQualityMode **Flag `json:"video_quality_mode,omitempty"` + DefaultAutoArchiveDuration **int `json:"default_auto_archive_duration,omitempty"` + DefaultReactionEmoji **DefaultReaction `json:"default_reaction_emoji,omitempty"` + Name string `json:"name"` + GuildID string `json:"-"` +} + +// Modify Guild Channel Positions +// PATCH /guilds/{guild.id}/channels +// https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions +type ModifyGuildChannelPositions struct { + GuildID string `json:"-"` + Parameters []*ModifyGuildChannelPositionParameters `json:"parameters"` +} + +// Modify Guild Channel Position Parameters +// https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions-json-params +type ModifyGuildChannelPositionParameters struct { + Position *int `json:"position"` + LockPermissions *bool `json:"lock_permissions"` + ParentID *string `json:"parent_id"` + ID string `json:"id"` +} + +// List Active Guild Threads +// GET /guilds/{guild.id}/threads/active +// https://discord.com/developers/docs/resources/guild#list-active-guild-threads +type ListActiveGuildThreads struct { + GuildID string `json:"-"` +} + +// Get Guild Member +// GET /guilds/{guild.id}/members/{user.id} +// https://discord.com/developers/docs/resources/guild#get-guild-member +type GetGuildMember struct { + GuildID string + UserID string +} + +// List Guild Members +// GET /guilds/{guild.id}/members +// https://discord.com/developers/docs/resources/guild#list-guild-members +type ListGuildMembers struct { + Limit *int `url:"limit,omitempty"` + After *string `url:"after,omitempty"` + GuildID string `url:"-"` +} + +// Search Guild Members +// GET /guilds/{guild.id}/members/search +// https://discord.com/developers/docs/resources/guild#search-guild-members +type SearchGuildMembers struct { + Limit *int `url:"limit,omitempty"` + GuildID string `url:"-"` + Query string `url:"query"` +} + +// Add Guild Member +// PUT /guilds/{guild.id}/members/{user.id} +// https://discord.com/developers/docs/resources/guild#add-guild-member +type AddGuildMember struct { + Deaf *bool `json:"deaf,omitempty"` + Nick *string `json:"nick,omitempty"` + Mute *bool `json:"mute,omitempty"` + UserID string `json:"-"` + AccessToken string `json:"access_token"` + GuildID string `json:"-"` + Roles []string `json:"roles,omitempty"` +} + +// Modify Guild Member +// PATCH /guilds/{guild.id}/members/{user.id} +// https://discord.com/developers/docs/resources/guild#modify-guild-member +type ModifyGuildMember struct { + ChannelID **string `json:"channel_id,omitempty"` + CommunicationDisabledUntil **time.Time `json:"communication_disabled_until,omitempty"` + Nick **string `json:"nick,omitempty"` + Roles *[]string `json:"roles,omitempty"` + Mute **bool `json:"mute,omitempty"` + Deaf **bool `json:"deaf,omitempty"` + GuildID string `json:"-"` + UserID string `json:"-"` +} + +// Modify Current Member +// PATCH /guilds/{guild.id}/members/@me +// https://discord.com/developers/docs/resources/guild#modify-current-member +type ModifyCurrentMember struct { + Nick **string `json:"nick,omitempty"` + GuildID string `json:"-"` +} + +// Add Guild Member Role +// PUT /guilds/{guild.id}/members/{user.id}/roles/{role.id} +// https://discord.com/developers/docs/resources/guild#add-guild-member-role +type AddGuildMemberRole struct { + GuildID string + UserID string + RoleID string +} + +// Remove Guild Member Role +// DELETE /guilds/{guild.id}/members/{user.id}/roles/{role.id} +// https://discord.com/developers/docs/resources/guild#remove-guild-member-role +type RemoveGuildMemberRole struct { + GuildID string + UserID string + RoleID string +} + +// Remove Guild Member +// DELETE /guilds/{guild.id}/members/{user.id} +// https://discord.com/developers/docs/resources/guild#remove-guild-member +type RemoveGuildMember struct { + GuildID string + UserID string +} + +// Get Guild Bans +// GET /guilds/{guild.id}/bans +// https://discord.com/developers/docs/resources/guild#get-guild-bans +type GetGuildBans struct { + Limit *int `url:"limit,omitempty"` + Before *string `url:"before,omitempty"` + After *string `url:"after,omitempty"` + GuildID string `url:"-"` +} + +// Get Guild Ban +// GET /guilds/{guild.id}/bans/{user.id} +// https://discord.com/developers/docs/resources/guild#get-guild-ban +type GetGuildBan struct { + GuildID string + UserID string +} + +// Create Guild Ban +// PUT /guilds/{guild.id}/bans/{user.id} +// https://discord.com/developers/docs/resources/guild#create-guild-ban +type CreateGuildBan struct { + DeleteMessageSeconds *int `json:"delete_message_seconds,omitempty"` + GuildID string `json:"-"` + UserID string `json:"-"` +} + +// Remove Guild Ban +// DELETE /guilds/{guild.id}/bans/{user.id} +// https://discord.com/developers/docs/resources/guild#remove-guild-ban +type RemoveGuildBan struct { + GuildID string + UserID string +} + +// Get Guild Roles +// GET /guilds/{guild.id}/roles +// https://discord.com/developers/docs/resources/guild#get-guild-roles +type GetGuildRoles struct { + GuildID string +} + +// Create Guild Role +// POST /guilds/{guild.id}/roles +// https://discord.com/developers/docs/resources/guild#create-guild-role +type CreateGuildRole struct { + UnicodeEmoji **string `json:"unicode_emoji,omitempty"` + Name *string `json:"name,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Color *int `json:"color,omitempty"` + Hoist *bool `json:"hoist,omitempty"` + Icon **string `json:"icon,omitempty"` + Mentionable *bool `json:"mentionable,omitempty"` + GuildID string `json:"-"` +} + +// Modify Guild Role Positions +// PATCH /guilds/{guild.id}/roles +// https://discord.com/developers/docs/resources/guild#modify-guild-role-positions +type ModifyGuildRolePositions struct { + GuildID string `json:"-"` + Parameters []*ModifyGuildRolePositionParameters `json:"parameters"` +} + +// Modify Guild Role Position Parameters +// https://discord.com/developers/docs/resources/guild#create-guild-role-json-params +type ModifyGuildRolePositionParameters struct { + Position **int `json:"position,omitempty"` + ID string `json:"id"` +} + +// Modify Guild Role +// PATCH /guilds/{guild.id}/roles/{role.id} +// https://discord.com/developers/docs/resources/guild#modify-guild-role +type ModifyGuildRole struct { + Icon **string `json:"icon,omitempty"` + UnicodeEmoji **string `json:"unicode_emoji,omitempty"` + Name **string `json:"name,omitempty"` + Permissions **string `json:"permissions,omitempty"` + Color **int `json:"color,omitempty"` + Hoist **bool `json:"hoist,omitempty"` + Mentionable **bool `json:"mentionable,omitempty"` + GuildID string `json:"-"` + RoleID string `json:"-"` +} + +// Modify Guild MFA Level +// POST /guilds/{guild.id}/mfa +// https://discord.com/developers/docs/resources/guild#modify-guild-mfa-level +type ModifyGuildMFALevel struct { + GuildID string `json:"-"` + Level Flag `json:"level"` +} + +// Delete Guild Role +// DELETE /guilds/{guild.id}/roles/{role.id} +// https://discord.com/developers/docs/resources/guild#delete-guild-role +type DeleteGuildRole struct { + GuildID string + RoleID string +} + +// Get Guild Prune Count +// GET /guilds/{guild.id}/prune +// https://discord.com/developers/docs/resources/guild#get-guild-prune-count +type GetGuildPruneCount struct { + GuildID string `url:"-"` + IncludeRoles []string `url:"include_roles,omitempty"` + Days int `url:"days,omitempty"` +} + +// Begin Guild Prune +// POST /guilds/{guild.id}/prune +// https://discord.com/developers/docs/resources/guild#begin-guild-prune +type BeginGuildPrune struct { + GuildID string `json:"-"` + IncludeRoles []string `json:"include_roles"` + Days int `json:"days"` + ComputePruneCount bool `json:"compute_prune_count"` +} + +// Get Guild Voice Regions +// GET /guilds/{guild.id}/regions +// https://discord.com/developers/docs/resources/guild#get-guild-voice-regions +type GetGuildVoiceRegions struct { + GuildID string +} + +// Get Guild Invites +// GET /guilds/{guild.id}/invites +// https://discord.com/developers/docs/resources/guild#get-guild-invites +type GetGuildInvites struct { + GuildID string +} + +// Get Guild Integrations +// GET /guilds/{guild.id}/integrations +// https://discord.com/developers/docs/resources/guild#get-guild-integrations +type GetGuildIntegrations struct { + GuildID string +} + +// Delete Guild Integration +// DELETE /guilds/{guild.id}/integrations/{integration.id} +// https://discord.com/developers/docs/resources/guild#delete-guild-integration +type DeleteGuildIntegration struct { + GuildID string + IntegrationID string +} + +// Get Guild Widget Settings +// GET /guilds/{guild.id}/widget +// https://discord.com/developers/docs/resources/guild#get-guild-widget-settings +type GetGuildWidgetSettings struct { + GuildID string +} + +// Modify Guild Widget +// PATCH /guilds/{guild.id}/widget +// https://discord.com/developers/docs/resources/guild#modify-guild-widget +type ModifyGuildWidget struct { + GuildID string +} + +// Get Guild Widget +// GET /guilds/{guild.id}/widget.json +// https://discord.com/developers/docs/resources/guild#get-guild-widget +type GetGuildWidget struct { + GuildID string +} + +// Get Guild Vanity URL +// GET /guilds/{guild.id}/vanity-url +// https://discord.com/developers/docs/resources/guild#get-guild-vanity-url +type GetGuildVanityURL struct { + Code *string `json:"code"` + GuildID string `json:"-"` + Uses int `json:"uses,omitempty"` +} + +// Get Guild Widget Image +// GET /guilds/{guild.id}/widget.png +// https://discord.com/developers/docs/resources/guild#get-guild-widget-image +type GetGuildWidgetImage struct { + // Widget Style Options + // https://discord.com/developers/docs/resources/guild#get-guild-widget-image-widget-style-options + Style *string `url:"style,omitempty"` + + GuildID string `url:"-"` +} + +// Widget Style Options +// https://discord.com/developers/docs/resources/guild#get-guild-widget-image-widget-style-options +const ( + FlagWidgetStyleOptionShield = "shield" + FlagWidgetStyleOptionBanner1 = "banner1" + FlagWidgetStyleOptionBanner2 = "banner2" + FlagWidgetStyleOptionBanner3 = "banner3" + FlagWidgetStyleOptionBanner4 = "banner4" +) + +// Get Guild Welcome Screen +// GET /guilds/{guild.id}/welcome-screen +// https://discord.com/developers/docs/resources/guild#get-guild-welcome-screen +type GetGuildWelcomeScreen struct { + GuildID string +} + +// Modify Guild Welcome Screen +// PATCH /guilds/{guild.id}/welcome-screen +// https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen +type ModifyGuildWelcomeScreen struct { + Enabled **bool `json:"enabled,omitempty"` + WelcomeChannels *[]*WelcomeScreenChannel `json:"welcome_channels,omitempty"` + Description **string `json:"description,omitempty"` + GuildID string `json:"-"` +} + +// Modify Current User Voice State +// PATCH /guilds/{guild.id}/voice-states/@me +// https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state +type ModifyCurrentUserVoiceState struct { + ChannelID *string `json:"channel_id,omitempty"` + Suppress *bool `json:"suppress,omitempty"` + RequestToSpeakTimestamp **time.Time `json:"request_to_speak_timestamp,omitempty"` + GuildID string `json:"-"` +} + +// Modify User Voice State +// PATCH /guilds/{guild.id}/voice-states/{user.id} +// https://discord.com/developers/docs/resources/guild#modify-user-voice-state +type ModifyUserVoiceState struct { + Suppress *bool `json:"suppress,omitempty"` + GuildID string `json:"-"` + UserID string `json:"-"` + ChannelID string `json:"channel_id"` +} + +// List Scheduled Events for Guild +// GET /guilds/{guild.id}/scheduled-events +// https://discord.com/developers/docs/resources/guild-scheduled-event#list-scheduled-events-for-guild +type ListScheduledEventsforGuild struct { + WithUserCount *bool `url:"with_user_count,omitempty"` + GuildID string `url:"-"` +} + +// Create Guild Scheduled Event +// POST /guilds/{guild.id}/scheduled-events +// https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event +type CreateGuildScheduledEvent struct { + ScheduledStartTime time.Time `json:"scheduled_start_time"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + ChannelID *string `json:"channel_id,omitempty"` + EntityMetadata *GuildScheduledEventEntityMetadata `json:"entity_metadata,omitempty"` + Image *string `json:"image,omitempty"` + Description *string `json:"description,omitempty"` + EntityType *Flag `json:"entity_type,omitempty"` + GuildID string `json:"-"` + Name string `json:"name"` + PrivacyLevel Flag `json:"privacy_level"` +} + +// Get Guild Scheduled Event +// GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id} +// https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event +type GetGuildScheduledEvent struct { + WithUserCount *bool `url:"with_user_count,omitempty"` + GuildID string `url:"-"` + GuildScheduledEventID string `url:"-"` +} + +// Modify Guild Scheduled Event +// PATCH /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id} +// https://discord.com/developers/docs/resources/guild-scheduled-event#modify-guild-scheduled-event +type ModifyGuildScheduledEvent struct { + ScheduledStartTime *time.Time `json:"scheduled_start_time,omitempty"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + ChannelID *string `json:"channel_id,omitempty"` + EntityMetadata **GuildScheduledEventEntityMetadata `json:"entity_metadata,omitempty"` + Name *string `json:"name,omitempty"` + PrivacyLevel *Flag `json:"privacy_level,omitempty"` + Description **string `json:"description,omitempty"` + EntityType *Flag `json:"entity_type,omitempty"` + Status *Flag `json:"status,omitempty"` + Image *string `json:"image,omitempty"` + GuildID string `json:"-"` + GuildScheduledEventID string `json:"-"` +} + +// Delete Guild Scheduled Event +// DELETE /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id} +// https://discord.com/developers/docs/resources/guild-scheduled-event#delete-guild-scheduled-event +type DeleteGuildScheduledEvent struct { + GuildID string + GuildScheduledEventID string +} + +// Get Guild Scheduled Event Users +// GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id}/users +// https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event-users +type GetGuildScheduledEventUsers struct { + Limit *int `url:"limit,omitempty"` + WithMember *bool `url:"with_member,omitempty"` + Before *string `url:"before,omitempty"` + After *string `url:"after,omitempty"` + GuildID string `url:"-"` + GuildScheduledEventID string `url:"-"` +} + +// Get Guild Template +// GET /guilds/templates/{template.code} +// https://discord.com/developers/docs/resources/guild-template#get-guild-template +type GetGuildTemplate struct { + TemplateCode string +} + +// Create Guild from Guild Template +// POST /guilds/templates/{template.code} +// https://discord.com/developers/docs/resources/guild-template#create-guild-from-guild-template +type CreateGuildfromGuildTemplate struct { + Icon *string `json:"icon,omitempty"` + TemplateCode string `json:"-"` + Name string `json:"name"` +} + +// Get Guild Templates +// GET /guilds/{guild.id}/templates +// https://discord.com/developers/docs/resources/guild-template#get-guild-templates +type GetGuildTemplates struct { + GuildID string +} + +// Create Guild Template +// POST /guilds/{guild.id}/templates +// https://discord.com/developers/docs/resources/guild-template#create-guild-template +type CreateGuildTemplate struct { + Description **string `json:"description,omitempty"` + GuildID string `json:"-"` + Name string `json:"name"` +} + +// Sync Guild Template +// PUT /guilds/{guild.id}/templates/{template.code} +// https://discord.com/developers/docs/resources/guild-template#sync-guild-template +type SyncGuildTemplate struct { + GuildID string + TemplateCode string +} + +// Modify Guild Template +// PATCH /guilds/{guild.id}/templates/{template.code} +// https://discord.com/developers/docs/resources/guild-template#modify-guild-template +type ModifyGuildTemplate struct { + Name *string `json:"name,omitempty"` + Description **string `json:"description,omitempty"` + GuildID string + TemplateCode string `json:"-"` +} + +// Delete Guild Template +// DELETE /guilds/{guild.id}/templates/{template.code} +// https://discord.com/developers/docs/resources/guild-template#delete-guild-template +type DeleteGuildTemplate struct { + GuildID string + TemplateCode string +} + +// Get Invite +// GET /invites/{invite.code} +// https://discord.com/developers/docs/resources/invite#get-invite +type GetInvite struct { + WithCounts *bool `url:"with_counts,omitempty"` + WithExpiration *bool `url:"with_expiration,omitempty"` + GuildScheduledEventID *string `url:"guild_scheduled_event_id,omitempty"` + InviteCode string `url:"-"` +} + +// Delete Invite +// DELETE /invites/{invite.code} +// https://discord.com/developers/docs/resources/invite#delete-invite +type DeleteInvite struct { + InviteCode string +} + +// Create Stage Instance +// POST /stage-instances +// https://discord.com/developers/docs/resources/stage-instance#create-stage-instance +type CreateStageInstance struct { + PrivacyLevel *Flag `json:"privacy_level,omitempty"` + SendStartNotification *bool `json:"send_start_notification,omitempty"` + ChannelID string `json:"channel_id"` + Topic string `json:"topic"` +} + +// Get Stage Instance +// GET /stage-instances/{channel.id} +// https://discord.com/developers/docs/resources/stage-instance#get-stage-instance +type GetStageInstance struct { + ChannelID string +} + +// Modify Stage Instance +// PATCH /stage-instances/{channel.id} +// https://discord.com/developers/docs/resources/stage-instance#modify-stage-instance +type ModifyStageInstance struct { + Topic *string `json:"topic,omitempty"` + PrivacyLevel *Flag `json:"privacy_level,omitempty"` + ChannelID string `json:"-"` +} + +// Delete Stage Instance +// DELETE /stage-instances/{channel.id} +// https://discord.com/developers/docs/resources/stage-instance#delete-stage-instance +type DeleteStageInstance struct { + ChannelID string +} + +// Get Sticker +// GET /stickers/{sticker.id} +// https://discord.com/developers/docs/resources/sticker#get-sticker +type GetSticker struct { + StickerID string +} + +// List Nitro Sticker Packs +// GET /sticker-packs +// https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs +type ListNitroStickerPacks struct{} + +// List Guild Stickers +// GET /guilds/{guild.id}/stickers +// https://discord.com/developers/docs/resources/sticker#list-guild-stickers +type ListGuildStickers struct { + GuildID string +} + +// Get Guild Sticker +// GET /guilds/{guild.id}/stickers/{sticker.id} +// https://discord.com/developers/docs/resources/sticker#get-guild-sticker +type GetGuildSticker struct { + GuildID string + StickerID string +} + +// Create Guild Sticker +// POST /guilds/{guild.id}/stickers +// https://discord.com/developers/docs/resources/sticker#create-guild-sticker +type CreateGuildSticker struct { + GuildID string `json:"-"` + Name string `json:"name"` + Description string `json:"description"` + Tags *string `json:"tags"` + File File `json:"-" dasgo:"file"` +} + +// Modify Guild Sticker +// PATCH /guilds/{guild.id}/stickers/{sticker.id} +// https://discord.com/developers/docs/resources/sticker#modify-guild-sticker +type ModifyGuildSticker struct { + Name *string `json:"name,omitempty"` + Description **string `json:"description,omitempty"` + Tags *string `json:"tags,omitempty"` + GuildID string `json:"-"` + StickerID string `json:"-"` +} + +// Delete Guild Sticker +// DELETE /guilds/{guild.id}/stickers/{sticker.id} +// https://discord.com/developers/docs/resources/sticker#delete-guild-sticker +type DeleteGuildSticker struct { + GuildID string + StickerID string +} + +// Get Current User +// GET/users/@me +// https://discord.com/developers/docs/resources/user#get-current-user +type GetCurrentUser struct{} + +// Get User +// GET/users/{user.id} +// https://discord.com/developers/docs/resources/user#get-user +type GetUser struct { + UserID string +} + +// Modify Current User +// PATCH /users/@me +// https://discord.com/developers/docs/resources/user#modify-current-user +type ModifyCurrentUser struct { + Username *string `json:"username,omitempty"` + Avatar *string `json:"avatar,omitempty"` +} + +// Get Current User Guilds +// GET /users/@me/guilds +// https://discord.com/developers/docs/resources/user#get-current-user-guilds +type GetCurrentUserGuilds struct { + Before *string `json:"before,omitempty"` + After *string `json:"after,omitempty"` + Limit *int `json:"limit,omitempty"` +} + +// Get Current User Guild Member +// GET /users/@me/guilds/{guild.id}/member +// https://discord.com/developers/docs/resources/user#get-current-user-guild-member +type GetCurrentUserGuildMember struct { + GuildID string +} + +// Leave Guild +// DELETE /users/@me/guilds/{guild.id} +// https://discord.com/developers/docs/resources/user#leave-guild +type LeaveGuild struct { + GuildID string +} + +// Create DM +// POST /users/@me/channels +// https://discord.com/developers/docs/resources/user#create-dm +type CreateDM struct { + RecipientID string `json:"recipient_id"` +} + +// Create Group DM +// POST /users/@me/channels +// https://discord.com/developers/docs/resources/user#create-group-dm +type CreateGroupDM struct { + Nicks map[string]string `json:"nicks"` + AccessTokens []*string `json:"access_tokens"` +} + +// Get User Connections +// GET /users/@me/connections +// https://discord.com/developers/docs/resources/user#get-user-connections +type GetUserConnections struct{} + +// List Voice Regions +// GET /voice/regions +// https://discord.com/developers/docs/resources/voice#list-voice-regions +type ListVoiceRegions struct{} + +// Create Webhook +// POST /channels/{channel.id}/webhooks +// https://discord.com/developers/docs/resources/webhook#create-webhook +type CreateWebhook struct { + Avatar **string `json:"avatar,omitempty"` + ChannelID string `json:"-"` + Name string `json:"name"` +} + +// Get Channel Webhooks +// GET /channels/{channel.id}/webhooks +// https://discord.com/developers/docs/resources/webhook#get-channel-webhooks +type GetChannelWebhooks struct { + ChannelID string +} + +// Get Guild Webhooks +// GET /guilds/{guild.id}/webhooks +// https://discord.com/developers/docs/resources/webhook#get-guild-webhooks +type GetGuildWebhooks struct { + GuildID string +} + +// Get Webhook +// GET /webhooks/{webhook.id} +// https://discord.com/developers/docs/resources/webhook#get-webhook +type GetWebhook struct { + WebhookID string +} + +// Get Webhook with Token +// GET /webhooks/{webhook.id}/{webhook.token} +// https://discord.com/developers/docs/resources/webhook#get-webhook-with-token +type GetWebhookwithToken struct { + WebhookID string + WebhookToken string +} + +// Modify Webhook +// PATCH /webhooks/{webhook.id} +// https://discord.com/developers/docs/resources/webhook#modify-webhook +type ModifyWebhook struct { + Name *string `json:"name,omitempty"` + Avatar **string `json:"avatar,omitempty"` + ChannelID *string `json:"channel_id,omitempty"` + WebhookID string `json:"-"` +} + +// Modify Webhook with Token +// PATCH /webhooks/{webhook.id}/{webhook.token} +// https://discord.com/developers/docs/resources/webhook#modify-webhook-with-token +type ModifyWebhookwithToken struct { + Name *string `json:"name,omitempty"` + Avatar **string `json:"avatar,omitempty"` + WebhookID string + WebhookToken string +} + +// Delete Webhook +// DELETE /webhooks/{webhook.id} +// https://discord.com/developers/docs/resources/webhook#delete-webhook +type DeleteWebhook struct { + WebhookID string +} + +// Delete Webhook with Token +// DELETE /webhooks/{webhook.id}/{webhook.token} +// https://discord.com/developers/docs/resources/webhook#delete-webhook-with-token +type DeleteWebhookwithToken struct { + WebhookID string + WebhookToken string +} + +// Execute Webhook +// POST /webhooks/{webhook.id}/{webhook.token} +// https://discord.com/developers/docs/resources/webhook#execute-webhook +type ExecuteWebhook struct { + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty" url:"-"` + Flags *BitFlag `json:"flags,omitempty" url:"-"` + Wait *bool `json:"-" url:"wait,omitempty"` + ThreadID *string `json:"-" url:"thread_id,omitempty"` + Content *string `json:"content,omitempty" url:"-"` + Username *string `json:"username,omitempty" url:"-"` + AvatarURL *string `json:"avatar_url,omitempty" url:"-"` + TTS *bool `json:"tts,omitempty" url:"-"` + ThreadName *string `json:"thread_name,omitempty" url:"-"` + WebhookToken string `json:"-" url:"-"` + WebhookID string `json:"-" url:"-"` + Embeds []*Embed `json:"embeds,omitempty" url:"-"` + Components []Component `json:"components,omitempty" url:"-"` + Files []*File `json:"-" url:"-" dasgo:"files"` + Attachments []*Attachment `json:"attachments,omitempty" url:"-"` +} + +// Execute Slack-Compatible Webhook +// POST /webhooks/{webhook.id}/{webhook.token}/slack +// https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook +type ExecuteSlackCompatibleWebhook struct { + ThreadID *string `url:"thread_id,omitempty"` + Wait *bool `url:"wait,omitempty"` + WebhookID string `url:"-"` + WebhookToken string `url:"-"` +} + +// Execute GitHub-Compatible Webhook +// POST /webhooks/{webhook.id}/{webhook.token}/github +// https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook +type ExecuteGitHubCompatibleWebhook struct { + ThreadID *string `url:"thread_id,omitempty"` + Wait *bool `url:"wait,omitempty"` + WebhookID string `url:"-"` + WebhookToken string `url:"-"` +} + +// Get Webhook Message +// GET /webhooks/{webhook.id}/{webhook.token}/messages/{message.id} +// https://discord.com/developers/docs/resources/webhook#get-webhook-message +type GetWebhookMessage struct { + ThreadID *string `url:"thread_id,omitempty"` + WebhookID string `url:"-"` + WebhookToken string `url:"-"` + MessageID string `url:"-"` +} + +// Edit Webhook Message +// PATCH /webhooks/{webhook.id}/{webhook.token}/messages/{message.id} +// https://discord.com/developers/docs/resources/webhook#edit-webhook-message +type EditWebhookMessage struct { + Components *[]Component `json:"components,omitempty" url:"-"` + AllowedMentions **AllowedMentions `json:"allowed_mentions,omitempty" url:"-"` + ThreadID *string `url:"thread_id,omitempty"` + Content **string `json:"content,omitempty" url:"-"` + Embeds *[]*Embed `json:"embeds,omitempty" url:"-"` + Attachments *[]*Attachment `json:"attachments,omitempty" url:"-"` + WebhookToken string `json:"-" url:"-"` + WebhookID string `json:"-" url:"-"` + MessageID string `json:"-" url:"-"` + Files []*File `json:"-" url:"-" dasgo:"files"` +} + +// Delete Webhook Message +// DELETE /webhooks/{webhook.id}/{webhook.token}/messages/{message.id} +// https://discord.com/developers/docs/resources/webhook#delete-webhook-message +type DeleteWebhookMessage struct { + ThreadID *string `url:"thread_id,omitempty"` + WebhookID string `url:"-"` + WebhookToken string `url:"-"` + MessageID string `url:"-"` +} + +// Get Current Bot Application Information +// GET /oauth2/applications/@me +// https://discord.com/developers/docs/topics/oauth2#get-current-bot-application-information +type GetCurrentBotApplicationInformation struct{} + +// Get Current Authorization Information +// GET /oauth2/@me +// https://discord.com/developers/docs/topics/oauth2#get-current-authorization-information +type GetCurrentAuthorizationInformation struct{} + +// Get Gateway +// GET /gateway +// https://discord.com/developers/docs/topics/gateway#get-gateway +type GetGateway struct{} + +// Get Gateway Bot +// GET /gateway/bot +// https://discord.com/developers/docs/topics/gateway#get-gateway-bot +type GetGatewayBot struct{} + +// Authorization URL +// GET /oauth2/authorize +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-authorization-url-example +type AuthorizationURL struct { + ResponseType string `url:"response_type,omitempty"` + ClientID string `url:"client_id,omitempty"` + Scope string `url:"scope,omitempty"` + State string `url:"state,omitempty"` + RedirectURI string `url:"redirect_uri,omitempty"` + Prompt string `url:"prompt,omitempty"` +} + +// Access Token Exchange +// POST /oauth2/token +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-exchange-example +type AccessTokenExchange struct { + ClientID string `url:"client_id,omitempty"` + ClientSecret string `url:"client_secret,omitempty"` + GrantType string `url:"grant_type,omitempty"` + Code string `url:"code,omitempty"` + RedirectURI string `url:"redirect_uri,omitempty"` +} + +// Refresh Token Exchange +// POST /oauth2/token +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-refresh-token-exchange-example +type RefreshTokenExchange struct { + ClientID string `url:"client_id,omitempty"` + ClientSecret string `url:"client_secret,omitempty"` + GrantType string `url:"grant_type,omitempty"` + RefreshToken string `url:"refresh_token,omitempty"` +} + +// Client Credentials Token Request +// POST /oauth2/token +// https://discord.com/developers/docs/topics/oauth2#client-credentials-grant-client-credentials-token-request-example +type ClientCredentialsTokenRequest struct { + GrantType string `url:"grant_type,omitempty"` + Scope string `url:"scope,omitempty"` +} + +// Bot Auth Parameters +// GET /oauth2/authorize +// https://discord.com/developers/docs/topics/oauth2#bot-authorization-flow-bot-auth-parameters +type BotAuth struct { + ClientID string `url:"client_id"` + Scope string `url:"scope"` + GuildID string `url:"guild_id"` + Permissions BitFlag `url:"permissions"` + DisableGuildSelect bool `url:"disable_guild_select"` +} + +// Application Command Structure +// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure +type ApplicationCommand struct { + Type *Flag `json:"type,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + DMPermission *bool `json:"dm_permission,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + DefaultMemberPermissions *string `json:"default_member_permissions"` + ID string `json:"id"` + ApplicationID string `json:"application_id"` + Description string `json:"description"` + Name string `json:"name"` + Version string `json:"version,omitempty"` + Options []*ApplicationCommandOption `json:"options,omitempty"` +} + +// Application Command Types +// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types +const ( + FlagApplicationCommandTypeCHAT_INPUT Flag = 1 + FlagApplicationCommandTypeUSER Flag = 2 + FlagApplicationCommandTypeMESSAGE Flag = 3 +) + +// Application Command Option Structure +// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure +type ApplicationCommandOption struct { + MaxValue *float64 `json:"max_value,omitempty"` + Autocomplete *bool `json:"autocomplete,omitempty"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + MinValue *float64 `json:"min_value,omitempty"` + DescriptionLocalizations *map[string]string `json:"description_localizations,omitempty"` + Required *bool `json:"required,omitempty"` + MaxLength *int `json:"max_length,omitempty"` + MinLength *int `json:"min_length,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + Options []*ApplicationCommandOption `json:"options,omitempty"` + ChannelTypes []Flag `json:"channel_types,omitempty"` + Choices []*ApplicationCommandOptionChoice `json:"choices,omitempty"` + Type Flag `json:"type"` +} + +// Application Command Option Type +// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type +const ( + FlagApplicationCommandOptionTypeSUB_COMMAND Flag = 1 + FlagApplicationCommandOptionTypeSUB_COMMAND_GROUP Flag = 2 + FlagApplicationCommandOptionTypeSTRING Flag = 3 + FlagApplicationCommandOptionTypeINTEGER Flag = 4 + FlagApplicationCommandOptionTypeBOOLEAN Flag = 5 + FlagApplicationCommandOptionTypeUSER Flag = 6 + FlagApplicationCommandOptionTypeCHANNEL Flag = 7 + FlagApplicationCommandOptionTypeROLE Flag = 8 + FlagApplicationCommandOptionTypeMENTIONABLE Flag = 9 + FlagApplicationCommandOptionTypeNUMBER Flag = 10 + FlagApplicationCommandOptionTypeATTACHMENT Flag = 11 +) + +// Application Command Option Choice +// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-choice-structure +type ApplicationCommandOptionChoice struct { + Name string `json:"name"` + NameLocalizations *map[string]string `json:"name_localizations,omitempty"` + Value Value `json:"value"` +} + +// Guild Application Command Permissions Object +// https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure +type GuildApplicationCommandPermissions struct { + ID string `json:"id"` + ApplicationID string `json:"application_id"` + GuildID string `json:"guild_id"` + Permissions []*ApplicationCommandPermissions `json:"permissions"` +} + +// Application Command Permissions Structure +// https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure +type ApplicationCommandPermissions struct { + ID string `json:"id"` + Type Flag `json:"type"` + Permission bool `json:"permission"` +} + +// Application Command Permission Type +// https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type +const ( + FlagApplicationCommandPermissionTypeROLE Flag = 1 + FlagApplicationCommandPermissionTypeUSER Flag = 2 + FlagApplicationCommandPermissionTypeCHANNEL Flag = 3 +) + +// Component Object +// https://discord.com/developers/docs/interactions/message-components#component-object +type Component interface { + ComponentType() Flag +} + +// Component Types +// https://discord.com/developers/docs/interactions/message-components#component-object-component-types +const ( + FlagComponentTypeActionRow Flag = 1 + FlagComponentTypeButton Flag = 2 + FlagComponentTypeSelectMenu Flag = 3 + FlagComponentTypeTextInput Flag = 4 + FlagComponentTypeUserSelect Flag = 5 + FlagComponentTypeRoleSelect Flag = 6 + FlagComponentTypeMentionableSelect Flag = 7 + FlagComponentTypeChannelSelect Flag = 8 +) + +// https://discord.com/developers/docs/interactions/message-components#component-object +type ActionsRow struct { + Components []Component `json:"components"` +} + +// Button Object +// https://discord.com/developers/docs/interactions/message-components#button-object +type Button struct { + Label *string `json:"label,omitempty"` + Emoji *Emoji `json:"emoji,omitempty"` + CustomID *string `json:"custom_id,omitempty"` + URL *string `json:"url,omitempty"` + Disabled *bool `json:"disabled,omitempty"` + Style Flag `json:"style"` +} + +// Button Styles +// https://discord.com/developers/docs/interactions/message-components#button-object-button-styles +const ( + FlagButtonStylePRIMARY Flag = 1 + FlagButtonStyleBLURPLE Flag = 1 + FlagButtonStyleSecondary Flag = 2 + FlagButtonStyleGREY Flag = 2 + FlagButtonStyleSuccess Flag = 3 + FlagButtonStyleGREEN Flag = 3 + FlagButtonStyleDanger Flag = 4 + FlagButtonStyleRED Flag = 4 + FlagButtonStyleLINK Flag = 5 +) + +// Select Menu Structure +// https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-menu-structure +type SelectMenu struct { + MaxValues *Flag `json:"max_values,omitempty"` + Disabled *bool `json:"disabled,omitempty"` + Placeholder *string `json:"placeholder,omitempty"` + MinValues *Flag `json:"min_values,omitempty"` + CustomID string `json:"custom_id"` + Options []SelectMenuOption `json:"options"` + ChannelTypes []Flag `json:"channel_types,omitempty"` + Type int `json:"type"` +} + +// Select Menu Option Structure +// https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure +type SelectMenuOption struct { + Description *string `json:"description,omitempty"` + Emoji *Emoji `json:"emoji,omitempty"` + Default *bool `json:"default,omitempty"` + Label string `json:"label"` + Value string `json:"value"` +} + +// Text Input Structure +// https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure +type TextInput struct { + Value *string `json:"value,omitempty"` + Placeholder *string `json:"placeholder,omitempty"` + Label *string `json:"label"` + MinLength *int `json:"min_length,omitempty"` + MaxLength *int `json:"max_length,omitempty"` + Required *bool `json:"required,omitempty"` + CustomID string `json:"custom_id"` + Style Flag `json:"style"` +} + +// Text Input Styles +// https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles +const ( + FlagTextInputStyleShort Flag = 1 + FlagTextInputStyleParagraph Flag = 2 +) + +// Interaction Object +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-structure +type Interaction struct { + Data InteractionData `json:"data,omitempty"` + Message *Message `json:"message,omitempty"` + Locale *string `json:"locale,omitempty"` + AppPermissions *BitFlag `json:"app_permissions,omitempty,string"` + GuildID *string `json:"guild_id,omitempty"` + ChannelID *string `json:"channel_id,omitempty"` + Member *GuildMember `json:"member,omitempty"` + User *User `json:"user,omitempty"` + GuildLocale *string `json:"guild_locale,omitempty"` + Token string `json:"token"` + ApplicationID string `json:"application_id"` + ID string `json:"id"` + Version int `json:"version,omitempty"` + Type Flag `json:"type"` +} + +// Interaction Type +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type +const ( + FlagInteractionTypePING Flag = 1 + FlagInteractionTypeAPPLICATION_COMMAND Flag = 2 + FlagInteractionTypeMESSAGE_COMPONENT Flag = 3 + FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE Flag = 4 + FlagInteractionTypeMODAL_SUBMIT Flag = 5 +) + +// Interaction Data +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-data +type InteractionData interface { + InteractionDataType() Flag +} + +// Application Command Data Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-application-command-data-structure +type ApplicationCommandData struct { + TargetID *string `json:"target_id,omitempty"` + Resolved *ResolvedData `json:"resolved,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + Name string `json:"name"` + ID string `json:"id"` + Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"` + Type Flag `json:"type"` +} + +// Message Component Data Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-message-component-data-structure +type MessageComponentData struct { + CustomID string `json:"custom_id"` + Values []*SelectMenuOption `json:"values,omitempty"` + ComponentType Flag `json:"component_type"` +} + +// Modal Submit Data Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-modal-submit-data-structure +type ModalSubmitData struct { + CustomID string `json:"custom_id"` + Components []Component `json:"components"` +} + +// Resolved Data Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-resolved-data-structure +type ResolvedData struct { + Users map[string]*User `json:"users,omitempty"` + Members map[string]*GuildMember `json:"members,omitempty"` + Roles map[string]*Role `json:"roles,omitempty"` + Channels map[string]*Channel `json:"channels,omitempty"` + Messages map[string]*Message `json:"messages,omitempty"` + Attachments map[string]*Attachment `json:"attachments,omitempty"` +} + +// Application Command Interaction Data Option Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-application-command-interaction-data-option-structure +type ApplicationCommandInteractionDataOption struct { + Value *Value `json:"value,omitempty"` + Focused *bool `json:"focused,omitempty"` + Name string `json:"name"` + Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"` + Type Flag `json:"type"` +} + +// Message Interaction Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object-message-interaction-structure +type MessageInteraction struct { + User *User `json:"user"` + Member *GuildMember `json:"member,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Type Flag `json:"type"` +} + +// Interaction Response Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-response-structure +type InteractionResponse struct { + Data InteractionCallbackData `json:"data,omitempty"` + Type Flag `json:"type"` +} + +// Interaction Callback Type +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type +const ( + FlagInteractionCallbackTypePONG Flag = 1 + FlagInteractionCallbackTypeCHANNEL_MESSAGE_WITH_SOURCE Flag = 4 + FlagInteractionCallbackTypeDEFERRED_CHANNEL_MESSAGE_WITH_SOURCE Flag = 5 + FlagInteractionCallbackTypeDEFERRED_UPDATE_MESSAGE Flag = 6 + FlagInteractionCallbackTypeUPDATE_MESSAGE Flag = 7 + FlagInteractionCallbackTypeAPPLICATION_COMMAND_AUTOCOMPLETE_RESULT Flag = 8 + FlagInteractionCallbackTypeMODAL Flag = 9 +) + +// Interaction Callback Data Structure +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-data-structure +type InteractionCallbackData interface { + InteractionCallbackDataType() Flag +} + +// Messages +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-messages +type Messages struct { + TTS *bool `json:"tts,omitempty"` + Content *string `json:"content,omitempty"` + Embeds []*Embed `json:"embeds,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + Components []Component `json:"components,omitempty"` + Attachments []*Attachment `json:"attachments,omitempty"` +} + +// Autocomplete +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-autocomplete +type Autocomplete struct { + Choices []*ApplicationCommandOptionChoice `json:"choices"` +} + +// Modal +// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-modal +type Modal struct { + CustomID string `json:"custom_id"` + Title string `json:"title"` + Components []Component `json:"components"` +} + +// Application Object +// https://discord.com/developers/docs/resources/application +type Application struct { + Slug *string `json:"slug,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + Icon *string `json:"icon"` + Team *Team `json:"team"` + InstallParams *InstallParams `json:"install_params,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + CoverImage *string `json:"cover_image,omitempty"` + TermsOfServiceURL *string `json:"terms_of_service_url,omitempty"` + PrivacyProxyURL *string `json:"privacy_policy_url,omitempty"` + Owner *User `json:"owner,omitempty"` + CustomInstallURL *string `json:"custom_install_url,omitempty"` + PrimarySKUID *string `json:"primary_sku_id,omitempty"` + Description string `json:"description"` + Name string `json:"name"` + VerifyKey string `json:"verify_key"` + ID string `json:"id"` + Tags []string `json:"tags,omitempty"` + RPCOrigins []string `json:"rpc_origins,omitempty"` + BotRequireCodeGrant bool `json:"bot_require_code_grant"` + BotPublic bool `json:"bot_public"` +} + +// Application Flags +// https://discord.com/developers/docs/resources/application#application-object-application-flags +const ( + FlagApplicationGATEWAY_PRESENCE BitFlag = 1 << 12 + FlagApplicationGATEWAY_PRESENCE_LIMITED BitFlag = 1 << 13 + FlagApplicationGATEWAY_GUILD_MEMBERS BitFlag = 1 << 14 + FlagApplicationGATEWAY_GUILD_MEMBERS_LIMITED BitFlag = 1 << 15 + FlagApplicationVERIFICATION_PENDING_GUILD_LIMIT BitFlag = 1 << 16 + FlagApplicationEMBEDDED BitFlag = 1 << 17 + FlagApplicationGATEWAY_MESSAGE_CONTENT BitFlag = 1 << 18 + FlagApplicationGATEWAY_MESSAGE_CONTENT_LIMITED BitFlag = 1 << 19 + FlagApplicationAPPLICATION_COMMAND_BADGE BitFlag = 1 << 23 +) + +// Install Params Object +// https://discord.com/developers/docs/resources/application#install-params-object +type InstallParams struct { + Permissions string `json:"permissions"` + Scopes []string `json:"scopes"` +} + +// Audit Log Object +// https://discord.com/developers/docs/resources/audit-log +type AuditLog struct { + ApplicationCommands []*ApplicationCommand `json:"application_commands"` + AuditLogEntries []*AuditLogEntry `json:"audit_log_entries"` + GuildScheduledEvents []*GuildScheduledEvent `json:"guild_scheduled_events"` + Integration []*Integration `json:"integrations"` + Threads []*Channel `json:"threads"` + Users []*User `json:"users"` + Webhooks []*Webhook `json:"webhooks"` +} + +// Audit Log Entry Object +// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-entry-structure +type AuditLogEntry struct { + TargetID *string `json:"target_id"` + UserID *string `json:"user_id"` + Options *AuditLogOptions `json:"options,omitempty"` + Reason *string `json:"reason,omitempty"` + ID string `json:"id"` + Changes []*AuditLogChange `json:"changes,omitempty"` + ActionType Flag `json:"action_type"` +} + +// Audit Log Events +// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events +const ( + FlagAuditLogEventGUILD_UPDATE Flag = 1 + FlagAuditLogEventCHANNEL_CREATE Flag = 10 + FlagAuditLogEventCHANNEL_UPDATE Flag = 11 + FlagAuditLogEventCHANNEL_DELETE Flag = 12 + FlagAuditLogEventCHANNEL_OVERWRITE_CREATE Flag = 13 + FlagAuditLogEventCHANNEL_OVERWRITE_UPDATE Flag = 14 + FlagAuditLogEventCHANNEL_OVERWRITE_DELETE Flag = 15 + FlagAuditLogEventMEMBER_KICK Flag = 20 + FlagAuditLogEventMEMBER_PRUNE Flag = 21 + FlagAuditLogEventMEMBER_BAN_ADD Flag = 22 + FlagAuditLogEventMEMBER_BAN_REMOVE Flag = 23 + FlagAuditLogEventMEMBER_UPDATE Flag = 24 + FlagAuditLogEventMEMBER_ROLE_UPDATE Flag = 25 + FlagAuditLogEventMEMBER_MOVE Flag = 26 + FlagAuditLogEventMEMBER_DISCONNECT Flag = 27 + FlagAuditLogEventBOT_ADD Flag = 28 + FlagAuditLogEventROLE_CREATE Flag = 30 + FlagAuditLogEventROLE_UPDATE Flag = 31 + FlagAuditLogEventROLE_DELETE Flag = 32 + FlagAuditLogEventINVITE_CREATE Flag = 40 + FlagAuditLogEventINVITE_UPDATE Flag = 41 + FlagAuditLogEventINVITE_DELETE Flag = 42 + FlagAuditLogEventWEBHOOK_CREATE Flag = 50 + FlagAuditLogEventWEBHOOK_UPDATE Flag = 51 + FlagAuditLogEventWEBHOOK_DELETE Flag = 52 + FlagAuditLogEventEMOJI_CREATE Flag = 60 + FlagAuditLogEventEMOJI_UPDATE Flag = 61 + FlagAuditLogEventEMOJI_DELETE Flag = 62 + FlagAuditLogEventMESSAGE_DELETE Flag = 72 + FlagAuditLogEventMESSAGE_BULK_DELETE Flag = 73 + FlagAuditLogEventMESSAGE_PIN Flag = 74 + FlagAuditLogEventMESSAGE_UNPIN Flag = 75 + FlagAuditLogEventINTEGRATION_CREATE Flag = 80 + FlagAuditLogEventINTEGRATION_UPDATE Flag = 81 + FlagAuditLogEventINTEGRATION_DELETE Flag = 82 + FlagAuditLogEventSTAGE_INSTANCE_CREATE Flag = 83 + FlagAuditLogEventSTAGE_INSTANCE_UPDATE Flag = 84 + FlagAuditLogEventSTAGE_INSTANCE_DELETE Flag = 85 + FlagAuditLogEventSTICKER_CREATE Flag = 90 + FlagAuditLogEventSTICKER_UPDATE Flag = 91 + FlagAuditLogEventSTICKER_DELETE Flag = 92 + FlagAuditLogEventGUILD_SCHEDULED_EVENT_CREATE Flag = 100 + FlagAuditLogEventGUILD_SCHEDULED_EVENT_UPDATE Flag = 101 + FlagAuditLogEventGUILD_SCHEDULED_EVENT_DELETE Flag = 102 + FlagAuditLogEventTHREAD_CREATE Flag = 110 + FlagAuditLogEventTHREAD_UPDATE Flag = 111 + FlagAuditLogEventTHREAD_DELETE Flag = 112 + FlagAuditLogEventAPPLICATION_COMMAND_PERMISSION_UPDATE Flag = 121 + FlagAuditLogEventAUTO_MODERATION_RULE_CREATE Flag = 140 + FlagAuditLogEventAUTO_MODERATION_RULE_UPDATE Flag = 141 + FlagAuditLogEventAUTO_MODERATION_RULE_DELETE Flag = 142 + FlagAuditLogEventAUTO_MODERATION_BLOCK_MESSAGE Flag = 143 + FlagAuditLogEventAUTO_MODERATION_FLAG_TO_CHANNEL Flag = 144 + FlagAuditLogEventAUTO_MODERATION_USER_COMMUNICATION_DISABLED Flag = 145 +) + +// Optional Audit Entry Info +// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-optional-audit-entry-info +type AuditLogOptions struct { + ApplicationID string `json:"application_id"` + AutoModerationRuleName string `json:"auto_moderation_rule_name"` + AutoModerationRuleTriggerType string `json:"auto_moderation_rule_trigger_type"` + ChannelID string `json:"channel_id"` + Count string `json:"count"` + DeleteMemberDays string `json:"delete_member_days"` + ID string `json:"id"` + MembersRemoved string `json:"members_removed"` + MessageID string `json:"message_id"` + RoleName string `json:"role_name"` + Type string `json:"type"` +} + +// Audit Log Change Object +// https://discord.com/developers/docs/resources/audit-log#audit-log-change-object +type AuditLogChange struct { + Key string `json:"key"` + NewValue json.RawMessage `json:"new_value,omitempty"` + OldValue json.RawMessage `json:"old_value,omitempty"` +} + +// Audit Log Change Exceptions +// https://discord.com/developers/docs/resources/audit-log#audit-log-change-object-audit-log-change-exceptions + +// Auto Moderation Rule Structure +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-auto-moderation-rule-structure +type AutoModerationRule struct { + ID string `json:"id"` + GuildID string `json:"guild_id"` + Name string `json:"name"` + CreatorID string `json:"creator_id"` + ExemptChannels []string `json:"exempt_channels"` + Actions []*AutoModerationAction `json:"actions"` + ExemptRoles []string `json:"exempt_roles"` + TriggerMetadata TriggerMetadata `json:"trigger_metadata"` + TriggerType Flag `json:"trigger_type"` + Enabled bool `json:"enabled"` + EventType Flag `json:"event_type"` +} + +// Trigger Types +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types +const ( + FlagTriggerTypeKEYWORD Flag = 1 + FlagTriggerTypeHARMFUL_LINK Flag = 2 + FlagTriggerTypeSPAM Flag = 3 + FlagTriggerTypeKEYWORD_PRESET Flag = 4 + FlagTriggerTypeMENTION_SPAM Flag = 5 +) + +// Trigger Metadata +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata +type TriggerMetadata struct { + // https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-matching-strategies + KeywordFilter []string `json:"keyword_filter"` + RegexPatterns []Flag `json:"regex_patterns"` + Presets []Flag `json:"presets"` + AllowList []string `json:"allow_list"` + MentionTotalLimit int `json:"mention_total_limit"` +} + +// Keyword Preset Types +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types +const ( + FlagKeywordPresetTypePROFANITY Flag = 1 + FlagKeywordPresetTypeSEXUAL_CONTENT Flag = 2 + FlagKeywordPresetTypeSLURS Flag = 3 +) + +// Event Types +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types +const ( + FlagEventTypeMESSAGE_SEND Flag = 1 +) + +// Auto Moderation Action Structure +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object +type AutoModerationAction struct { + Metadata *ActionMetadata `json:"metadata,omitempty"` + Type Flag `json:"type"` +} + +// Action Types +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types +const ( + FlagActionTypeBLOCK_MESSAGE Flag = 1 + FlagActionTypeSEND_ALERT_MESSAGE Flag = 2 + FlagActionTypeTIMEOUT Flag = 3 +) + +// Action Metadata +// https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +type ActionMetadata struct { + ChannelID string `json:"channel_id"` + DurationSeconds int `json:"duration_seconds"` +} + +// Channel Object +// https://discord.com/developers/docs/resources/channel +type Channel struct { + DefaultSortOrder **int `json:"default_sort_order,omitempty"` + Type *Flag `json:"type"` + GuildID *string `json:"guild_id,omitempty"` + Position *int `json:"position,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` + Name **string `json:"name,omitempty"` + Topic **string `json:"topic,omitempty"` + NSFW *bool `json:"nsfw,omitempty"` + LastMessageID **string `json:"last_message_id,omitempty"` + Bitrate *int `json:"bitrate,omitempty"` + UserLimit *int `json:"user_limit,omitempty"` + RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"` + DefaultReactionEmoji *DefaultReaction `json:"default_reaction_emoji"` + Icon **string `json:"icon,omitempty"` + OwnerID *string `json:"owner_id,omitempty"` + ApplicationID *string `json:"application_id,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + LastPinTimestamp **time.Time `json:"last_pin_timestamp,omitempty"` + RTCRegion **string `json:"rtc_region,omitempty"` + VideoQualityMode *Flag `json:"video_quality_mode,omitempty"` + MessageCount *int `json:"message_count,omitempty"` + MemberCount *int `json:"member_count,omitempty"` + ThreadMetadata *ThreadMetadata `json:"thread_metadata,omitempty"` + Member *ThreadMember `json:"member,omitempty"` + DefaultAutoArchiveDuration *int `json:"default_auto_archive_duration,omitempty"` + Permissions *string `json:"permissions,omitempty"` + ParentID **string `json:"parent_id,omitempty"` + TotalMessageSent *int `json:"total_message_sent,omitempty"` + ID string `json:"id"` + AvailableTags []*ForumTag `json:"available_tags,omitempty"` + AppliedTags []string `json:"applied_tags,omitempty"` + Recipients []*User `json:"recipients,omitempty"` + PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"` +} + +// Channel Types +// https://discord.com/developers/docs/resources/channel#channel-object-channel-types +const ( + FlagChannelTypeGUILD_TEXT Flag = 0 + FlagChannelTypeDM Flag = 1 + FlagChannelTypeGUILD_VOICE Flag = 2 + FlagChannelTypeGROUP_DM Flag = 3 + FlagChannelTypeGUILD_CATEGORY Flag = 4 + FlagChannelTypeGUILD_ANNOUNCEMENT Flag = 5 + FlagChannelTypeANNOUNCEMENT_THREAD Flag = 10 + FlagChannelTypePUBLIC_THREAD Flag = 11 + FlagChannelTypePRIVATE_THREAD Flag = 12 + FlagChannelTypeGUILD_STAGE_VOICE Flag = 13 + FlagChannelTypeGUILD_DIRECTORY Flag = 14 + FlagChannelTypeGUILD_FORUM Flag = 15 +) + +// Video Quality Modes +// https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes +const ( + FlagVideoQualityModeAUTO Flag = 1 + FlagVideoQualityModeFULL Flag = 2 +) + +// Channel Flags +// https://discord.com/developers/docs/resources/channel#channel-object-channel-flags +const ( + FlagChannelPINNED BitFlag = 1 << 1 + FlagChannelREQUIRE_TAG BitFlag = 1 << 4 +) + +// Sort Order Types +// https://discord.com/developers/docs/resources/channel#channel-object-sort-order-types +const ( + FlagSortOrderTypeLATEST_ACTIVITY Flag = 0 + FlagSortOrderTypeCREATION_DATE Flag = 1 +) + +// Message Object +// https://discord.com/developers/docs/resources/channel#message-object +type Message struct { + Timestamp time.Time `json:"timestamp"` + WebhookID *string `json:"webhook_id,omitempty"` + Author *User `json:"author"` + Position *int `json:"position,omitempty"` + + // MessageCreate Event Extra Field + // https://discord.com/developers/docs/topics/gateway-events#message-create + GuildID *string `json:"guild_id,omitempty"` + + EditedTimestamp *time.Time `json:"edited_timestamp"` + Thread *Channel `json:"thread"` + Interaction *Interaction `json:"interaction"` + ReferencedMessage **Message `json:"referenced_message,omitempty"` + Flags *BitFlag `json:"flags,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + ApplicationID *string `json:"application_id,omitempty"` + Application *Application `json:"application,omitempty"` + Activity *MessageActivity `json:"activity,omitempty"` + Nonce *Nonce `json:"nonce,omitempty"` + + // MessageCreate Event Extra Field + // https://discord.com/developers/docs/topics/gateway-events#message-create + Member *GuildMember `json:"member,omitempty"` + + ChannelID string `json:"channel_id"` + ID string `json:"id"` + Content string `json:"content"` + Stickers []*Sticker `json:"stickers"` + Attachments []*Attachment `json:"attachments"` + MentionChannels []*ChannelMention `json:"mention_channels,omitempty"` + MentionRoles []*string `json:"mention_roles"` + Mentions []*User `json:"mentions"` + Reactions []*Reaction `json:"reactions,omitempty"` + Embeds []*Embed `json:"embeds"` + Components []Component `json:"components"` + StickerItems []*StickerItem `json:"sticker_items"` + MentionEveryone bool `json:"mention_everyone"` + TTS bool `json:"tts"` + Type Flag `json:"type"` + Pinned bool `json:"pinned"` +} + +// Message Types +// https://discord.com/developers/docs/resources/channel#message-object-message-types +const ( + FlagMessageTypeDEFAULT Flag = 0 + FlagMessageTypeRECIPIENT_ADD Flag = 1 + FlagMessageTypeRECIPIENT_REMOVE Flag = 2 + FlagMessageTypeCALL Flag = 3 + FlagMessageTypeCHANNEL_NAME_CHANGE Flag = 4 + FlagMessageTypeCHANNEL_ICON_CHANGE Flag = 5 + FlagMessageTypeCHANNEL_PINNED_MESSAGE Flag = 6 + FlagMessageTypeUSER_JOIN Flag = 7 + FlagMessageTypeGUILD_BOOST Flag = 8 + FlagMessageTypeGUILD_BOOST_TIER_1 Flag = 9 + FlagMessageTypeGUILD_BOOST_TIER_2 Flag = 10 + FlagMessageTypeGUILD_BOOST_TIER_3 Flag = 11 + FlagMessageTypeCHANNEL_FOLLOW_ADD Flag = 12 + FlagMessageTypeGUILD_DISCOVERY_DISQUALIFIED Flag = 14 + FlagMessageTypeGUILD_DISCOVERY_REQUALIFIED Flag = 15 + FlagMessageTypeGUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING Flag = 16 + FlagMessageTypeGUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING Flag = 17 + FlagMessageTypeTHREAD_CREATED Flag = 18 + FlagMessageTypeREPLY Flag = 19 + FlagMessageTypeCHAT_INPUT_COMMAND Flag = 20 + FlagMessageTypeTHREAD_STARTER_MESSAGE Flag = 21 + FlagMessageTypeGUILD_INVITE_REMINDER Flag = 22 + FlagMessageTypeCONTEXT_MENU_COMMAND Flag = 23 + FlagMessageTypeAUTO_MODERATION_ACTION Flag = 24 +) + +// Message Activity Structure +// https://discord.com/developers/docs/resources/channel#message-object-message-activity-structure +type MessageActivity struct { + PartyID *string `json:"party_id,omitempty"` + Type int `json:"type"` +} + +// Message Activity Types +// https://discord.com/developers/docs/resources/channel#message-object-message-activity-types +const ( + FlagMessageActivityTypeJOIN Flag = 1 + FlagMessageActivityTypeSPECTATE Flag = 2 + FlagMessageActivityTypeLISTEN Flag = 3 + FlagMessageActivityTypeJOIN_REQUEST Flag = 5 +) + +// Message Flags +// https://discord.com/developers/docs/resources/channel#message-object-message-flags +const ( + FlagMessageCROSSPOSTED BitFlag = 1 << 0 + FlagMessageIS_CROSSPOST BitFlag = 1 << 1 + FlagMessageSUPPRESS_EMBEDS BitFlag = 1 << 2 + FlagMessageSOURCE_MESSAGE_DELETED BitFlag = 1 << 3 + FlagMessageURGENT BitFlag = 1 << 4 + FlagMessageHAS_THREAD BitFlag = 1 << 5 + FlagMessageEPHEMERAL BitFlag = 1 << 6 + FlagMessageLOADING BitFlag = 1 << 7 + FlagMessageFAILED_TO_MENTION_SOME_ROLES_IN_THREAD BitFlag = 1 << 8 +) + +// Message Reference Object +// https://discord.com/developers/docs/resources/channel#message-reference-object +type MessageReference struct { + MessageID *string `json:"message_id,omitempty"` + ChannelID *string `json:"channel_id,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + FailIfNotExists *bool `json:"fail_if_not_exists,omitempty"` +} + +// Followed Channel Structure +// https://discord.com/developers/docs/resources/channel#followed-channel-object-followed-channel-structure +type FollowedChannel struct { + ChannelID string `json:"channel_id"` + WebhookID string `json:"webhook_id"` +} + +// Reaction Object +// https://discord.com/developers/docs/resources/channel#reaction-object +type Reaction struct { + Emoji *Emoji `json:"emoji"` + Count int `json:"count"` + Me bool `json:"me"` +} + +// Overwrite Object +// https://discord.com/developers/docs/resources/channel#overwrite-object +type PermissionOverwrite struct { + ID string `json:"id"` + Deny string `json:"deny"` + Allow string `json:"allow"` + Type Flag `json:"type"` +} + +// Thread Metadata Object +// https://discord.com/developers/docs/resources/channel#thread-metadata-object +type ThreadMetadata struct { + ArchiveTimestamp time.Time `json:"archive_timestamp"` + Invitable *bool `json:"invitable,omitempty"` + CreateTimestamp **time.Time `json:"create_timestamp"` + AutoArchiveDuration int `json:"auto_archive_duration"` + Archived bool `json:"archived"` + Locked bool `json:"locked"` +} + +// Thread Member Object +// https://discord.com/developers/docs/resources/channel#thread-member-object +type ThreadMember struct { + ThreadID *string `json:"id,omitempty"` + UserID *string `json:"user_id,omitempty"` + JoinTimestamp time.Time `json:"join_timestamp"` + Flags Flag `json:"flags"` +} + +// Default Reaction Structure +// https://discord.com/developers/docs/resources/channel#default-reaction-object-default-reaction-structure +type DefaultReaction struct { + EmojiID *string `json:"emoji_id"` + EmojiName *string `json:"emoji_name"` +} + +// Forum Tag Structure +// https://discord.com/developers/docs/resources/channel#forum-tag-object-forum-tag-structure +type ForumTag struct { + EmojiName *string `json:"emoji_name"` + ID string `json:"id"` + Name string `json:"name"` + EmojiID string `json:"emoji_id"` + Moderated bool `json:"moderated"` +} + +// Embed Object +// https://discord.com/developers/docs/resources/channel#embed-object +type Embed struct { + Title *string `json:"title,omitempty"` + Type *string `json:"type,omitempty"` + Description *string `json:"description,omitempty"` + URL *string `json:"url,omitempty"` + Timestamp *time.Time `json:"timestamp,omitempty"` + Color *int `json:"color,omitempty"` + Footer *EmbedFooter `json:"footer,omitempty"` + Image *EmbedImage `json:"image,omitempty"` + Thumbnail *EmbedThumbnail `json:"thumbnail,omitempty"` + Video *EmbedVideo `json:"video,omitempty"` + Provider *EmbedProvider `json:"provider,omitempty"` + Author *EmbedAuthor `json:"author,omitempty"` + Fields []*EmbedField `json:"fields,omitempty"` +} + +// Embed Thumbnail Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure +type EmbedThumbnail struct { + ProxyURL *string `json:"proxy_url,omitempty"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + URL string `json:"url"` +} + +// Embed Video Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-video-structure +type EmbedVideo struct { + URL *string `json:"url,omitempty"` + ProxyURL *string `json:"proxy_url,omitempty"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` +} + +// Embed Image Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure +type EmbedImage struct { + ProxyURL *string `json:"proxy_url,omitempty"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + URL string `json:"url"` +} + +// Embed Provider Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure +type EmbedProvider struct { + Name *string `json:"name,omitempty"` + URL *string `json:"url,omitempty"` +} + +// Embed Author Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure +type EmbedAuthor struct { + URL *string `json:"url,omitempty"` + IconURL *string `json:"icon_url,omitempty"` + ProxyIconURL *string `json:"proxy_icon_url,omitempty"` + Name string `json:"name"` +} + +// Embed Footer Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure +type EmbedFooter struct { + IconURL *string `json:"icon_url,omitempty"` + ProxyIconURL *string `json:"proxy_icon_url,omitempty"` + Text string `json:"text"` +} + +// Embed Field Structure +// https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure +type EmbedField struct { + Inline *bool `json:"inline,omitempty"` + Name string `json:"name"` + Value string `json:"value"` +} + +// Embed Limits +// https://discord.com/developers/docs/resources/channel#embed-object-embed-limits +const ( + FlagEmbedLimitTitle = 256 + FlagEmbedLimitDescription = 4096 + FlagEmbedLimitFields = 25 + FlagEmbedLimitFieldName = 256 + FlagEmbedLimitFieldValue = 1024 + FlagEmbedLimitFooterText = 2048 + FlagEmbedLimitAuthorName = 256 +) + +// Message Attachment Object +// https://discord.com/developers/docs/resources/channel#attachment-object-attachment-structure +type Attachment struct { + Height **int `json:"height,omitempty"` + Description *string `json:"description,omitempty"` + ContentType *string `json:"content_type,omitempty"` + Width **int `json:"width,omitempty"` + Emphemeral *bool `json:"ephemeral,omitempty"` + ID string `json:"id"` + URL string `json:"url"` + ProxyURL string `json:"proxy_url"` + Filename string `json:"filename"` + Size int `json:"size"` +} + +// Channel Mention Object +// https://discord.com/developers/docs/resources/channel#channel-mention-object +type ChannelMention struct { + ID string `json:"id"` + GuildID string `json:"guild_id"` + Type *Flag `json:"type"` + Name string `json:"name"` +} + +// Allowed Mentions Structure +// https://discord.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-structure +type AllowedMentions struct { + Parse []*string `json:"parse"` + Roles []*string `json:"roles"` + Users []*string `json:"users"` + RepliedUser bool `json:"replied_user"` +} + +// Allowed Mention Types +// https://discord.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-structure +const ( + FlagAllowedMentionTypeRoles = "roles" + FlagAllowedMentionTypeUsers = "users" + FlagAllowedMentionTypeEveryone = "everyone" +) + +// Emoji Object +// https://discord.com/developers/docs/resources/emoji#emoji-object-emoji-structure +type Emoji struct { + ID *string `json:"id"` + Name *string `json:"name,omitempty"` + User *User `json:"user,omitempty"` + RequireColons *bool `json:"require_colons,omitempty"` + Managed *bool `json:"managed,omitempty"` + Animated *bool `json:"animated,omitempty"` + Available *bool `json:"available,omitempty"` + Roles []string `json:"roles,omitempty"` +} + +// Guild Object +// https://discord.com/developers/docs/resources/guild#guild-object +type Guild struct { + RulesChannelID *string `json:"rules_channel_id"` + WelcomeScreen *WelcomeScreen `json:"welcome_screen,omitempty"` + Icon *string `json:"icon"` + IconHash **string `json:"icon_hash,omitempty"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Owner *bool `json:"owner,omitempty"` + ApproximatePresenceCount *int `json:"approximate_presence_count,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Region **string `json:"region,omitempty"` + ApproximateMemberCount *int `json:"approximate_member_count,omitempty"` + MaxVideoChannelUsers *int `json:"max_video_channel_users,omitempty"` + WidgetEnabled *bool `json:"widget_enabled,omitempty"` + WidgetChannelID **string `json:"widget_channel_id,omitempty"` + PublicUpdatesChannelID *string `json:"public_updates_channel_id"` + PremiumSubscriptionCount *int `json:"premium_subscription_count,omitempty"` + ApplicationID *string `json:"application_id"` + Banner *string `json:"banner"` + Description *string `json:"description"` + VanityUrl *string `json:"vanity_url_code"` + MaxPresences **int `json:"max_presences,omitempty"` + MaxMembers *int `json:"max_members,omitempty"` + SystemChannelID *string `json:"system_channel_id"` + AfkChannelID *string `json:"afk_channel_id"` + + // Unavailable Guild Object + // https://discord.com/developers/docs/resources/guild#unavailable-guild-object + Unavailable *bool `json:"unavailable,omitempty"` + + OwnerID string `json:"owner_id"` + ID string `json:"id"` + Name string `json:"name"` + PreferredLocale string `json:"preferred_locale"` + Emojis []*Emoji `json:"emojis"` + Roles []*Role `json:"roles"` + Stickers []*Sticker `json:"stickers,omitempty"` + Features []*string `json:"features"` + AfkTimeout int `json:"afk_timeout"` + SystemChannelFlags BitFlag `json:"system_channel_flags"` + DefaultMessageNotifications Flag `json:"default_message_notifications"` + PremiumTier Flag `json:"premium_tier"` + ExplicitContentFilter Flag `json:"explicit_content_filter"` + NSFWLevel Flag `json:"nsfw_level"` + MFALevel Flag `json:"mfa_level"` + PremiumProgressBarEnabled bool `json:"premium_progress_bar_enabled"` + VerificationLevel Flag `json:"verification_level"` +} + +// Default Message Notification Level +// https://discord.com/developers/docs/resources/guild#guild-object-default-message-notification-level +const ( + FlagDefaultMessageNotificationLevelALL_MESSAGES Flag = 0 + FlagDefaultMessageNotificationLevelONLY_MENTIONS Flag = 1 +) + +// Explicit Content Filter Level +// https://discord.com/developers/docs/resources/guild#guild-object-explicit-content-filter-level +const ( + FlagExplicitContentFilterLevelDISABLED Flag = 0 + FlagExplicitContentFilterLevelMEMBERS_WITHOUT_ROLES Flag = 1 + FlagExplicitContentFilterLevelALL_MEMBERS Flag = 2 +) + +// MFA Level +// https://discord.com/developers/docs/resources/guild#guild-object-mfa-level +const ( + FlagMFALevelNONE Flag = 0 + FlagMFALevelELEVATED Flag = 1 +) + +// Verification Level +// https://discord.com/developers/docs/resources/guild#guild-object-verification-level +const ( + FlagVerificationLevelNONE Flag = 0 + FlagVerificationLevelLOW Flag = 1 + FlagVerificationLevelMEDIUM Flag = 2 + FlagVerificationLevelHIGH Flag = 3 + FlagVerificationLevelVERY_HIGH Flag = 4 +) + +// Guild NSFW Level +// https://discord.com/developers/docs/resources/guild#guild-object-guild-nsfw-level +const ( + FlagGuildNSFWLevelDEFAULT Flag = 0 + FlagGuildNSFWLevelEXPLICIT Flag = 1 + FlagGuildNSFWLevelSAFE Flag = 2 + FlagGuildNSFWLevelAGE_RESTRICTED Flag = 3 +) + +// Premium Tier +// https://discord.com/developers/docs/resources/guild#guild-object-premium-tier +const ( + FlagPremiumTierNONE Flag = 0 + FlagPremiumTierONE Flag = 1 + FlagPremiumTierTWO Flag = 2 + FlagPremiumTierTHREE Flag = 3 +) + +// System Channel Flags +// https://discord.com/developers/docs/resources/guild#guild-object-system-channel-flags +const ( + FlagSystemChannelSUPPRESS_JOIN_NOTIFICATIONS BitFlag = 1 << 0 + FlagSystemChannelSUPPRESS_PREMIUM_SUBSCRIPTIONS BitFlag = 1 << 1 + FlagSystemChannelSUPPRESS_GUILD_REMINDER_NOTIFICATIONS BitFlag = 1 << 2 + FlagSystemChannelSUPPRESS_JOIN_NOTIFICATION_REPLIES BitFlag = 1 << 3 +) + +// Guild Features +// https://discord.com/developers/docs/resources/guild#guild-object-guild-features +const ( + FlagGuildFeatureANIMATED_BANNER = "ANIMATED_BANNER" + FlagGuildFeatureANIMATED_ICON = "ANIMATED_ICON" + FlagGuildFeatureAPPLICATION_COMMAND_PERMISSIONS_V2 = "APPLICATION_COMMAND_PERMISSIONS_V2" + FlagGuildFeatureAUTO_MODERATION = "AUTO_MODERATION" + FlagGuildFeatureBANNER = "BANNER" + FlagGuildFeatureCOMMUNITY = "COMMUNITY" + FlagGuildFeatureDEVELOPER_SUPPORT_SERVER = "DEVELOPER_SUPPORT_SERVER" + FlagGuildFeatureDISCOVERABLE = "DISCOVERABLE" + FlagGuildFeatureFEATURABLE = "FEATURABLE" + FlagGuildFeatureINVITES_DISABLED = "INVITES_DISABLED" + FlagGuildFeatureINVITE_SPLASH = "INVITE_SPLASH" + FlagGuildFeatureMEMBER_VERIFICATION_GATE_ENABLED = "MEMBER_VERIFICATION_GATE_ENABLED" + FlagGuildFeatureMONETIZATION_ENABLED = "MONETIZATION_ENABLED" + FlagGuildFeatureMORE_STICKERS = "MORE_STICKERS" + FlagGuildFeatureNEWS = "NEWS" + FlagGuildFeaturePARTNERED = "PARTNERED" + FlagGuildFeaturePREVIEW_ENABLED = "PREVIEW_ENABLED" + FlagGuildFeatureROLE_ICONS = "ROLE_ICONS" + FlagGuildFeatureTICKETED_EVENTS_ENABLED = "TICKETED_EVENTS_ENABLED" + FlagGuildFeatureVANITY_URL = "VANITY_URL" + FlagGuildFeatureVERIFIED = "VERIFIED" + FlagGuildFeatureVIP_REGIONS = "VIP_REGIONS" + FlagGuildFeatureWELCOME_SCREEN_ENABLED = "WELCOME_SCREEN_ENABLED" +) + +// Mutable Guild Features +// https://discord.com/developers/docs/resources/guild#guild-object-mutable-guild-features +var ( + MutableGuildFeatures = map[string]bool{ + FlagGuildFeatureCOMMUNITY: true, + FlagGuildFeatureINVITES_DISABLED: true, + FlagGuildFeatureDISCOVERABLE: true, + } +) + +// Guild Preview Object +// https://discord.com/developers/docs/resources/guild#guild-preview-object-guild-preview-structure +type GuildPreview struct { + Icon *string `json:"icon"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Description *string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + Emojis []*Emoji `json:"emojis"` + Features []*string `json:"features"` + Stickers []*Sticker `json:"stickers"` + ApproximateMemberCount int `json:"approximate_member_count"` + ApproximatePresenceCount int `json:"approximate_presence_count"` +} + +// Guild Widget Settings Object +// https://discord.com/developers/docs/resources/guild#guild-widget-settings-object +type GuildWidgetSettings struct { + ChannelID *string `json:"channel_id"` + Enabled bool `json:"enabled"` +} + +// Guild Widget Object +// https://discord.com/developers/docs/resources/guild#et-gguild-widget-object-get-guild-widget-structure* +type GuildWidget struct { + ID string `json:"id"` + Name string `json:"name"` + InstantInvite *string `json:"instant_invite"` + Channels []*Channel `json:"channels"` + Members []*User `json:"members"` + PresenceCount int `json:"presence_count"` +} + +// Guild Member Object +// https://discord.com/developers/docs/resources/guild#guild-member-object +type GuildMember struct { + JoinedAt time.Time `json:"joined_at"` + User *User `json:"user,omitempty"` + Nick **string `json:"nick,omitempty"` + Avatar **string `json:"avatar,omitempty"` + Permissions *string `json:"permissions,omitempty"` + PremiumSince **time.Time `json:"premium_since,omitempty"` + Pending *bool `json:"pending,omitempty"` + CommunicationDisabledUntil **time.Time `json:"communication_disabled_until,omitempty"` + Roles []*string `json:"roles"` + Deaf bool `json:"deaf"` + Mute bool `json:"mute"` +} + +// Integration Object +// https://discord.com/developers/docs/resources/guild#integration-object +type Integration struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Enabled *bool `json:"enabled,omitempty"` + Syncing *bool `json:"syncing,omitempty"` + RoleID *string `json:"role_id,omitempty"` + EnableEmoticons *bool `json:"enable_emoticons,omitempty"` + ExpireBehavior *Flag `json:"expire_behavior,omitempty"` + ExpireGracePeriod *int `json:"expire_grace_period,omitempty"` + User *User `json:"user,omitempty"` + Account IntegrationAccount `json:"account"` + SyncedAt *time.Time `json:"synced_at,omitempty"` + SubscriberCount *int `json:"subscriber_count,omitempty"` + Revoked *bool `json:"revoked,omitempty"` + Application *Application `json:"application,omitempty"` + Scopes []string `json:"scopes,omitempty"` +} + +// Integration Expire Behaviors +// https://discord.com/developers/docs/resources/guild#integration-object-integration-expire-behaviors +const ( + FlagIntegrationExpireBehaviorREMOVEROLE Flag = 0 + FlagIntegrationExpireBehaviorKICK Flag = 1 +) + +// Integration Account Object +// https://discord.com/developers/docs/resources/guild#integration-account-object +type IntegrationAccount struct { + ID string `json:"id"` + Name string `json:"name"` +} + +// Integration Application Object +// https://discord.com/developers/docs/resources/guild#integration-application-object-integration-application-structure +type IntegrationApplication struct { + Icon *string `json:"icon"` + Bot *User `json:"bot,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` +} + +// Guild Ban Object +// https://discord.com/developers/docs/resources/guild#ban-object +type Ban struct { + Reason *string `json:"reason"` + User *User `json:"user"` +} + +// Welcome Screen Object +// https://discord.com/developers/docs/resources/guild#welcome-screen-object-welcome-screen-structure +type WelcomeScreen struct { + Description *string `json:"description"` + WelcomeScreenChannels []*WelcomeScreenChannel `json:"welcome_channels"` +} + +// Welcome Screen Channel Structure +// https://discord.com/developers/docs/resources/guild#welcome-screen-object-welcome-screen-channel-structure +type WelcomeScreenChannel struct { + Description *string `json:"description"` + EmojiID *string `json:"emoji_id"` + EmojiName *string `json:"emoji_name"` + ChannelID string `json:"channel_id"` +} + +// Guild Scheduled Event Object +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-structure +type GuildScheduledEvent struct { + ScheduledStartTime time.Time `json:"scheduled_start_time"` + EntityMetadata *GuildScheduledEventEntityMetadata `json:"entity_metadata"` + ChannelID *string `json:"channel_id"` + CreatorID **string `json:"creator_id,omitempty"` + EntityID *string `json:"entity_id"` + Description **string `json:"description,omitempty"` + Creator *User `json:"creator,omitempty"` + ScheduledEndTime *time.Time `json:"scheduled_end_time"` + Image **string `json:"image,omitempty"` + UserCount *int `json:"user_count,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + GuildID string `json:"guild_id"` + EntityType Flag `json:"entity_type"` + Status Flag `json:"status"` + PrivacyLevel Flag `json:"privacy_level"` +} + +// Guild Scheduled Event Privacy Level +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level +const ( + FlagGuildScheduledEventPrivacyLevelGUILD_ONLY Flag = 2 +) + +// Guild Scheduled Event Entity Types +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types +const ( + FlagGuildScheduledEventEntityTypeSTAGE_INSTANCE Flag = 1 + FlagGuildScheduledEventEntityTypeVOICE Flag = 2 + FlagGuildScheduledEventEntityTypeEXTERNAL Flag = 3 +) + +// Guild Scheduled Event Status +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status +const ( + FlagGuildScheduledEventStatusSCHEDULED Flag = 1 + FlagGuildScheduledEventStatusACTIVE Flag = 2 + FlagGuildScheduledEventStatusCOMPLETED Flag = 3 + FlagGuildScheduledEventStatusCANCELED Flag = 4 +) + +// Guild Scheduled Event Entity Metadata +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata +type GuildScheduledEventEntityMetadata struct { + Location string `json:"location,omitempty"` +} + +// Guild Scheduled Event User Object +// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-user-object-guild-scheduled-event-user-structure +type GuildScheduledEventUser struct { + User *User `json:"user"` + Member *GuildMember `json:"member,omitempty"` + GuildScheduledEventID string `json:"guild_scheduled_event_id"` +} + +// Guild Template Object +// https://discord.com/developers/docs/resources/guild-template#guild-template-object +type GuildTemplate struct { + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Description *string `json:"description"` + SerializedSourceGuild *Guild `json:"serialized_source_guild"` + IsDirty *bool `json:"is_dirty"` + Creator *User `json:"creator"` + Code string `json:"code"` + Name string `json:"name"` + SourceGuildID string `json:"source_guild_id"` + CreatorID string `json:"creator_id"` + UsageCount int `json:"usage_count"` +} + +// Invite Object +// https://discord.com/developers/docs/resources/invite#invite-object +type Invite struct { + TargetApplication *Application `json:"target_application,omitempty"` + Guild *Guild `json:"guild,omitempty"` + Channel *Channel `json:"channel"` + Inviter *User `json:"inviter,omitempty"` + TargetType *Flag `json:"target_type,omitempty"` + TargetUser *User `json:"target_user,omitempty"` + ApproximatePresenceCount *int `json:"approximate_presence_count,omitempty"` + ApproximateMemberCount *int `json:"approximate_member_count,omitempty"` + ExpiresAt **time.Time `json:"expires_at,omitempty"` + GuildScheduledEvent *GuildScheduledEvent `json:"guild_scheduled_event,omitempty"` + Code string `json:"code"` +} + +// Invite Target Types +// https://discord.com/developers/docs/resources/invite#invite-object-invite-target-types +const ( + FlagInviteTargetTypeSTREAM Flag = 1 + FlagInviteTargetTypeEMBEDDED_APPLICATION Flag = 2 +) + +// Invite Metadata Object +// https://discord.com/developers/docs/resources/invite#invite-metadata-object-invite-metadata-structure +type InviteMetadata struct { + CreatedAt time.Time `json:"created_at"` + Uses int `json:"uses"` + MaxUses int `json:"max_uses"` + MaxAge int `json:"max_age"` + Temporary bool `json:"temporary"` +} + +// Stage Instance Object +// https://discord.com/developers/docs/resources/stage-instance#stage-instance-object +type StageInstance struct { + GuildScheduledEventID *string `json:"guild_scheduled_event_id"` + GuildID string `json:"guild_id"` + ChannelID string `json:"channel_id"` + Topic string `json:"topic"` + ID string `json:"id"` + PrivacyLevel Flag `json:"privacy_level"` + DiscoverableDisabled bool `json:"discoverable_disabled"` +} + +// Stage Instance Privacy Level +// https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level +const ( + FlagStageInstancePrivacyLevelGUILD_ONLY Flag = 2 +) + +// Sticker Structure +// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-structure +type Sticker struct { + PackID *string `json:"pack_id,omitempty"` + Available *bool `json:"available,omitempty"` + Description *string `json:"description"` + User *User `json:"user,omitempty"` + Asset *string `json:"asset,omitempty"` + GuildID *string `json:"guild_id,omitempty"` + SortValue *int `json:"sort_value,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Tags string `json:"tags"` + Type Flag `json:"type"` + FormatType Flag `json:"format_type"` +} + +// Sticker Types +// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-types +const ( + FlagStickerTypeSTANDARD Flag = 1 + FlagStickerTypeGUILD Flag = 2 +) + +// Sticker Format Types +// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-format-types +const ( + FlagStickerFormatTypePNG Flag = 1 + FlagStickerFormatTypeAPNG Flag = 2 + FlagStickerFormatTypeLOTTIE Flag = 3 +) + +// Sticker Item Object +// https://discord.com/developers/docs/resources/sticker#sticker-item-object +type StickerItem struct { + ID string `json:"id"` + Name string `json:"name"` + FormatType Flag `json:"format_type"` +} + +// Sticker Pack Object +// https://discord.com/developers/docs/resources/sticker#sticker-pack-object-sticker-pack-structure +type StickerPack struct { + BannerAssetID *string `json:"banner_asset_id,omitempty"` + CoverStickerID *string `json:"cover_sticker_id,omitempty"` + Name string `json:"name"` + SKU_ID string `json:"sku_id"` + Description string `json:"description"` + ID string `json:"id"` + Stickers []*Sticker `json:"stickers"` +} + +// User Object +// https://discord.com/developers/docs/resources/user#user-object +type User struct { + PublicFlags *BitFlag `json:"public_flag,omitempty"` + PremiumType *Flag `json:"premium_type,omitempty"` + Flags *BitFlag `json:"flag,omitempty"` + Avatar *string `json:"avatar"` + Bot *bool `json:"bot,omitempty"` + System *bool `json:"system,omitempty"` + MFAEnabled *bool `json:"mfa_enabled,omitempty"` + Banner **string `json:"banner,omitempty"` + AccentColor **int `json:"accent_color,omitempty"` + Locale *string `json:"locale,omitempty"` + Verified *bool `json:"verified,omitempty"` + Email **string `json:"email,omitempty"` + Discriminator string `json:"discriminator"` + Username string `json:"username"` + ID string `json:"id"` +} + +// User Flags +// https://discord.com/developers/docs/resources/user#user-object-user-flags +const ( + FlagUserNONE BitFlag = 0 + FlagUserSTAFF BitFlag = 1 << 0 + FlagUserPARTNER BitFlag = 1 << 1 + FlagUserHYPESQUAD BitFlag = 1 << 2 + FlagUserBUG_HUNTER_LEVEL_1 BitFlag = 1 << 3 + FlagUserHYPESQUAD_ONLINE_HOUSE_ONE BitFlag = 1 << 6 + FlagUserHYPESQUAD_ONLINE_HOUSE_TWO BitFlag = 1 << 7 + FlagUserHYPESQUAD_ONLINE_HOUSE_THREE BitFlag = 1 << 8 + FlagUserPREMIUM_EARLY_SUPPORTER BitFlag = 1 << 9 + FlagUserTEAM_PSEUDO_USER BitFlag = 1 << 10 + FlagUserBUG_HUNTER_LEVEL_2 BitFlag = 1 << 14 + FlagUserVERIFIED_BOT BitFlag = 1 << 16 + FlagUserVERIFIED_DEVELOPER BitFlag = 1 << 17 + FlagUserCERTIFIED_MODERATOR BitFlag = 1 << 18 + FlagUserBOT_HTTP_INTERACTIONS BitFlag = 1 << 19 + FlagUserACTIVE_DEVELOPER BitFlag = 1 << 22 +) + +// Premium Types +// https://discord.com/developers/docs/resources/user#user-object-premium-types +const ( + FlagPremiumTypeNONE Flag = 0 + FlagPremiumTypeNITROCLASSIC Flag = 1 + FlagPremiumTypeNITRO Flag = 2 + FlagPremiumTypeNITROBASIC Flag = 3 +) + +// User Connection Object +// https://discord.com/developers/docs/resources/user#connection-object-connection-structure +type Connection struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Revoked *bool `json:"revoked,omitempty"` + Integrations []*Integration `json:"integrations,omitempty"` + Verified bool `json:"verified"` + FriendSync bool `json:"friend_sync"` + ShowActivity bool `json:"show_activity"` + TwoWayLink bool `json:"two_way_link"` + Visibility Flag `json:"visibility"` +} + +// Visibility Types +// https://discord.com/developers/docs/resources/user#connection-object-visibility-types +const ( + FlagVisibilityTypeNONE Flag = 0 + FlagVisibilityTypeEVERYONE Flag = 1 +) + +// Voice State Object +// https://discord.com/developers/docs/resources/voice#voice-state-object-voice-state-structure +type VoiceState struct { + GuildID *string `json:"guild_id,omitempty"` + ChannelID *string `json:"channel_id"` + SelfStream *bool `json:"self_stream,omitempty"` + Member *GuildMember `json:"member,omitempty"` + RequestToSpeakTimestamp *time.Time `json:"request_to_speak_timestamp"` + SessionID string `json:"session_id"` + UserID string `json:"user_id"` + Deaf bool `json:"deaf"` + SelfDeaf bool `json:"self_deaf"` + SelfMute bool `json:"self_mute"` + SelfVideo bool `json:"self_video"` + Suppress bool `json:"suppress"` + Mute bool `json:"mute"` +} + +// Voice Region Object +// https://discord.com/developers/docs/resources/voice#voice-region-object-voice-region-structure +type VoiceRegion struct { + ID string `json:"id"` + Name string `json:"name"` + Optimal bool `json:"optimal"` + Deprecated bool `json:"deprecated"` + Custom bool `json:"custom"` +} + +// Webhook Object +// https://discord.com/developers/docs/resources/webhook#webhook-object +type Webhook struct { + Avatar *string `json:"avatar"` + Token *string `json:"token,omitempty"` + GuildID **string `json:"guild_id,omitempty"` + ChannelID *string `json:"channel_id"` + User *User `json:"user,omitempty"` + Name *string `json:"name"` + ApplicationID *string `json:"application_id"` + SourceGuild *Guild `json:"source_guild,omitempty"` + SourceChannel *Channel `json:"source_channel,omitempty"` + URL *string `json:"url,omitempty"` + ID string `json:"id"` + Type Flag `json:"type"` +} + +// Webhook Types +// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types +const ( + FlagWebhookTypeINCOMING Flag = 1 + FlagWebhookTypeCHANNELFOLLOWER Flag = 2 + FlagWebhookTypeAPPLICATION Flag = 3 +) + +// Bitwise Permission Flags +// https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags +const ( + FlagBitwisePermissionCREATE_INSTANT_INVITE BitFlag = 1 << 0 + FlagBitwisePermissionKICK_MEMBERS BitFlag = 1 << 1 + FlagBitwisePermissionBAN_MEMBERS BitFlag = 1 << 2 + FlagBitwisePermissionADMINISTRATOR BitFlag = 1 << 3 + FlagBitwisePermissionMANAGE_CHANNELS BitFlag = 1 << 4 + FlagBitwisePermissionMANAGE_GUILD BitFlag = 1 << 5 + FlagBitwisePermissionADD_REACTIONS BitFlag = 1 << 6 + FlagBitwisePermissionVIEW_AUDIT_LOG BitFlag = 1 << 7 + FlagBitwisePermissionPRIORITY_SPEAKER BitFlag = 1 << 8 + FlagBitwisePermissionSTREAM BitFlag = 1 << 9 + FlagBitwisePermissionVIEW_CHANNEL BitFlag = 1 << 10 + FlagBitwisePermissionSEND_MESSAGES BitFlag = 1 << 11 + FlagBitwisePermissionSEND_TTS_MESSAGES BitFlag = 1 << 12 + FlagBitwisePermissionMANAGE_MESSAGES BitFlag = 1 << 13 + FlagBitwisePermissionEMBED_LINKS BitFlag = 1 << 14 + FlagBitwisePermissionATTACH_FILES BitFlag = 1 << 15 + FlagBitwisePermissionREAD_MESSAGE_HISTORY BitFlag = 1 << 16 + FlagBitwisePermissionMENTION_EVERYONE BitFlag = 1 << 17 + FlagBitwisePermissionUSE_EXTERNAL_EMOJIS BitFlag = 1 << 18 + FlagBitwisePermissionVIEW_GUILD_INSIGHTS BitFlag = 1 << 19 + FlagBitwisePermissionCONNECT BitFlag = 1 << 20 + FlagBitwisePermissionSPEAK BitFlag = 1 << 21 + FlagBitwisePermissionMUTE_MEMBERS BitFlag = 1 << 22 + FlagBitwisePermissionDEAFEN_MEMBERS BitFlag = 1 << 23 + FlagBitwisePermissionMOVE_MEMBERS BitFlag = 1 << 24 + FlagBitwisePermissionUSE_VAD BitFlag = 1 << 25 + FlagBitwisePermissionCHANGE_NICKNAME BitFlag = 1 << 26 + FlagBitwisePermissionMANAGE_NICKNAMES BitFlag = 1 << 27 + FlagBitwisePermissionMANAGE_ROLES BitFlag = 1 << 28 + FlagBitwisePermissionMANAGE_WEBHOOKS BitFlag = 1 << 29 + FlagBitwisePermissionMANAGE_EMOJIS_AND_STICKERS BitFlag = 1 << 30 + FlagBitwisePermissionUSE_APPLICATION_COMMANDS BitFlag = 1 << 31 + FlagBitwisePermissionREQUEST_TO_SPEAK BitFlag = 1 << 32 + FlagBitwisePermissionMANAGE_EVENTS BitFlag = 1 << 33 + FlagBitwisePermissionMANAGE_THREADS BitFlag = 1 << 34 + FlagBitwisePermissionCREATE_PUBLIC_THREADS BitFlag = 1 << 35 + FlagBitwisePermissionCREATE_PRIVATE_THREADS BitFlag = 1 << 36 + FlagBitwisePermissionUSE_EXTERNAL_STICKERS BitFlag = 1 << 37 + FlagBitwisePermissionSEND_MESSAGES_IN_THREADS BitFlag = 1 << 38 + FlagBitwisePermissionUSE_EMBEDDED_ACTIVITIES BitFlag = 1 << 39 + FlagBitwisePermissionMODERATE_MEMBERS BitFlag = 1 << 40 +) + +// Permission Overwrite Types +const ( + FlagPermissionOverwriteTypeRole Flag = 0 + FlagPermissionOverwriteTypeMember Flag = 1 +) + +// Role Object +// https://discord.com/developers/docs/topics/permissions#role-object +type Role struct { + Icon **string `json:"icon,omitempty"` + UnicodeEmoji **string `json:"unicode_emoji,omitempty"` + Tags *RoleTags `json:"tags,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Permissions string `json:"permissions"` + Color int `json:"color"` + Position int `json:"position"` + Hoist bool `json:"hoist"` + Managed bool `json:"managed"` + Mentionable bool `json:"mentionable"` +} + +// Role Tags Structure +// https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure +type RoleTags struct { + BotID *string `json:"bot_id,omitempty"` + IntegrationID *string `json:"integration_id,omitempty"` + PremiumSubscriber *bool `json:"premium_subscriber,omitempty"` +} + +// Team Object +// https://discord.com/developers/docs/topics/teams#data-models-team-object +type Team struct { + Icon *string `json:"icon"` + Description *string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + OwnerUserID string `json:"owner_user_id"` + Members []*TeamMember `json:"members"` +} + +// Team Member Object +// https://discord.com/developers/docs/topics/teams#data-models-team-member-object +type TeamMember struct { + User *User `json:"user"` + TeamID string `json:"team_id"` + Permissions []string `json:"permissions"` + MembershipState Flag `json:"membership_state"` +} + +// Membership State Enum +// https://discord.com/developers/docs/topics/teams#data-models-membership-state-enum +const ( + FlagMembershipStateEnumINVITED Flag = 1 + FlagMembershipStateEnumACCEPTED Flag = 2 +) + +// Client Status Object +// https://discord.com/developers/docs/topics/gateway-events#client-status-object +type ClientStatus struct { + Desktop *string `json:"desktop,omitempty"` + Mobile *string `json:"mobile,omitempty"` + Web *string `json:"web,omitempty"` +} + +// Activity Object +// https://discord.com/developers/docs/topics/gateway-events#activity-object +type Activity struct { + Assets *ActivityAssets `json:"assets,omitempty"` + Instance *bool `json:"instance,omitempty"` + URL **string `json:"url,omitempty"` + Secrets *ActivitySecrets `json:"secrets,omitempty"` + Timestamps *ActivityTimestamps `json:"timestamps,omitempty"` + ApplicationID *string `json:"application_id,omitempty"` + Details **string `json:"details,omitempty"` + State **string `json:"state,omitempty"` + Emoji **Emoji `json:"emoji,omitempty"` + Party *ActivityParty `json:"party,omitempty"` + Name string `json:"name"` + Buttons []*Button `json:"buttons,omitempty"` + CreatedAt int `json:"created_at"` + Flags BitFlag `json:"flags,omitempty"` + Type Flag `json:"type"` +} + +// Activity Types +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types +const ( + FlagActivityTypePlaying Flag = 0 + FlagActivityTypeStreaming Flag = 1 + FlagActivityTypeListening Flag = 2 + FlagActivityTypeWatching Flag = 3 + FlagActivityTypeCustom Flag = 4 + FlagActivityTypeCompeting Flag = 5 +) + +// Activity Timestamps Struct +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-timestamps +type ActivityTimestamps struct { + Start *int `json:"start,omitempty"` + End *int `json:"end,omitempty"` +} + +// Activity Emoji +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-emoji +type ActivityEmoji struct { + ID *string `json:"id,omitempty"` + Animated *bool `json:"animated,omitempty"` + Name string `json:"name"` +} + +// Activity Party Struct +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-party +type ActivityParty struct { + ID *string `json:"id,omitempty"` + Size *[2]int `json:"size,omitempty"` +} + +// Activity Assets Struct +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-assets +type ActivityAssets struct { + LargeImage *string `json:"large_image,omitempty"` + LargeText *string `json:"large_text,omitempty"` + SmallImage *string `json:"small_image,omitempty"` + SmallText *string `json:"small_text,omitempty"` +} + +// Activity Asset Image +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-asset-image +type ActivityAssetImage struct { + ApplicationAsset string `json:"application_asset_id"` + MediaProxyImage string `json:"image_id"` +} + +// Activity Secrets Struct +// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-secrets +type ActivitySecrets struct { + Join *string `json:"join,omitempty"` + Spectate *string `json:"spectate,omitempty"` + Match *string `json:"match,omitempty"` +} + +// Activity Flags +// https://discord.com/developers/docs/topics/gateway#activity-object-activity-flags +const ( + FlagActivityINSTANCE BitFlag = 1 << 0 + FlagActivityJOIN BitFlag = 1 << 1 + FlagActivitySPECTATE BitFlag = 1 << 2 + FlagActivityJOIN_REQUEST BitFlag = 1 << 3 + FlagActivitySYNC BitFlag = 1 << 4 + FlagActivityPLAY BitFlag = 1 << 5 + FlagActivityPARTY_PRIVACY_FRIENDS BitFlag = 1 << 6 + FlagActivityPARTY_PRIVACY_VOICE_CHANNEL BitFlag = 1 << 7 + FlagActivityEMBEDDED BitFlag = 1 << 8 +) + +// OAuth2 Scopes +// https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes +const ( + FlagOAuth2ScopeActivitiesRead = "activities.read" + FlagOAuth2ScopeActivitiesWrite = "activities.write" + FlagOAuth2ScopeApplicationsBuildsRead = "applications.builds.read" + FlagOAuth2ScopeApplicationsBuildsUpload = "applications.builds.upload" + FlagOAuth2ScopeApplicationsCommands = "applications.commands" + FlagOAuth2ScopeApplicationsCommandsUpdate = "applications.commands.update" + FlagOAuth2ScopeApplicationsCommandsPermissionsUpdate = "applications.commands.permissions.update" + FlagOAuth2ScopeApplicationsEntitlements = "applications.entitlements" + FlagOAuth2ScopeApplicationsStoreUpdate = "applications.store.update" + FlagOAuth2ScopeBot = "bot" + FlagOAuth2ScopeConnections = "connections" + FlagOAuth2ScopeDM_channelsRead = "dm_channels.read" + FlagOAuth2ScopeEmail = "email" + FlagOAuth2ScopeGDMJoin = "gdm.join" + FlagOAuth2ScopeGuilds = "guilds" + FlagOAuth2ScopeGuildsJoin = "guilds.join" + FlagOAuth2ScopeGuildsMembersRead = "guilds.members.read" + FlagOAuth2ScopeIdentify = "identify" + FlagOAuth2ScopeMessagesRead = "messages.read" + FlagOAuth2ScopeRelationshipsRead = "relationships.read" + FlagOAuth2ScopeRPC = "rpc" + FlagOAuth2ScopeRPCActivitiesWrite = "rpc.activities.write" + FlagOAuth2ScopeRPCNotificationsRead = "rpc.notifications.read" + FlagOAuth2ScopeRPCVoiceRead = "rpc.voice.read" + FlagOAuth2ScopeRPCVoiceWrite = "rpc.voice.write" + FlagOAuth2ScopeVoice = "voice" + FlagOAuth2ScopeWebhookIncoming = "webhook.incoming" +) + +// List Public Archived Threads Response Body +// https://discord.com/developers/docs/resources/channel#list-public-archived-threads-response-body +type ListPublicArchivedThreadsResponse struct { + Threads []*Channel `json:"threads"` + Members []*ThreadMember `json:"members"` + HasMore bool `json:"has_more"` +} + +// List Private Archived Threads Response Body +// https://discord.com/developers/docs/resources/channel#list-private-archived-threads-response-body +type ListPrivateArchivedThreadsResponse struct { + Threads []*Channel `json:"threads"` + Members []*ThreadMember `json:"members"` + HasMore bool `json:"has_more"` +} + +// List Joined Private Archived Threads Response Body +// https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads-response-body +type ListJoinedPrivateArchivedThreadsResponse struct { + Threads []*Channel `json:"threads"` + Members []*ThreadMember `json:"members"` + HasMore bool `json:"has_more"` +} + +// List Active Guild Threads Response Body +// https://discord.com/developers/docs/resources/guild#list-active-guild-threads-response-body +type ListActiveGuildThreadsResponse struct { + Threads []*Channel `json:"threads"` + Members []*ThreadMember `json:"members"` +} + +// Get Guild Prune Count Response Body +// https://discord.com/developers/docs/resources/guild#get-guild-prune-count +type GetGuildPruneCountResponse struct { + Pruned int `json:"pruned"` +} + +// Modify Guild MFA Level Response +// https://discord.com/developers/docs/resources/guild#modify-guild-mfa-level +type ModifyGuildMFALevelResponse struct { + Level Flag `json:"level"` +} + +// List Nitro Sticker Packs Response +// https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs +type ListNitroStickerPacksResponse struct { + StickerPacks []*StickerPack `json:"sticker_packs"` +} + +// Current Authorization Information Response Structure +// https://discord.com/developers/docs/topics/oauth2#get-current-authorization-information +type CurrentAuthorizationInformationResponse struct { + Application *Application `json:"application"` + Expires *time.Time `json:"expires"` + User *User `json:"user,omitempty"` + Scopes []int `json:"scopes"` +} + +// Get Gateway Response +// https://discord.com/developers/docs/topics/gateway#get-gateway-example-response +type GetGatewayResponse struct { + URL string `json:"url,omitempty"` +} + +// Get Gateway Bot Response +// https://discord.com/developers/docs/topics/gateway#get-gateway-example-response +type GetGatewayBotResponse struct { + Shards *int `json:"shards"` + URL string `json:"url"` + SessionStartLimit SessionStartLimit `json:"session_start_limit"` +} + +// Redirect URL +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-redirect-url-example +type RedirectURL struct { + Code string `url:"code,omitempty"` + State string `url:"state,omitempty"` + + // https://discord.com/developers/docs/topics/oauth2#advanced-bot-authorization + GuildID string `url:"guild_id,omitempty"` + Permissions BitFlag `url:"permissions,omitempty"` +} + +// Access Token Response +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-response +type AccessTokenResponse struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + Scope string `json:"scope,omitempty"` + ExpiresIn time.Duration `json:"expires_in,omitempty"` +} + +// Redirect URI +// https://discord.com/developers/docs/topics/oauth2#implicit-grant-redirect-url-example +type RedirectURI struct { + AccessToken string `url:"access_token,omitempty"` + TokenType string `url:"token_type,omitempty"` + Scope string `url:"scope,omitempty"` + State string `url:"state,omitempty"` + ExpiresIn time.Duration `url:"expires_in,omitempty"` +} + +// Client Credentials Access Token Response +// https://discord.com/developers/docs/topics/oauth2#client-credentials-grant-client-credentials-access-token-response +type ClientCredentialsAccessTokenResponse struct { + AccessToken string `json:"access_token,omitempty"` + TokenType string `json:"token_type,omitempty"` + Scope string `json:"scope,omitempty"` + ExpiresIn time.Duration `json:"expires_in,omitempty"` +} + +// Webhook Token Response +// https://discord.com/developers/docs/topics/oauth2#webhooks-webhook-token-response-example +type WebhookTokenResponse struct { + Webhook *Webhook `json:"webhook,omitempty"` + TokenType string `json:"token_type,omitempty"` + AccessToken string `json:"access_token,omitempty"` + Scope string `json:"scope,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + ExpiresIn time.Duration `json:"expires_in,omitempty"` +} + +// Extended Bot Authorization Access Token Response +// https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-response +type ExtendedBotAuthorizationAccessTokenResponse struct { + Guild *Guild `json:"guild,omitempty"` + TokenType string `json:"token_type,omitempty"` + AccessToken string `json:"access_token,omitempty"` + Scope string `json:"scope,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` + ExpiresIn time.Duration `json:"expires_in,omitempty"` +} + +// Pointer returns a pointer to the given value. +func Pointer[T any](v T) *T { + return &v +} + +// Pointer2 returns a double pointer to the given value. +// +// set `null` to true in order to point the double pointer to a `nil` pointer. +func Pointer2[T any](v T, null ...bool) **T { + if len(null) != 0 && null[0] { + return new(*T) + } + + pointer := Pointer(v) + + return &pointer +} + +// IsValue returns whether the given pointer contains a value. +func IsValue[T any](p *T) bool { + return p != nil +} + +// IsValue2 returns returns whether the given double pointer contains a pointer. +func IsValue2[T any](dp **T) bool { + return dp != nil +} + +// PointerCheck returns whether the given double pointer contains a value. +// +// returns IsValueNothing, IsValueNull, or IsValueValid. +// +// IsValueNothing indicates that the field was not provided. +// IsValueNull indicates the the field was provided with a null value. +// IsValueValid indicates that the field is a valid value. +func PointerCheck[T any](dp **T) PointerIndicator { + if dp != nil { + if *dp != nil { + return IsValueValid + } + + return IsValueNull + } + + return IsValueNothing +} + +func (c ActionsRow) ComponentType() Flag { + return FlagComponentTypeActionRow +} + +func (c Button) ComponentType() Flag { + return FlagComponentTypeButton +} + +func (c SelectMenu) ComponentType() Flag { + return FlagComponentTypeSelectMenu +} + +func (c TextInput) ComponentType() Flag { + return FlagComponentTypeTextInput +} + +func (d ApplicationCommandData) InteractionDataType() Flag { + return FlagInteractionTypeAPPLICATION_COMMAND +} + +func (d MessageComponentData) InteractionDataType() Flag { + return FlagInteractionTypeMESSAGE_COMPONENT +} + +func (d ModalSubmitData) InteractionDataType() Flag { + return FlagInteractionTypeMODAL_SUBMIT +} + +func (d Messages) InteractionCallbackDataType() Flag { + return FlagInteractionCallbackTypeCHANNEL_MESSAGE_WITH_SOURCE +} + +func (d Autocomplete) InteractionCallbackDataType() Flag { + return FlagInteractionCallbackTypeAPPLICATION_COMMAND_AUTOCOMPLETE_RESULT +} + +func (d Modal) InteractionCallbackDataType() Flag { + return FlagInteractionCallbackTypeMODAL +} + +// Discord API Endpoints +const ( + EndpointBaseURL = "https://discord.com/api/v" + VersionDiscordAPI + "/" + CDNEndpointBaseURL = "https://cdn.discordapp.com/" + achievements = "achievements" + active = "active" + appassets = "app-assets" + appicons = "app-icons" + applications = "applications" + archived = "archived" + auditlogs = "audit-logs" + authorize = "authorize" + automoderation = "auto-moderation" + avatars = "avatars" + banners = "banners" + bans = "bans" + bot = "bot" + bulkdelete = "bulk-delete" + callback = "callback" + channels = "channels" + commands = "commands" + connections = "connections" + crosspost = "crosspost" + discoverysplashes = "discovery-splashes" + embed = "embed" + emojis = "emojis" + followers = "followers" + gateway = "gateway" + github = "github" + guildevents = "guild-events" + guilds = "guilds" + icons = "icons" + integrations = "integrations" + interactions = "interactions" + invites = "invites" + me = "@me" + member = "member" + members = "members" + messages = "messages" + mfa = "mfa" + nick = "nick" + oauth = "oauth2" + original = "@original" + permissions = "permissions" + pins = "pins" + preview = "preview" + private = "private" + prune = "prune" + public = "public" + reactions = "reactions" + recipients = "recipients" + regions = "regions" + revoke = "revoke" + roleicons = "role-icons" + roles = "roles" + rules = "rules" + scheduledevents = "scheduled-events" + search = "search" + slack = "slack" + slash = "/" + splashes = "splashes" + stageinstances = "stage-instances" + stickerpacks = "sticker-packs" + stickers = "stickers" + store = "store" + teamicons = "team-icons" + templates = "templates" + threadmembers = "thread-members" + threads = "threads" + token = "token" + typing = "typing" + users = "users" + vanityurl = "vanity-url" + voice = "voice" + voicestates = "voice-states" + webhooks = "webhooks" + welcomescreen = "welcome-screen" + widget = "widget" + widgetjson = "widget.json" + widgetpng = "widget.png" +) + +// EndpointGetGlobalApplicationCommands builds a query for an HTTP request. +func EndpointGetGlobalApplicationCommands(applicationid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands +} + +// EndpointCreateGlobalApplicationCommand builds a query for an HTTP request. +func EndpointCreateGlobalApplicationCommand(applicationid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands +} + +// EndpointGetGlobalApplicationCommand builds a query for an HTTP request. +func EndpointGetGlobalApplicationCommand(applicationid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands + slash + commandid +} + +// EndpointEditGlobalApplicationCommand builds a query for an HTTP request. +func EndpointEditGlobalApplicationCommand(applicationid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands + slash + commandid +} + +// EndpointDeleteGlobalApplicationCommand builds a query for an HTTP request. +func EndpointDeleteGlobalApplicationCommand(applicationid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands + slash + commandid +} + +// EndpointBulkOverwriteGlobalApplicationCommands builds a query for an HTTP request. +func EndpointBulkOverwriteGlobalApplicationCommands(applicationid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + commands +} + +// EndpointGetGuildApplicationCommands builds a query for an HTTP request. +func EndpointGetGuildApplicationCommands(applicationid, guildid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands +} + +// EndpointCreateGuildApplicationCommand builds a query for an HTTP request. +func EndpointCreateGuildApplicationCommand(applicationid, guildid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands +} + +// EndpointGetGuildApplicationCommand builds a query for an HTTP request. +func EndpointGetGuildApplicationCommand(applicationid, guildid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + commandid +} + +// EndpointEditGuildApplicationCommand builds a query for an HTTP request. +func EndpointEditGuildApplicationCommand(applicationid, guildid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + commandid +} + +// EndpointDeleteGuildApplicationCommand builds a query for an HTTP request. +func EndpointDeleteGuildApplicationCommand(applicationid, guildid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + commandid +} + +// EndpointBulkOverwriteGuildApplicationCommands builds a query for an HTTP request. +func EndpointBulkOverwriteGuildApplicationCommands(applicationid, guildid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands +} + +// EndpointGetGuildApplicationCommandPermissions builds a query for an HTTP request. +func EndpointGetGuildApplicationCommandPermissions(applicationid, guildid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + permissions +} + +// EndpointGetApplicationCommandPermissions builds a query for an HTTP request. +func EndpointGetApplicationCommandPermissions(applicationid, guildid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + commandid + slash + permissions +} + +// EndpointEditApplicationCommandPermissions builds a query for an HTTP request. +func EndpointEditApplicationCommandPermissions(applicationid, guildid, commandid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + commandid + slash + permissions +} + +// EndpointBatchEditApplicationCommandPermissions builds a query for an HTTP request. +func EndpointBatchEditApplicationCommandPermissions(applicationid, guildid string) string { + return EndpointBaseURL + applications + slash + applicationid + slash + guilds + slash + guildid + slash + commands + slash + permissions +} + +// EndpointCreateInteractionResponse builds a query for an HTTP request. +func EndpointCreateInteractionResponse(interactionid, interactiontoken string) string { + return EndpointBaseURL + interactions + slash + interactionid + slash + interactiontoken + slash + callback +} + +// EndpointGetOriginalInteractionResponse builds a query for an HTTP request. +func EndpointGetOriginalInteractionResponse(applicationid, interactiontoken string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + original +} + +// EndpointEditOriginalInteractionResponse builds a query for an HTTP request. +func EndpointEditOriginalInteractionResponse(applicationid, interactiontoken string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + original +} + +// EndpointDeleteOriginalInteractionResponse builds a query for an HTTP request. +func EndpointDeleteOriginalInteractionResponse(applicationid, interactiontoken string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + original +} + +// EndpointCreateFollowupMessage builds a query for an HTTP request. +func EndpointCreateFollowupMessage(applicationid, interactiontoken string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken +} + +// EndpointGetFollowupMessage builds a query for an HTTP request. +func EndpointGetFollowupMessage(applicationid, interactiontoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + messageid +} + +// EndpointEditFollowupMessage builds a query for an HTTP request. +func EndpointEditFollowupMessage(applicationid, interactiontoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + messageid +} + +// EndpointDeleteFollowupMessage builds a query for an HTTP request. +func EndpointDeleteFollowupMessage(applicationid, interactiontoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + applicationid + slash + interactiontoken + slash + messages + slash + messageid +} + +// EndpointGetGuildAuditLog builds a query for an HTTP request. +func EndpointGetGuildAuditLog(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + auditlogs +} + +// EndpointListAutoModerationRulesForGuild builds a query for an HTTP request. +func EndpointListAutoModerationRulesForGuild(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + automoderation + slash + rules +} + +// EndpointGetAutoModerationRule builds a query for an HTTP request. +func EndpointGetAutoModerationRule(guildid, automoderationruleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + automoderation + slash + rules + slash + automoderationruleid +} + +// EndpointCreateAutoModerationRule builds a query for an HTTP request. +func EndpointCreateAutoModerationRule(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + automoderation + slash + rules +} + +// EndpointModifyAutoModerationRule builds a query for an HTTP request. +func EndpointModifyAutoModerationRule(guildid, automoderationruleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + automoderation + slash + rules + slash + automoderationruleid +} + +// EndpointDeleteAutoModerationRule builds a query for an HTTP request. +func EndpointDeleteAutoModerationRule(guildid, automoderationruleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + automoderation + slash + rules + slash + automoderationruleid +} + +// EndpointGetChannel builds a query for an HTTP request. +func EndpointGetChannel(channelid string) string { + return EndpointBaseURL + channels + slash + channelid +} + +// EndpointModifyChannel builds a query for an HTTP request. +func EndpointModifyChannel(channelid string) string { + return EndpointBaseURL + channels + slash + channelid +} + +// EndpointDeleteCloseChannel builds a query for an HTTP request. +func EndpointDeleteCloseChannel(channelid string) string { + return EndpointBaseURL + channels + slash + channelid +} + +// EndpointGetChannelMessages builds a query for an HTTP request. +func EndpointGetChannelMessages(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages +} + +// EndpointGetChannelMessage builds a query for an HTTP request. +func EndpointGetChannelMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid +} + +// EndpointCreateMessage builds a query for an HTTP request. +func EndpointCreateMessage(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages +} + +// EndpointCrosspostMessage builds a query for an HTTP request. +func EndpointCrosspostMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + crosspost +} + +// EndpointCreateReaction builds a query for an HTTP request. +func EndpointCreateReaction(channelid, messageid, emoji string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions + slash + emoji + slash + me +} + +// EndpointDeleteOwnReaction builds a query for an HTTP request. +func EndpointDeleteOwnReaction(channelid, messageid, emoji string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions + slash + emoji + slash + me +} + +// EndpointDeleteUserReaction builds a query for an HTTP request. +func EndpointDeleteUserReaction(channelid, messageid, emoji, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions + slash + emoji + slash + userid +} + +// EndpointGetReactions builds a query for an HTTP request. +func EndpointGetReactions(channelid, messageid, emoji string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions + slash + emoji +} + +// EndpointDeleteAllReactions builds a query for an HTTP request. +func EndpointDeleteAllReactions(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions +} + +// EndpointDeleteAllReactionsforEmoji builds a query for an HTTP request. +func EndpointDeleteAllReactionsforEmoji(channelid, messageid, emoji string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + reactions + slash + emoji +} + +// EndpointEditMessage builds a query for an HTTP request. +func EndpointEditMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid +} + +// EndpointDeleteMessage builds a query for an HTTP request. +func EndpointDeleteMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid +} + +// EndpointBulkDeleteMessages builds a query for an HTTP request. +func EndpointBulkDeleteMessages(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + bulkdelete +} + +// EndpointEditChannelPermissions builds a query for an HTTP request. +func EndpointEditChannelPermissions(channelid, overwriteid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + permissions + slash + overwriteid +} + +// EndpointGetChannelInvites builds a query for an HTTP request. +func EndpointGetChannelInvites(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + invites +} + +// EndpointCreateChannelInvite builds a query for an HTTP request. +func EndpointCreateChannelInvite(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + invites +} + +// EndpointDeleteChannelPermission builds a query for an HTTP request. +func EndpointDeleteChannelPermission(channelid, overwriteid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + permissions + slash + overwriteid +} + +// EndpointFollowAnnouncementChannel builds a query for an HTTP request. +func EndpointFollowAnnouncementChannel(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + followers +} + +// EndpointTriggerTypingIndicator builds a query for an HTTP request. +func EndpointTriggerTypingIndicator(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + typing +} + +// EndpointGetPinnedMessages builds a query for an HTTP request. +func EndpointGetPinnedMessages(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + pins +} + +// EndpointPinMessage builds a query for an HTTP request. +func EndpointPinMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + pins + slash + messageid +} + +// EndpointUnpinMessage builds a query for an HTTP request. +func EndpointUnpinMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + pins + slash + messageid +} + +// EndpointGroupDMAddRecipient builds a query for an HTTP request. +func EndpointGroupDMAddRecipient(channelid, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + recipients + slash + userid +} + +// EndpointGroupDMRemoveRecipient builds a query for an HTTP request. +func EndpointGroupDMRemoveRecipient(channelid, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + recipients + slash + userid +} + +// EndpointStartThreadfromMessage builds a query for an HTTP request. +func EndpointStartThreadfromMessage(channelid, messageid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + messages + slash + messageid + slash + threads +} + +// EndpointStartThreadwithoutMessage builds a query for an HTTP request. +func EndpointStartThreadwithoutMessage(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threads +} + +// EndpointStartThreadinForumChannel builds a query for an HTTP request. +func EndpointStartThreadinForumChannel(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threads +} + +// EndpointJoinThread builds a query for an HTTP request. +func EndpointJoinThread(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers + slash + me +} + +// EndpointAddThreadMember builds a query for an HTTP request. +func EndpointAddThreadMember(channelid, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers + slash + userid +} + +// EndpointLeaveThread builds a query for an HTTP request. +func EndpointLeaveThread(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers + slash + me +} + +// EndpointRemoveThreadMember builds a query for an HTTP request. +func EndpointRemoveThreadMember(channelid, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers + slash + userid +} + +// EndpointGetThreadMember builds a query for an HTTP request. +func EndpointGetThreadMember(channelid, userid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers + slash + userid +} + +// EndpointListThreadMembers builds a query for an HTTP request. +func EndpointListThreadMembers(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threadmembers +} + +// EndpointListPublicArchivedThreads builds a query for an HTTP request. +func EndpointListPublicArchivedThreads(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threads + slash + archived + slash + public +} + +// EndpointListPrivateArchivedThreads builds a query for an HTTP request. +func EndpointListPrivateArchivedThreads(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + threads + slash + archived + slash + private +} + +// EndpointListJoinedPrivateArchivedThreads builds a query for an HTTP request. +func EndpointListJoinedPrivateArchivedThreads(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + users + slash + me + slash + threads + slash + archived + slash + private +} + +// EndpointListGuildEmojis builds a query for an HTTP request. +func EndpointListGuildEmojis(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + emojis +} + +// EndpointGetGuildEmoji builds a query for an HTTP request. +func EndpointGetGuildEmoji(guildid, emojiid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + emojis + slash + emojiid +} + +// EndpointCreateGuildEmoji builds a query for an HTTP request. +func EndpointCreateGuildEmoji(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + emojis +} + +// EndpointModifyGuildEmoji builds a query for an HTTP request. +func EndpointModifyGuildEmoji(guildid, emojiid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + emojis + slash + emojiid +} + +// EndpointDeleteGuildEmoji builds a query for an HTTP request. +func EndpointDeleteGuildEmoji(guildid, emojiid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + emojis + slash + emojiid +} + +// EndpointCreateGuild builds a query for an HTTP request. +func EndpointCreateGuild() string { + return EndpointBaseURL + guilds +} + +// EndpointGetGuild builds a query for an HTTP request. +func EndpointGetGuild(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid +} + +// EndpointGetGuildPreview builds a query for an HTTP request. +func EndpointGetGuildPreview(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + preview +} + +// EndpointModifyGuild builds a query for an HTTP request. +func EndpointModifyGuild(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid +} + +// EndpointDeleteGuild builds a query for an HTTP request. +func EndpointDeleteGuild(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid +} + +// EndpointGetGuildChannels builds a query for an HTTP request. +func EndpointGetGuildChannels(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + channels +} + +// EndpointCreateGuildChannel builds a query for an HTTP request. +func EndpointCreateGuildChannel(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + channels +} + +// EndpointModifyGuildChannelPositions builds a query for an HTTP request. +func EndpointModifyGuildChannelPositions(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + channels +} + +// EndpointListActiveGuildThreads builds a query for an HTTP request. +func EndpointListActiveGuildThreads(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + threads + slash + active +} + +// EndpointGetGuildMember builds a query for an HTTP request. +func EndpointGetGuildMember(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid +} + +// EndpointListGuildMembers builds a query for an HTTP request. +func EndpointListGuildMembers(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members +} + +// EndpointSearchGuildMembers builds a query for an HTTP request. +func EndpointSearchGuildMembers(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + search +} + +// EndpointAddGuildMember builds a query for an HTTP request. +func EndpointAddGuildMember(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid +} + +// EndpointModifyGuildMember builds a query for an HTTP request. +func EndpointModifyGuildMember(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid +} + +// EndpointModifyCurrentMember builds a query for an HTTP request. +func EndpointModifyCurrentMember(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + me +} + +// EndpointModifyCurrentUserNick builds a query for an HTTP request. +func EndpointModifyCurrentUserNick(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + me + slash + nick +} + +// EndpointAddGuildMemberRole builds a query for an HTTP request. +func EndpointAddGuildMemberRole(guildid, userid, roleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid + slash + roles + slash + roleid +} + +// EndpointRemoveGuildMemberRole builds a query for an HTTP request. +func EndpointRemoveGuildMemberRole(guildid, userid, roleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid + slash + roles + slash + roleid +} + +// EndpointRemoveGuildMember builds a query for an HTTP request. +func EndpointRemoveGuildMember(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + members + slash + userid +} + +// EndpointGetGuildBans builds a query for an HTTP request. +func EndpointGetGuildBans(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + bans +} + +// EndpointGetGuildBan builds a query for an HTTP request. +func EndpointGetGuildBan(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + bans + slash + userid +} + +// EndpointCreateGuildBan builds a query for an HTTP request. +func EndpointCreateGuildBan(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + bans + slash + userid +} + +// EndpointRemoveGuildBan builds a query for an HTTP request. +func EndpointRemoveGuildBan(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + bans + slash + userid +} + +// EndpointGetGuildRoles builds a query for an HTTP request. +func EndpointGetGuildRoles(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + roles +} + +// EndpointCreateGuildRole builds a query for an HTTP request. +func EndpointCreateGuildRole(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + roles +} + +// EndpointModifyGuildRolePositions builds a query for an HTTP request. +func EndpointModifyGuildRolePositions(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + roles +} + +// EndpointModifyGuildRole builds a query for an HTTP request. +func EndpointModifyGuildRole(guildid, roleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + roles + slash + roleid +} + +// EndpointModifyGuildMFALevel builds a query for an HTTP request. +func EndpointModifyGuildMFALevel(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + mfa +} + +// EndpointDeleteGuildRole builds a query for an HTTP request. +func EndpointDeleteGuildRole(guildid, roleid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + roles + slash + roleid +} + +// EndpointGetGuildPruneCount builds a query for an HTTP request. +func EndpointGetGuildPruneCount(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + prune +} + +// EndpointBeginGuildPrune builds a query for an HTTP request. +func EndpointBeginGuildPrune(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + prune +} + +// EndpointGetGuildVoiceRegions builds a query for an HTTP request. +func EndpointGetGuildVoiceRegions(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + regions +} + +// EndpointGetGuildInvites builds a query for an HTTP request. +func EndpointGetGuildInvites(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + invites +} + +// EndpointGetGuildIntegrations builds a query for an HTTP request. +func EndpointGetGuildIntegrations(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + integrations +} + +// EndpointDeleteGuildIntegration builds a query for an HTTP request. +func EndpointDeleteGuildIntegration(guildid, integrationid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + integrations + slash + integrationid +} + +// EndpointGetGuildWidgetSettings builds a query for an HTTP request. +func EndpointGetGuildWidgetSettings(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + widget +} + +// EndpointModifyGuildWidget builds a query for an HTTP request. +func EndpointModifyGuildWidget(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + widget +} + +// EndpointGetGuildWidget builds a query for an HTTP request. +func EndpointGetGuildWidget(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + widgetjson +} + +// EndpointGetGuildVanityURL builds a query for an HTTP request. +func EndpointGetGuildVanityURL(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + vanityurl +} + +// EndpointGetGuildWidgetImage builds a query for an HTTP request. +func EndpointGetGuildWidgetImage(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + widgetpng +} + +// EndpointGetGuildWelcomeScreen builds a query for an HTTP request. +func EndpointGetGuildWelcomeScreen(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + welcomescreen +} + +// EndpointModifyGuildWelcomeScreen builds a query for an HTTP request. +func EndpointModifyGuildWelcomeScreen(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + welcomescreen +} + +// EndpointModifyCurrentUserVoiceState builds a query for an HTTP request. +func EndpointModifyCurrentUserVoiceState(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + voicestates + slash + me +} + +// EndpointModifyUserVoiceState builds a query for an HTTP request. +func EndpointModifyUserVoiceState(guildid, userid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + voicestates + slash + userid +} + +// EndpointListScheduledEventsforGuild builds a query for an HTTP request. +func EndpointListScheduledEventsforGuild(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents +} + +// EndpointCreateGuildScheduledEvent builds a query for an HTTP request. +func EndpointCreateGuildScheduledEvent(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents +} + +// EndpointGetGuildScheduledEvent builds a query for an HTTP request. +func EndpointGetGuildScheduledEvent(guildid, guildscheduledeventid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents + slash + guildscheduledeventid +} + +// EndpointModifyGuildScheduledEvent builds a query for an HTTP request. +func EndpointModifyGuildScheduledEvent(guildid, guildscheduledeventid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents + slash + guildscheduledeventid +} + +// EndpointDeleteGuildScheduledEvent builds a query for an HTTP request. +func EndpointDeleteGuildScheduledEvent(guildid, guildscheduledeventid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents + slash + guildscheduledeventid +} + +// EndpointGetGuildScheduledEventUsers builds a query for an HTTP request. +func EndpointGetGuildScheduledEventUsers(guildid, guildscheduledeventid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + scheduledevents + slash + guildscheduledeventid + slash + users +} + +// EndpointGetGuildTemplate builds a query for an HTTP request. +func EndpointGetGuildTemplate(templatecode string) string { + return EndpointBaseURL + guilds + slash + templates + slash + templatecode +} + +// EndpointCreateGuildfromGuildTemplate builds a query for an HTTP request. +func EndpointCreateGuildfromGuildTemplate(templatecode string) string { + return EndpointBaseURL + guilds + slash + templates + slash + templatecode +} + +// EndpointGetGuildTemplates builds a query for an HTTP request. +func EndpointGetGuildTemplates(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + templates +} + +// EndpointCreateGuildTemplate builds a query for an HTTP request. +func EndpointCreateGuildTemplate(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + templates +} + +// EndpointSyncGuildTemplate builds a query for an HTTP request. +func EndpointSyncGuildTemplate(guildid, templatecode string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + templates + slash + templatecode +} + +// EndpointModifyGuildTemplate builds a query for an HTTP request. +func EndpointModifyGuildTemplate(guildid, templatecode string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + templates + slash + templatecode +} + +// EndpointDeleteGuildTemplate builds a query for an HTTP request. +func EndpointDeleteGuildTemplate(guildid, templatecode string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + templates + slash + templatecode +} + +// EndpointGetInvite builds a query for an HTTP request. +func EndpointGetInvite(invitecode string) string { + return EndpointBaseURL + invites + slash + invitecode +} + +// EndpointDeleteInvite builds a query for an HTTP request. +func EndpointDeleteInvite(invitecode string) string { + return EndpointBaseURL + invites + slash + invitecode +} + +// EndpointCreateStageInstance builds a query for an HTTP request. +func EndpointCreateStageInstance() string { + return EndpointBaseURL + stageinstances +} + +// EndpointGetStageInstance builds a query for an HTTP request. +func EndpointGetStageInstance(channelid string) string { + return EndpointBaseURL + stageinstances + slash + channelid +} + +// EndpointModifyStageInstance builds a query for an HTTP request. +func EndpointModifyStageInstance(channelid string) string { + return EndpointBaseURL + stageinstances + slash + channelid +} + +// EndpointDeleteStageInstance builds a query for an HTTP request. +func EndpointDeleteStageInstance(channelid string) string { + return EndpointBaseURL + stageinstances + slash + channelid +} + +// EndpointGetSticker builds a query for an HTTP request. +func EndpointGetSticker(stickerid string) string { + return EndpointBaseURL + stickers + slash + stickerid +} + +// EndpointListNitroStickerPacks builds a query for an HTTP request. +func EndpointListNitroStickerPacks() string { + return EndpointBaseURL + stickerpacks +} + +// EndpointListGuildStickers builds a query for an HTTP request. +func EndpointListGuildStickers(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + stickers +} + +// EndpointGetGuildSticker builds a query for an HTTP request. +func EndpointGetGuildSticker(guildid, stickerid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + stickers + slash + stickerid +} + +// EndpointCreateGuildSticker builds a query for an HTTP request. +func EndpointCreateGuildSticker(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + stickers +} + +// EndpointModifyGuildSticker builds a query for an HTTP request. +func EndpointModifyGuildSticker(guildid, stickerid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + stickers + slash + stickerid +} + +// EndpointDeleteGuildSticker builds a query for an HTTP request. +func EndpointDeleteGuildSticker(guildid, stickerid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + stickers + slash + stickerid +} + +// EndpointGetCurrentUser builds a query for an HTTP request. +func EndpointGetCurrentUser() string { + return EndpointBaseURL + users + slash + me +} + +// EndpointGetUser builds a query for an HTTP request. +func EndpointGetUser(userid string) string { + return EndpointBaseURL + users + slash + userid +} + +// EndpointModifyCurrentUser builds a query for an HTTP request. +func EndpointModifyCurrentUser() string { + return EndpointBaseURL + users + slash + me +} + +// EndpointGetCurrentUserGuilds builds a query for an HTTP request. +func EndpointGetCurrentUserGuilds() string { + return EndpointBaseURL + users + slash + me + slash + guilds +} + +// EndpointGetCurrentUserGuildMember builds a query for an HTTP request. +func EndpointGetCurrentUserGuildMember(guildid string) string { + return EndpointBaseURL + users + slash + me + slash + guilds + slash + guildid + slash + member +} + +// EndpointLeaveGuild builds a query for an HTTP request. +func EndpointLeaveGuild(guildid string) string { + return EndpointBaseURL + users + slash + me + slash + guilds + slash + guildid +} + +// EndpointCreateDM builds a query for an HTTP request. +func EndpointCreateDM() string { + return EndpointBaseURL + users + slash + me + slash + channels +} + +// EndpointCreateGroupDM builds a query for an HTTP request. +func EndpointCreateGroupDM() string { + return EndpointBaseURL + users + slash + me + slash + channels +} + +// EndpointGetUserConnections builds a query for an HTTP request. +func EndpointGetUserConnections() string { + return EndpointBaseURL + users + slash + me + slash + connections +} + +// EndpointListVoiceRegions builds a query for an HTTP request. +func EndpointListVoiceRegions() string { + return EndpointBaseURL + voice + slash + regions +} + +// EndpointCreateWebhook builds a query for an HTTP request. +func EndpointCreateWebhook(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + webhooks +} + +// EndpointGetChannelWebhooks builds a query for an HTTP request. +func EndpointGetChannelWebhooks(channelid string) string { + return EndpointBaseURL + channels + slash + channelid + slash + webhooks +} + +// EndpointGetGuildWebhooks builds a query for an HTTP request. +func EndpointGetGuildWebhooks(guildid string) string { + return EndpointBaseURL + guilds + slash + guildid + slash + webhooks +} + +// EndpointGetWebhook builds a query for an HTTP request. +func EndpointGetWebhook(webhookid string) string { + return EndpointBaseURL + webhooks + slash + webhookid +} + +// EndpointGetWebhookwithToken builds a query for an HTTP request. +func EndpointGetWebhookwithToken(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken +} + +// EndpointModifyWebhook builds a query for an HTTP request. +func EndpointModifyWebhook(webhookid string) string { + return EndpointBaseURL + webhooks + slash + webhookid +} + +// EndpointModifyWebhookwithToken builds a query for an HTTP request. +func EndpointModifyWebhookwithToken(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken +} + +// EndpointDeleteWebhook builds a query for an HTTP request. +func EndpointDeleteWebhook(webhookid string) string { + return EndpointBaseURL + webhooks + slash + webhookid +} + +// EndpointDeleteWebhookwithToken builds a query for an HTTP request. +func EndpointDeleteWebhookwithToken(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken +} + +// EndpointExecuteWebhook builds a query for an HTTP request. +func EndpointExecuteWebhook(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken +} + +// EndpointExecuteSlackCompatibleWebhook builds a query for an HTTP request. +func EndpointExecuteSlackCompatibleWebhook(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken + slash + slack +} + +// EndpointExecuteGitHubCompatibleWebhook builds a query for an HTTP request. +func EndpointExecuteGitHubCompatibleWebhook(webhookid, webhooktoken string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken + slash + github +} + +// EndpointGetWebhookMessage builds a query for an HTTP request. +func EndpointGetWebhookMessage(webhookid, webhooktoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken + slash + messages + slash + messageid +} + +// EndpointEditWebhookMessage builds a query for an HTTP request. +func EndpointEditWebhookMessage(webhookid, webhooktoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken + slash + messages + slash + messageid +} + +// EndpointDeleteWebhookMessage builds a query for an HTTP request. +func EndpointDeleteWebhookMessage(webhookid, webhooktoken, messageid string) string { + return EndpointBaseURL + webhooks + slash + webhookid + slash + webhooktoken + slash + messages + slash + messageid +} + +// EndpointGetGateway builds a query for an HTTP request. +func EndpointGetGateway() string { + return EndpointBaseURL + gateway +} + +// EndpointGetGatewayBot builds a query for an HTTP request. +func EndpointGetGatewayBot() string { + return EndpointBaseURL + gateway + slash + bot +} + +// EndpointAuthorizationURL builds a query for an HTTP request. +func EndpointAuthorizationURL() string { + return EndpointBaseURL + oauth + slash + authorize +} + +// EndpointTokenURL builds a query for an HTTP request. +func EndpointTokenURL() string { + return EndpointBaseURL + oauth + slash + token +} + +// EndpointTokenRevocationURL builds a query for an HTTP request. +func EndpointTokenRevocationURL() string { + return EndpointBaseURL + oauth + slash + token + slash + revoke +} + +// EndpointGetCurrentBotApplicationInformation builds a query for an HTTP request. +func EndpointGetCurrentBotApplicationInformation() string { + return EndpointBaseURL + oauth + slash + applications + slash + me +} + +// EndpointGetCurrentAuthorizationInformation builds a query for an HTTP request. +func EndpointGetCurrentAuthorizationInformation() string { + return EndpointBaseURL + oauth + slash + me +} + +// CDNEndpointCustomEmoji builds a query for an HTTP request. +func CDNEndpointCustomEmoji(emojiid string) string { + return CDNEndpointBaseURL + emojis + slash + emojiid +} + +// CDNEndpointGuildIcon builds a query for an HTTP request. +func CDNEndpointGuildIcon(guildid, guildicon string) string { + return CDNEndpointBaseURL + icons + slash + guildid + slash + guildicon +} + +// CDNEndpointGuildSplash builds a query for an HTTP request. +func CDNEndpointGuildSplash(guildid, guildsplash string) string { + return CDNEndpointBaseURL + splashes + slash + guildid + slash + guildsplash +} + +// CDNEndpointGuildDiscoverySplash builds a query for an HTTP request. +func CDNEndpointGuildDiscoverySplash(guildid, guilddiscoverysplash string) string { + return CDNEndpointBaseURL + discoverysplashes + slash + guildid + slash + guilddiscoverysplash +} + +// CDNEndpointGuildBanner builds a query for an HTTP request. +func CDNEndpointGuildBanner(guildid, guildbanner string) string { + return CDNEndpointBaseURL + banners + slash + guildid + slash + guildbanner +} + +// CDNEndpointUserBanner builds a query for an HTTP request. +func CDNEndpointUserBanner(userid, userbanner string) string { + return CDNEndpointBaseURL + banners + slash + userid + slash + userbanner +} + +// CDNEndpointDefaultUserAvatar builds a query for an HTTP request. +func CDNEndpointDefaultUserAvatar(userdiscriminator string) string { + return CDNEndpointBaseURL + embed + slash + avatars + slash + userdiscriminator +} + +// CDNEndpointUserAvatar builds a query for an HTTP request. +func CDNEndpointUserAvatar(userid, useravatar string) string { + return CDNEndpointBaseURL + avatars + slash + userid + slash + useravatar +} + +// CDNEndpointGuildMemberAvatar builds a query for an HTTP request. +func CDNEndpointGuildMemberAvatar(guildid, userid, memberavatar string) string { + return CDNEndpointBaseURL + guilds + slash + guildid + slash + users + slash + userid + slash + avatars + slash + memberavatar +} + +// CDNEndpointApplicationIcon builds a query for an HTTP request. +func CDNEndpointApplicationIcon(applicationid, icon string) string { + return CDNEndpointBaseURL + appicons + slash + applicationid + slash + icon +} + +// CDNEndpointApplicationCover builds a query for an HTTP request. +func CDNEndpointApplicationCover(applicationid, coverimage string) string { + return CDNEndpointBaseURL + appicons + slash + applicationid + slash + coverimage +} + +// CDNEndpointApplicationAsset builds a query for an HTTP request. +func CDNEndpointApplicationAsset(applicationid, assetid string) string { + return CDNEndpointBaseURL + appassets + slash + applicationid + slash + assetid +} + +// CDNEndpointAchievementIcon builds a query for an HTTP request. +func CDNEndpointAchievementIcon(applicationid, achievementid, iconhash string) string { + return CDNEndpointBaseURL + appassets + slash + applicationid + slash + achievements + slash + achievementid + slash + icons + slash + iconhash +} + +// CDNEndpointStickerPackBanner builds a query for an HTTP request. +func CDNEndpointStickerPackBanner(applicationid, stickerpackbannerassetid string) string { + return CDNEndpointBaseURL + appassets + slash + applicationid + slash + store + slash + stickerpackbannerassetid +} + +// CDNEndpointTeamIcon builds a query for an HTTP request. +func CDNEndpointTeamIcon(teamid, teamicon string) string { + return CDNEndpointBaseURL + teamicons + slash + teamid + slash + teamicon +} + +// CDNEndpointSticker builds a query for an HTTP request. +func CDNEndpointSticker(stickerid string) string { + return CDNEndpointBaseURL + stickers + slash + stickerid +} + +// CDNEndpointRoleIcon builds a query for an HTTP request. +func CDNEndpointRoleIcon(roleid, roleicon string) string { + return CDNEndpointBaseURL + roleicons + slash + roleid + slash + roleicon +} + +// CDNEndpointGuildScheduledEventCover builds a query for an HTTP request. +func CDNEndpointGuildScheduledEventCover(scheduledeventid, scheduledeventcoverimage string) string { + return CDNEndpointBaseURL + guildevents + slash + scheduledeventid + slash + scheduledeventcoverimage +} + +// CDNEndpointGuildMemberBanner builds a query for an HTTP request. +func CDNEndpointGuildMemberBanner(guildid, userid, memberbanner string) string { + return CDNEndpointBaseURL + guilds + slash + guildid + slash + users + slash + userid + slash + banners + slash + memberbanner +} + +var ( + EndpointModifyChannelGroupDM = EndpointModifyChannel + EndpointModifyChannelGuild = EndpointModifyChannel + EndpointModifyChannelThread = EndpointModifyChannel +) + +// Send Request Error Messages. +const ( + errSendMarshal = "marshalling an HTTP body: %w" + errUnmarshal = "error unmarshalling into %T: %w" + errRateLimit = "error converting the HTTP rate limit header %q: %w" +) + +// ErrorRequest represents an HTTP Request error that occurs when an attempt to send a request fails. +type ErrorRequest struct { + // Err represents the error that occurred while performing the action. + Err error + + // ClientID represents the Application ID of the request sender. + ClientID string + + // CorrelationID represents the ID used to correlate the request to other logs. + CorrelationID string + + // RouteID represents the ID (hash) of the Disgo Route. + RouteID string + + // ResourceID represents the ID (hash) of the resource for the route. + ResourceID string + + // Endpoint represents the endpoint the request was sent to. + Endpoint string +} + +func (e ErrorRequest) Error() string { + return fmt.Errorf("REQUEST ERROR: client %q: x %q: route: %q: resource: %q: endpoint: %q: error: %w", + e.ClientID, e.CorrelationID, e.RouteID, e.ResourceID, e.Endpoint, e.Err).Error() +} + +// Status Code Error Messages. +const ( + errStatusCodeKnown = "Status Code %d: %v" + errStatusCodeUnknown = "Status Code %d: Unknown status code error from Discord" +) + +// StatusCodeError handles a Discord API HTTP Status Code and returns the relevant error message. +func StatusCodeError(status int) error { + if msg, ok := HTTPResponseCodes[status]; ok { + return fmt.Errorf(errStatusCodeKnown, status, msg) + } + + return fmt.Errorf(errStatusCodeUnknown, status) +} + +// JSON Error Code Messages. +const ( + errJSONErrorCodeKnown = "JSON Error Code %d: %v" + errJSONErrorUnknown = "JSON Error Code %d: Unknown JSON Error Code from Discord" +) + +// JSONCodeError handles a Discord API JSON Error Code and returns the relevant error message. +func JSONCodeError(status int) error { + if msg, ok := JSONErrorCodes[status]; ok { + return fmt.Errorf(errJSONErrorCodeKnown, status, msg) + } + + return fmt.Errorf(errJSONErrorUnknown, status) +} + +// Event Handler Error Messages. +const ( + errHandleNotRemoved = "event handler was not added" + errRemoveInvalidIndex = "event handler cannot be removed since there is no event handler at index %d" +) + +// ErrorEventHandler represents an Event Handler error that occurs when an attempt to +// add or remove an event handler fails. +type ErrorEventHandler struct { + // Err represents the error that occurred while performing the action. + Err error + + // ClientID represents the Application ID of the event handler owner. + ClientID string + + // Event represents the event of the involved handler. + Event string +} + +func (e ErrorEventHandler) Error() string { + return fmt.Errorf("EVENT HANDLER ERROR: client %q: event %q: error: %w", + e.ClientID, e.Event, e.Err).Error() +} + +const ( + ErrorEventActionUnmarshal = "unmarshalling" + ErrorEventActionMarshal = "marshalling" + ErrorEventActionRead = "reading" + ErrorEventActionWrite = "writing" +) + +// ErrorEvent represents a WebSocket error that occurs when an attempt to {action} an event fails. +type ErrorEvent struct { + // ClientID represents the Application ID of the event handler caller. + ClientID string + + // Event represents the name of the event involved in this error. + Event string + + // Err represents the error that occurred while performing the action. + Err error + + // Action represents the action that prompted the error. + // + // ErrorEventAction's can be one of four values: + // ErrorEventActionUnmarshal: an error occurred while unmarshalling the Event from a JSON. + // ErrorEventActionMarshal: an error occurred while marshalling the Event to a JSON. + // ErrorEventActionRead: an error occurred while reading the Event from a Websocket Connection. + // ErrorEventActionWrite: an error occurred while writing the Event to a Websocket Connection. + Action string +} + +func (e ErrorEvent) Error() string { + return fmt.Errorf("EVENT ERROR: client %q: event %q: action: %q, error: %w", + e.ClientID, e.Event, e.Action, e.Err).Error() +} + +// ErrorSession represents a WebSocket Session error that occurs during an active session. +type ErrorSession struct { + // Err represents the error that occurred. + Err error + + // SessionID represents the ID of the Session. + SessionID string +} + +func (e ErrorSession) Error() string { + return fmt.Errorf("SESSION ERROR: session %q: error: %w", e.SessionID, e.Err).Error() +} + +const ( + ErrConnectionSession = "Discord Gateway" +) + +// ErrorDisconnect represents a disconnection error that occurs when +// an attempt to gracefully disconnect from a connection fails. +type ErrorDisconnect struct { + // Action represents the error that prompted the disconnection (if applicable). + Action error + + // Err represents the error that occurred while disconnecting. + Err error + + // Connection represents the name of the connection. + Connection string +} + +func (e ErrorDisconnect) Error() string { + return fmt.Errorf("error disconnecting from %q\n"+ + "\tDisconnect(): %v\n"+ + "\treason: %w\n", + e.Connection, e.Err, e.Action).Error() +} + +// Handlers represents a bot's event handlers. +type Handlers struct { + Hello []func(*Hello) + Ready []func(*Ready) + Resumed []func(*Resumed) + Reconnect []func(*Reconnect) + InvalidSession []func(*InvalidSession) + ApplicationCommandPermissionsUpdate []func(*ApplicationCommandPermissionsUpdate) + AutoModerationRuleCreate []func(*AutoModerationRuleCreate) + AutoModerationRuleUpdate []func(*AutoModerationRuleUpdate) + AutoModerationRuleDelete []func(*AutoModerationRuleDelete) + AutoModerationActionExecution []func(*AutoModerationActionExecution) + InteractionCreate []func(*InteractionCreate) + VoiceServerUpdate []func(*VoiceServerUpdate) + GuildMembersChunk []func(*GuildMembersChunk) + UserUpdate []func(*UserUpdate) + ChannelCreate []func(*ChannelCreate) + ChannelUpdate []func(*ChannelUpdate) + ChannelDelete []func(*ChannelDelete) + ChannelPinsUpdate []func(*ChannelPinsUpdate) + ThreadCreate []func(*ThreadCreate) + ThreadUpdate []func(*ThreadUpdate) + ThreadDelete []func(*ThreadDelete) + ThreadListSync []func(*ThreadListSync) + ThreadMemberUpdate []func(*ThreadMemberUpdate) + ThreadMembersUpdate []func(*ThreadMembersUpdate) + GuildCreate []func(*GuildCreate) + GuildUpdate []func(*GuildUpdate) + GuildDelete []func(*GuildDelete) + GuildBanAdd []func(*GuildBanAdd) + GuildBanRemove []func(*GuildBanRemove) + GuildEmojisUpdate []func(*GuildEmojisUpdate) + GuildStickersUpdate []func(*GuildStickersUpdate) + GuildIntegrationsUpdate []func(*GuildIntegrationsUpdate) + GuildMemberAdd []func(*GuildMemberAdd) + GuildMemberRemove []func(*GuildMemberRemove) + GuildMemberUpdate []func(*GuildMemberUpdate) + GuildRoleCreate []func(*GuildRoleCreate) + GuildRoleUpdate []func(*GuildRoleUpdate) + GuildRoleDelete []func(*GuildRoleDelete) + GuildScheduledEventCreate []func(*GuildScheduledEventCreate) + GuildScheduledEventUpdate []func(*GuildScheduledEventUpdate) + GuildScheduledEventDelete []func(*GuildScheduledEventDelete) + GuildScheduledEventUserAdd []func(*GuildScheduledEventUserAdd) + GuildScheduledEventUserRemove []func(*GuildScheduledEventUserRemove) + IntegrationCreate []func(*IntegrationCreate) + IntegrationUpdate []func(*IntegrationUpdate) + IntegrationDelete []func(*IntegrationDelete) + InviteCreate []func(*InviteCreate) + InviteDelete []func(*InviteDelete) + MessageCreate []func(*MessageCreate) + MessageUpdate []func(*MessageUpdate) + MessageDelete []func(*MessageDelete) + MessageDeleteBulk []func(*MessageDeleteBulk) + MessageReactionAdd []func(*MessageReactionAdd) + MessageReactionRemove []func(*MessageReactionRemove) + MessageReactionRemoveAll []func(*MessageReactionRemoveAll) + MessageReactionRemoveEmoji []func(*MessageReactionRemoveEmoji) + PresenceUpdate []func(*PresenceUpdate) + StageInstanceCreate []func(*StageInstanceCreate) + StageInstanceDelete []func(*StageInstanceDelete) + StageInstanceUpdate []func(*StageInstanceUpdate) + TypingStart []func(*TypingStart) + VoiceStateUpdate []func(*VoiceStateUpdate) + WebhooksUpdate []func(*WebhooksUpdate) + mu sync.RWMutex +} + +// Handle adds an event handler for the given event to the bot. +func (bot *Client) Handle(eventname string, function interface{}) error { + bot.Handlers.mu.Lock() + defer bot.Handlers.mu.Unlock() + + switch eventname { + case FlagGatewayEventNameHello: + if f, ok := function.(func(*Hello)); ok { + bot.Handlers.Hello = append(bot.Handlers.Hello, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameReady: + if f, ok := function.(func(*Ready)); ok { + bot.Handlers.Ready = append(bot.Handlers.Ready, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameResumed: + if f, ok := function.(func(*Resumed)); ok { + bot.Handlers.Resumed = append(bot.Handlers.Resumed, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameReconnect: + if f, ok := function.(func(*Reconnect)); ok { + bot.Handlers.Reconnect = append(bot.Handlers.Reconnect, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameInvalidSession: + if f, ok := function.(func(*InvalidSession)); ok { + bot.Handlers.InvalidSession = append(bot.Handlers.InvalidSession, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameApplicationCommandPermissionsUpdate: + if f, ok := function.(func(*ApplicationCommandPermissionsUpdate)); ok { + bot.Handlers.ApplicationCommandPermissionsUpdate = append(bot.Handlers.ApplicationCommandPermissionsUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameAutoModerationRuleCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] { + bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] = true + bot.Config.Gateway.Intents |= FlagIntentAUTO_MODERATION_CONFIGURATION + } + + if f, ok := function.(func(*AutoModerationRuleCreate)); ok { + bot.Handlers.AutoModerationRuleCreate = append(bot.Handlers.AutoModerationRuleCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameAutoModerationRuleUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] { + bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] = true + bot.Config.Gateway.Intents |= FlagIntentAUTO_MODERATION_CONFIGURATION + } + + if f, ok := function.(func(*AutoModerationRuleUpdate)); ok { + bot.Handlers.AutoModerationRuleUpdate = append(bot.Handlers.AutoModerationRuleUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameAutoModerationRuleDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] { + bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_CONFIGURATION] = true + bot.Config.Gateway.Intents |= FlagIntentAUTO_MODERATION_CONFIGURATION + } + + if f, ok := function.(func(*AutoModerationRuleDelete)); ok { + bot.Handlers.AutoModerationRuleDelete = append(bot.Handlers.AutoModerationRuleDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameAutoModerationActionExecution: + if !bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_EXECUTION] { + bot.Config.Gateway.IntentSet[FlagIntentAUTO_MODERATION_EXECUTION] = true + bot.Config.Gateway.Intents |= FlagIntentAUTO_MODERATION_EXECUTION + } + + if f, ok := function.(func(*AutoModerationActionExecution)); ok { + bot.Handlers.AutoModerationActionExecution = append(bot.Handlers.AutoModerationActionExecution, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameInteractionCreate: + if f, ok := function.(func(*InteractionCreate)); ok { + bot.Handlers.InteractionCreate = append(bot.Handlers.InteractionCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameVoiceServerUpdate: + if f, ok := function.(func(*VoiceServerUpdate)); ok { + bot.Handlers.VoiceServerUpdate = append(bot.Handlers.VoiceServerUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildMembersChunk: + if f, ok := function.(func(*GuildMembersChunk)); ok { + bot.Handlers.GuildMembersChunk = append(bot.Handlers.GuildMembersChunk, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameUserUpdate: + if f, ok := function.(func(*UserUpdate)); ok { + bot.Handlers.UserUpdate = append(bot.Handlers.UserUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameChannelCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ChannelCreate)); ok { + bot.Handlers.ChannelCreate = append(bot.Handlers.ChannelCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameChannelUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ChannelUpdate)); ok { + bot.Handlers.ChannelUpdate = append(bot.Handlers.ChannelUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameChannelDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ChannelDelete)); ok { + bot.Handlers.ChannelDelete = append(bot.Handlers.ChannelDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameChannelPinsUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGES + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ChannelPinsUpdate)); ok { + bot.Handlers.ChannelPinsUpdate = append(bot.Handlers.ChannelPinsUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ThreadCreate)); ok { + bot.Handlers.ThreadCreate = append(bot.Handlers.ThreadCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ThreadUpdate)); ok { + bot.Handlers.ThreadUpdate = append(bot.Handlers.ThreadUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ThreadDelete)); ok { + bot.Handlers.ThreadDelete = append(bot.Handlers.ThreadDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadListSync: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ThreadListSync)); ok { + bot.Handlers.ThreadListSync = append(bot.Handlers.ThreadListSync, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadMemberUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*ThreadMemberUpdate)); ok { + bot.Handlers.ThreadMemberUpdate = append(bot.Handlers.ThreadMemberUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameThreadMembersUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MEMBERS + } + + if f, ok := function.(func(*ThreadMembersUpdate)); ok { + bot.Handlers.ThreadMembersUpdate = append(bot.Handlers.ThreadMembersUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildCreate)); ok { + bot.Handlers.GuildCreate = append(bot.Handlers.GuildCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildUpdate)); ok { + bot.Handlers.GuildUpdate = append(bot.Handlers.GuildUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildDelete)); ok { + bot.Handlers.GuildDelete = append(bot.Handlers.GuildDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildBanAdd: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_BANS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_BANS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_BANS + } + + if f, ok := function.(func(*GuildBanAdd)); ok { + bot.Handlers.GuildBanAdd = append(bot.Handlers.GuildBanAdd, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildBanRemove: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_BANS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_BANS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_BANS + } + + if f, ok := function.(func(*GuildBanRemove)); ok { + bot.Handlers.GuildBanRemove = append(bot.Handlers.GuildBanRemove, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildEmojisUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_EMOJIS_AND_STICKERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_EMOJIS_AND_STICKERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_EMOJIS_AND_STICKERS + } + + if f, ok := function.(func(*GuildEmojisUpdate)); ok { + bot.Handlers.GuildEmojisUpdate = append(bot.Handlers.GuildEmojisUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildStickersUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_EMOJIS_AND_STICKERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_EMOJIS_AND_STICKERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_EMOJIS_AND_STICKERS + } + + if f, ok := function.(func(*GuildStickersUpdate)); ok { + bot.Handlers.GuildStickersUpdate = append(bot.Handlers.GuildStickersUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildIntegrationsUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INTEGRATIONS + } + + if f, ok := function.(func(*GuildIntegrationsUpdate)); ok { + bot.Handlers.GuildIntegrationsUpdate = append(bot.Handlers.GuildIntegrationsUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildMemberAdd: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MEMBERS + } + + if f, ok := function.(func(*GuildMemberAdd)); ok { + bot.Handlers.GuildMemberAdd = append(bot.Handlers.GuildMemberAdd, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildMemberRemove: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MEMBERS + } + + if f, ok := function.(func(*GuildMemberRemove)); ok { + bot.Handlers.GuildMemberRemove = append(bot.Handlers.GuildMemberRemove, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildMemberUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MEMBERS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MEMBERS + } + + if f, ok := function.(func(*GuildMemberUpdate)); ok { + bot.Handlers.GuildMemberUpdate = append(bot.Handlers.GuildMemberUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildRoleCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildRoleCreate)); ok { + bot.Handlers.GuildRoleCreate = append(bot.Handlers.GuildRoleCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildRoleUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildRoleUpdate)); ok { + bot.Handlers.GuildRoleUpdate = append(bot.Handlers.GuildRoleUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildRoleDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*GuildRoleDelete)); ok { + bot.Handlers.GuildRoleDelete = append(bot.Handlers.GuildRoleDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildScheduledEventCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_SCHEDULED_EVENTS + } + + if f, ok := function.(func(*GuildScheduledEventCreate)); ok { + bot.Handlers.GuildScheduledEventCreate = append(bot.Handlers.GuildScheduledEventCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildScheduledEventUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_SCHEDULED_EVENTS + } + + if f, ok := function.(func(*GuildScheduledEventUpdate)); ok { + bot.Handlers.GuildScheduledEventUpdate = append(bot.Handlers.GuildScheduledEventUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildScheduledEventDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_SCHEDULED_EVENTS + } + + if f, ok := function.(func(*GuildScheduledEventDelete)); ok { + bot.Handlers.GuildScheduledEventDelete = append(bot.Handlers.GuildScheduledEventDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildScheduledEventUserAdd: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_SCHEDULED_EVENTS + } + + if f, ok := function.(func(*GuildScheduledEventUserAdd)); ok { + bot.Handlers.GuildScheduledEventUserAdd = append(bot.Handlers.GuildScheduledEventUserAdd, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameGuildScheduledEventUserRemove: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_SCHEDULED_EVENTS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_SCHEDULED_EVENTS + } + + if f, ok := function.(func(*GuildScheduledEventUserRemove)); ok { + bot.Handlers.GuildScheduledEventUserRemove = append(bot.Handlers.GuildScheduledEventUserRemove, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameIntegrationCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INTEGRATIONS + } + + if f, ok := function.(func(*IntegrationCreate)); ok { + bot.Handlers.IntegrationCreate = append(bot.Handlers.IntegrationCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameIntegrationUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INTEGRATIONS + } + + if f, ok := function.(func(*IntegrationUpdate)); ok { + bot.Handlers.IntegrationUpdate = append(bot.Handlers.IntegrationUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameIntegrationDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INTEGRATIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INTEGRATIONS + } + + if f, ok := function.(func(*IntegrationDelete)); ok { + bot.Handlers.IntegrationDelete = append(bot.Handlers.IntegrationDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameInviteCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INVITES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INVITES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INVITES + } + + if f, ok := function.(func(*InviteCreate)); ok { + bot.Handlers.InviteCreate = append(bot.Handlers.InviteCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameInviteDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_INVITES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_INVITES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_INVITES + } + + if f, ok := function.(func(*InviteDelete)); ok { + bot.Handlers.InviteDelete = append(bot.Handlers.InviteDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGES + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGES + } + + if f, ok := function.(func(*MessageCreate)); ok { + bot.Handlers.MessageCreate = append(bot.Handlers.MessageCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGES + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGES + } + + if f, ok := function.(func(*MessageUpdate)); ok { + bot.Handlers.MessageUpdate = append(bot.Handlers.MessageUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGES + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGES + } + + if f, ok := function.(func(*MessageDelete)); ok { + bot.Handlers.MessageDelete = append(bot.Handlers.MessageDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageDeleteBulk: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGES + } + + if f, ok := function.(func(*MessageDeleteBulk)); ok { + bot.Handlers.MessageDeleteBulk = append(bot.Handlers.MessageDeleteBulk, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageReactionAdd: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGE_REACTIONS + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGE_REACTIONS + } + + if f, ok := function.(func(*MessageReactionAdd)); ok { + bot.Handlers.MessageReactionAdd = append(bot.Handlers.MessageReactionAdd, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageReactionRemove: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGE_REACTIONS + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGE_REACTIONS + } + + if f, ok := function.(func(*MessageReactionRemove)); ok { + bot.Handlers.MessageReactionRemove = append(bot.Handlers.MessageReactionRemove, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageReactionRemoveAll: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGE_REACTIONS + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGE_REACTIONS + } + + if f, ok := function.(func(*MessageReactionRemoveAll)); ok { + bot.Handlers.MessageReactionRemoveAll = append(bot.Handlers.MessageReactionRemoveAll, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameMessageReactionRemoveEmoji: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGE_REACTIONS + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGE_REACTIONS + } + + if f, ok := function.(func(*MessageReactionRemoveEmoji)); ok { + bot.Handlers.MessageReactionRemoveEmoji = append(bot.Handlers.MessageReactionRemoveEmoji, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNamePresenceUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_PRESENCES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_PRESENCES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_PRESENCES + } + + if f, ok := function.(func(*PresenceUpdate)); ok { + bot.Handlers.PresenceUpdate = append(bot.Handlers.PresenceUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameStageInstanceCreate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*StageInstanceCreate)); ok { + bot.Handlers.StageInstanceCreate = append(bot.Handlers.StageInstanceCreate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameStageInstanceDelete: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*StageInstanceDelete)); ok { + bot.Handlers.StageInstanceDelete = append(bot.Handlers.StageInstanceDelete, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameStageInstanceUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILDS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILDS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILDS + } + + if f, ok := function.(func(*StageInstanceUpdate)); ok { + bot.Handlers.StageInstanceUpdate = append(bot.Handlers.StageInstanceUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameTypingStart: + if !bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_TYPING] { + bot.Config.Gateway.IntentSet[FlagIntentDIRECT_MESSAGE_TYPING] = true + bot.Config.Gateway.Intents |= FlagIntentDIRECT_MESSAGE_TYPING + } + + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_MESSAGE_REACTIONS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_MESSAGE_REACTIONS + } + + if f, ok := function.(func(*TypingStart)); ok { + bot.Handlers.TypingStart = append(bot.Handlers.TypingStart, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameVoiceStateUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_VOICE_STATES] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_VOICE_STATES] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_VOICE_STATES + } + + if f, ok := function.(func(*VoiceStateUpdate)); ok { + bot.Handlers.VoiceStateUpdate = append(bot.Handlers.VoiceStateUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + + case FlagGatewayEventNameWebhooksUpdate: + if !bot.Config.Gateway.IntentSet[FlagIntentGUILD_WEBHOOKS] { + bot.Config.Gateway.IntentSet[FlagIntentGUILD_WEBHOOKS] = true + bot.Config.Gateway.Intents |= FlagIntentGUILD_WEBHOOKS + } + + if f, ok := function.(func(*WebhooksUpdate)); ok { + bot.Handlers.WebhooksUpdate = append(bot.Handlers.WebhooksUpdate, f) + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("added event handler") + return nil + } + } + + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf("%s", errHandleNotRemoved), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + + return err +} + +// Remove removes the event handler at the given index from the bot. +// This function does NOT remove intents automatically. +func (bot *Client) Remove(eventname string, index int) error { + bot.Handlers.mu.Lock() + defer bot.Handlers.mu.Unlock() + + switch eventname { + case FlagGatewayEventNameHello: + if len(bot.Handlers.Hello) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.Hello = append(bot.Handlers.Hello[:index], bot.Handlers.Hello[index+1:]...) + + case FlagGatewayEventNameReady: + if len(bot.Handlers.Ready) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.Ready = append(bot.Handlers.Ready[:index], bot.Handlers.Ready[index+1:]...) + + case FlagGatewayEventNameResumed: + if len(bot.Handlers.Resumed) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.Resumed = append(bot.Handlers.Resumed[:index], bot.Handlers.Resumed[index+1:]...) + + case FlagGatewayEventNameReconnect: + if len(bot.Handlers.Reconnect) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.Reconnect = append(bot.Handlers.Reconnect[:index], bot.Handlers.Reconnect[index+1:]...) + + case FlagGatewayEventNameInvalidSession: + if len(bot.Handlers.InvalidSession) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.InvalidSession = append(bot.Handlers.InvalidSession[:index], bot.Handlers.InvalidSession[index+1:]...) + + case FlagGatewayEventNameApplicationCommandPermissionsUpdate: + if len(bot.Handlers.ApplicationCommandPermissionsUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ApplicationCommandPermissionsUpdate = append(bot.Handlers.ApplicationCommandPermissionsUpdate[:index], bot.Handlers.ApplicationCommandPermissionsUpdate[index+1:]...) + + case FlagGatewayEventNameAutoModerationRuleCreate: + if len(bot.Handlers.AutoModerationRuleCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.AutoModerationRuleCreate = append(bot.Handlers.AutoModerationRuleCreate[:index], bot.Handlers.AutoModerationRuleCreate[index+1:]...) + + case FlagGatewayEventNameAutoModerationRuleUpdate: + if len(bot.Handlers.AutoModerationRuleUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.AutoModerationRuleUpdate = append(bot.Handlers.AutoModerationRuleUpdate[:index], bot.Handlers.AutoModerationRuleUpdate[index+1:]...) + + case FlagGatewayEventNameAutoModerationRuleDelete: + if len(bot.Handlers.AutoModerationRuleDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.AutoModerationRuleDelete = append(bot.Handlers.AutoModerationRuleDelete[:index], bot.Handlers.AutoModerationRuleDelete[index+1:]...) + + case FlagGatewayEventNameAutoModerationActionExecution: + if len(bot.Handlers.AutoModerationActionExecution) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.AutoModerationActionExecution = append(bot.Handlers.AutoModerationActionExecution[:index], bot.Handlers.AutoModerationActionExecution[index+1:]...) + + case FlagGatewayEventNameInteractionCreate: + if len(bot.Handlers.InteractionCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.InteractionCreate = append(bot.Handlers.InteractionCreate[:index], bot.Handlers.InteractionCreate[index+1:]...) + + case FlagGatewayEventNameVoiceServerUpdate: + if len(bot.Handlers.VoiceServerUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.VoiceServerUpdate = append(bot.Handlers.VoiceServerUpdate[:index], bot.Handlers.VoiceServerUpdate[index+1:]...) + + case FlagGatewayEventNameGuildMembersChunk: + if len(bot.Handlers.GuildMembersChunk) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildMembersChunk = append(bot.Handlers.GuildMembersChunk[:index], bot.Handlers.GuildMembersChunk[index+1:]...) + + case FlagGatewayEventNameUserUpdate: + if len(bot.Handlers.UserUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.UserUpdate = append(bot.Handlers.UserUpdate[:index], bot.Handlers.UserUpdate[index+1:]...) + + case FlagGatewayEventNameChannelCreate: + if len(bot.Handlers.ChannelCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ChannelCreate = append(bot.Handlers.ChannelCreate[:index], bot.Handlers.ChannelCreate[index+1:]...) + + case FlagGatewayEventNameChannelUpdate: + if len(bot.Handlers.ChannelUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ChannelUpdate = append(bot.Handlers.ChannelUpdate[:index], bot.Handlers.ChannelUpdate[index+1:]...) + + case FlagGatewayEventNameChannelDelete: + if len(bot.Handlers.ChannelDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ChannelDelete = append(bot.Handlers.ChannelDelete[:index], bot.Handlers.ChannelDelete[index+1:]...) + + case FlagGatewayEventNameChannelPinsUpdate: + if len(bot.Handlers.ChannelPinsUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ChannelPinsUpdate = append(bot.Handlers.ChannelPinsUpdate[:index], bot.Handlers.ChannelPinsUpdate[index+1:]...) + + case FlagGatewayEventNameThreadCreate: + if len(bot.Handlers.ThreadCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadCreate = append(bot.Handlers.ThreadCreate[:index], bot.Handlers.ThreadCreate[index+1:]...) + + case FlagGatewayEventNameThreadUpdate: + if len(bot.Handlers.ThreadUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadUpdate = append(bot.Handlers.ThreadUpdate[:index], bot.Handlers.ThreadUpdate[index+1:]...) + + case FlagGatewayEventNameThreadDelete: + if len(bot.Handlers.ThreadDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadDelete = append(bot.Handlers.ThreadDelete[:index], bot.Handlers.ThreadDelete[index+1:]...) + + case FlagGatewayEventNameThreadListSync: + if len(bot.Handlers.ThreadListSync) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadListSync = append(bot.Handlers.ThreadListSync[:index], bot.Handlers.ThreadListSync[index+1:]...) + + case FlagGatewayEventNameThreadMemberUpdate: + if len(bot.Handlers.ThreadMemberUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadMemberUpdate = append(bot.Handlers.ThreadMemberUpdate[:index], bot.Handlers.ThreadMemberUpdate[index+1:]...) + + case FlagGatewayEventNameThreadMembersUpdate: + if len(bot.Handlers.ThreadMembersUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.ThreadMembersUpdate = append(bot.Handlers.ThreadMembersUpdate[:index], bot.Handlers.ThreadMembersUpdate[index+1:]...) + + case FlagGatewayEventNameGuildCreate: + if len(bot.Handlers.GuildCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildCreate = append(bot.Handlers.GuildCreate[:index], bot.Handlers.GuildCreate[index+1:]...) + + case FlagGatewayEventNameGuildUpdate: + if len(bot.Handlers.GuildUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildUpdate = append(bot.Handlers.GuildUpdate[:index], bot.Handlers.GuildUpdate[index+1:]...) + + case FlagGatewayEventNameGuildDelete: + if len(bot.Handlers.GuildDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildDelete = append(bot.Handlers.GuildDelete[:index], bot.Handlers.GuildDelete[index+1:]...) + + case FlagGatewayEventNameGuildBanAdd: + if len(bot.Handlers.GuildBanAdd) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildBanAdd = append(bot.Handlers.GuildBanAdd[:index], bot.Handlers.GuildBanAdd[index+1:]...) + + case FlagGatewayEventNameGuildBanRemove: + if len(bot.Handlers.GuildBanRemove) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildBanRemove = append(bot.Handlers.GuildBanRemove[:index], bot.Handlers.GuildBanRemove[index+1:]...) + + case FlagGatewayEventNameGuildEmojisUpdate: + if len(bot.Handlers.GuildEmojisUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildEmojisUpdate = append(bot.Handlers.GuildEmojisUpdate[:index], bot.Handlers.GuildEmojisUpdate[index+1:]...) + + case FlagGatewayEventNameGuildStickersUpdate: + if len(bot.Handlers.GuildStickersUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildStickersUpdate = append(bot.Handlers.GuildStickersUpdate[:index], bot.Handlers.GuildStickersUpdate[index+1:]...) + + case FlagGatewayEventNameGuildIntegrationsUpdate: + if len(bot.Handlers.GuildIntegrationsUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildIntegrationsUpdate = append(bot.Handlers.GuildIntegrationsUpdate[:index], bot.Handlers.GuildIntegrationsUpdate[index+1:]...) + + case FlagGatewayEventNameGuildMemberAdd: + if len(bot.Handlers.GuildMemberAdd) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildMemberAdd = append(bot.Handlers.GuildMemberAdd[:index], bot.Handlers.GuildMemberAdd[index+1:]...) + + case FlagGatewayEventNameGuildMemberRemove: + if len(bot.Handlers.GuildMemberRemove) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildMemberRemove = append(bot.Handlers.GuildMemberRemove[:index], bot.Handlers.GuildMemberRemove[index+1:]...) + + case FlagGatewayEventNameGuildMemberUpdate: + if len(bot.Handlers.GuildMemberUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildMemberUpdate = append(bot.Handlers.GuildMemberUpdate[:index], bot.Handlers.GuildMemberUpdate[index+1:]...) + + case FlagGatewayEventNameGuildRoleCreate: + if len(bot.Handlers.GuildRoleCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildRoleCreate = append(bot.Handlers.GuildRoleCreate[:index], bot.Handlers.GuildRoleCreate[index+1:]...) + + case FlagGatewayEventNameGuildRoleUpdate: + if len(bot.Handlers.GuildRoleUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildRoleUpdate = append(bot.Handlers.GuildRoleUpdate[:index], bot.Handlers.GuildRoleUpdate[index+1:]...) + + case FlagGatewayEventNameGuildRoleDelete: + if len(bot.Handlers.GuildRoleDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildRoleDelete = append(bot.Handlers.GuildRoleDelete[:index], bot.Handlers.GuildRoleDelete[index+1:]...) + + case FlagGatewayEventNameGuildScheduledEventCreate: + if len(bot.Handlers.GuildScheduledEventCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildScheduledEventCreate = append(bot.Handlers.GuildScheduledEventCreate[:index], bot.Handlers.GuildScheduledEventCreate[index+1:]...) + + case FlagGatewayEventNameGuildScheduledEventUpdate: + if len(bot.Handlers.GuildScheduledEventUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildScheduledEventUpdate = append(bot.Handlers.GuildScheduledEventUpdate[:index], bot.Handlers.GuildScheduledEventUpdate[index+1:]...) + + case FlagGatewayEventNameGuildScheduledEventDelete: + if len(bot.Handlers.GuildScheduledEventDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildScheduledEventDelete = append(bot.Handlers.GuildScheduledEventDelete[:index], bot.Handlers.GuildScheduledEventDelete[index+1:]...) + + case FlagGatewayEventNameGuildScheduledEventUserAdd: + if len(bot.Handlers.GuildScheduledEventUserAdd) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildScheduledEventUserAdd = append(bot.Handlers.GuildScheduledEventUserAdd[:index], bot.Handlers.GuildScheduledEventUserAdd[index+1:]...) + + case FlagGatewayEventNameGuildScheduledEventUserRemove: + if len(bot.Handlers.GuildScheduledEventUserRemove) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.GuildScheduledEventUserRemove = append(bot.Handlers.GuildScheduledEventUserRemove[:index], bot.Handlers.GuildScheduledEventUserRemove[index+1:]...) + + case FlagGatewayEventNameIntegrationCreate: + if len(bot.Handlers.IntegrationCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.IntegrationCreate = append(bot.Handlers.IntegrationCreate[:index], bot.Handlers.IntegrationCreate[index+1:]...) + + case FlagGatewayEventNameIntegrationUpdate: + if len(bot.Handlers.IntegrationUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.IntegrationUpdate = append(bot.Handlers.IntegrationUpdate[:index], bot.Handlers.IntegrationUpdate[index+1:]...) + + case FlagGatewayEventNameIntegrationDelete: + if len(bot.Handlers.IntegrationDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.IntegrationDelete = append(bot.Handlers.IntegrationDelete[:index], bot.Handlers.IntegrationDelete[index+1:]...) + + case FlagGatewayEventNameInviteCreate: + if len(bot.Handlers.InviteCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.InviteCreate = append(bot.Handlers.InviteCreate[:index], bot.Handlers.InviteCreate[index+1:]...) + + case FlagGatewayEventNameInviteDelete: + if len(bot.Handlers.InviteDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.InviteDelete = append(bot.Handlers.InviteDelete[:index], bot.Handlers.InviteDelete[index+1:]...) + + case FlagGatewayEventNameMessageCreate: + if len(bot.Handlers.MessageCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageCreate = append(bot.Handlers.MessageCreate[:index], bot.Handlers.MessageCreate[index+1:]...) + + case FlagGatewayEventNameMessageUpdate: + if len(bot.Handlers.MessageUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageUpdate = append(bot.Handlers.MessageUpdate[:index], bot.Handlers.MessageUpdate[index+1:]...) + + case FlagGatewayEventNameMessageDelete: + if len(bot.Handlers.MessageDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageDelete = append(bot.Handlers.MessageDelete[:index], bot.Handlers.MessageDelete[index+1:]...) + + case FlagGatewayEventNameMessageDeleteBulk: + if len(bot.Handlers.MessageDeleteBulk) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageDeleteBulk = append(bot.Handlers.MessageDeleteBulk[:index], bot.Handlers.MessageDeleteBulk[index+1:]...) + + case FlagGatewayEventNameMessageReactionAdd: + if len(bot.Handlers.MessageReactionAdd) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageReactionAdd = append(bot.Handlers.MessageReactionAdd[:index], bot.Handlers.MessageReactionAdd[index+1:]...) + + case FlagGatewayEventNameMessageReactionRemove: + if len(bot.Handlers.MessageReactionRemove) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageReactionRemove = append(bot.Handlers.MessageReactionRemove[:index], bot.Handlers.MessageReactionRemove[index+1:]...) + + case FlagGatewayEventNameMessageReactionRemoveAll: + if len(bot.Handlers.MessageReactionRemoveAll) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageReactionRemoveAll = append(bot.Handlers.MessageReactionRemoveAll[:index], bot.Handlers.MessageReactionRemoveAll[index+1:]...) + + case FlagGatewayEventNameMessageReactionRemoveEmoji: + if len(bot.Handlers.MessageReactionRemoveEmoji) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.MessageReactionRemoveEmoji = append(bot.Handlers.MessageReactionRemoveEmoji[:index], bot.Handlers.MessageReactionRemoveEmoji[index+1:]...) + + case FlagGatewayEventNamePresenceUpdate: + if len(bot.Handlers.PresenceUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.PresenceUpdate = append(bot.Handlers.PresenceUpdate[:index], bot.Handlers.PresenceUpdate[index+1:]...) + + case FlagGatewayEventNameStageInstanceCreate: + if len(bot.Handlers.StageInstanceCreate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.StageInstanceCreate = append(bot.Handlers.StageInstanceCreate[:index], bot.Handlers.StageInstanceCreate[index+1:]...) + + case FlagGatewayEventNameStageInstanceDelete: + if len(bot.Handlers.StageInstanceDelete) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.StageInstanceDelete = append(bot.Handlers.StageInstanceDelete[:index], bot.Handlers.StageInstanceDelete[index+1:]...) + + case FlagGatewayEventNameStageInstanceUpdate: + if len(bot.Handlers.StageInstanceUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.StageInstanceUpdate = append(bot.Handlers.StageInstanceUpdate[:index], bot.Handlers.StageInstanceUpdate[index+1:]...) + + case FlagGatewayEventNameTypingStart: + if len(bot.Handlers.TypingStart) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.TypingStart = append(bot.Handlers.TypingStart[:index], bot.Handlers.TypingStart[index+1:]...) + + case FlagGatewayEventNameVoiceStateUpdate: + if len(bot.Handlers.VoiceStateUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.VoiceStateUpdate = append(bot.Handlers.VoiceStateUpdate[:index], bot.Handlers.VoiceStateUpdate[index+1:]...) + + case FlagGatewayEventNameWebhooksUpdate: + if len(bot.Handlers.WebhooksUpdate) <= index { + err := ErrorEventHandler{ + ClientID: bot.ApplicationID, + Event: eventname, + Err: fmt.Errorf(errRemoveInvalidIndex, index), + } + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(err).Msg("") + return err + } + + bot.Handlers.WebhooksUpdate = append(bot.Handlers.WebhooksUpdate[:index], bot.Handlers.WebhooksUpdate[index+1:]...) + } + + LogEventHandler(Logger.Info(), bot.ApplicationID, eventname).Msg("removed event handler") + + return nil +} + +// handle handles an event using its name and data. +func (bot *Client) handle(eventname string, data json.RawMessage) { + bot.Handlers.mu.RLock() + defer bot.Handlers.mu.RUnlock() + + switch eventname { + case FlagGatewayEventNameHello: + if len(bot.Handlers.Hello) != 0 { + event := new(Hello) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameHello, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.Hello { + go handler(event) + } + } + + case FlagGatewayEventNameReady: + if len(bot.Handlers.Ready) != 0 { + event := new(Ready) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameReady, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.Ready { + go handler(event) + } + } + + case FlagGatewayEventNameResumed: + if len(bot.Handlers.Resumed) != 0 { + event := new(Resumed) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameResumed, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.Resumed { + go handler(event) + } + } + + case FlagGatewayEventNameReconnect: + if len(bot.Handlers.Reconnect) != 0 { + event := new(Reconnect) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameReconnect, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.Reconnect { + go handler(event) + } + } + + case FlagGatewayEventNameInvalidSession: + if len(bot.Handlers.InvalidSession) != 0 { + event := new(InvalidSession) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameInvalidSession, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.InvalidSession { + go handler(event) + } + } + + case FlagGatewayEventNameApplicationCommandPermissionsUpdate: + if len(bot.Handlers.ApplicationCommandPermissionsUpdate) != 0 { + event := new(ApplicationCommandPermissionsUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameApplicationCommandPermissionsUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ApplicationCommandPermissionsUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameAutoModerationRuleCreate: + if len(bot.Handlers.AutoModerationRuleCreate) != 0 { + event := new(AutoModerationRuleCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameAutoModerationRuleCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.AutoModerationRuleCreate { + go handler(event) + } + } + + case FlagGatewayEventNameAutoModerationRuleUpdate: + if len(bot.Handlers.AutoModerationRuleUpdate) != 0 { + event := new(AutoModerationRuleUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameAutoModerationRuleUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.AutoModerationRuleUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameAutoModerationRuleDelete: + if len(bot.Handlers.AutoModerationRuleDelete) != 0 { + event := new(AutoModerationRuleDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameAutoModerationRuleDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.AutoModerationRuleDelete { + go handler(event) + } + } + + case FlagGatewayEventNameAutoModerationActionExecution: + if len(bot.Handlers.AutoModerationActionExecution) != 0 { + event := new(AutoModerationActionExecution) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameAutoModerationActionExecution, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.AutoModerationActionExecution { + go handler(event) + } + } + + case FlagGatewayEventNameInteractionCreate: + if len(bot.Handlers.InteractionCreate) != 0 { + event := new(InteractionCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameInteractionCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.InteractionCreate { + go handler(event) + } + } + + case FlagGatewayEventNameVoiceServerUpdate: + if len(bot.Handlers.VoiceServerUpdate) != 0 { + event := new(VoiceServerUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameVoiceServerUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.VoiceServerUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildMembersChunk: + if len(bot.Handlers.GuildMembersChunk) != 0 { + event := new(GuildMembersChunk) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildMembersChunk, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildMembersChunk { + go handler(event) + } + } + + case FlagGatewayEventNameUserUpdate: + if len(bot.Handlers.UserUpdate) != 0 { + event := new(UserUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameUserUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.UserUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameChannelCreate: + if len(bot.Handlers.ChannelCreate) != 0 { + event := new(ChannelCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameChannelCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ChannelCreate { + go handler(event) + } + } + + case FlagGatewayEventNameChannelUpdate: + if len(bot.Handlers.ChannelUpdate) != 0 { + event := new(ChannelUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameChannelUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ChannelUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameChannelDelete: + if len(bot.Handlers.ChannelDelete) != 0 { + event := new(ChannelDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameChannelDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ChannelDelete { + go handler(event) + } + } + + case FlagGatewayEventNameChannelPinsUpdate: + if len(bot.Handlers.ChannelPinsUpdate) != 0 { + event := new(ChannelPinsUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameChannelPinsUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ChannelPinsUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameThreadCreate: + if len(bot.Handlers.ThreadCreate) != 0 { + event := new(ThreadCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadCreate { + go handler(event) + } + } + + case FlagGatewayEventNameThreadUpdate: + if len(bot.Handlers.ThreadUpdate) != 0 { + event := new(ThreadUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameThreadDelete: + if len(bot.Handlers.ThreadDelete) != 0 { + event := new(ThreadDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadDelete { + go handler(event) + } + } + + case FlagGatewayEventNameThreadListSync: + if len(bot.Handlers.ThreadListSync) != 0 { + event := new(ThreadListSync) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadListSync, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadListSync { + go handler(event) + } + } + + case FlagGatewayEventNameThreadMemberUpdate: + if len(bot.Handlers.ThreadMemberUpdate) != 0 { + event := new(ThreadMemberUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadMemberUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadMemberUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameThreadMembersUpdate: + if len(bot.Handlers.ThreadMembersUpdate) != 0 { + event := new(ThreadMembersUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameThreadMembersUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.ThreadMembersUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildCreate: + if len(bot.Handlers.GuildCreate) != 0 { + event := new(GuildCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildCreate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildUpdate: + if len(bot.Handlers.GuildUpdate) != 0 { + event := new(GuildUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildDelete: + if len(bot.Handlers.GuildDelete) != 0 { + event := new(GuildDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildDelete { + go handler(event) + } + } + + case FlagGatewayEventNameGuildBanAdd: + if len(bot.Handlers.GuildBanAdd) != 0 { + event := new(GuildBanAdd) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildBanAdd, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildBanAdd { + go handler(event) + } + } + + case FlagGatewayEventNameGuildBanRemove: + if len(bot.Handlers.GuildBanRemove) != 0 { + event := new(GuildBanRemove) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildBanRemove, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildBanRemove { + go handler(event) + } + } + + case FlagGatewayEventNameGuildEmojisUpdate: + if len(bot.Handlers.GuildEmojisUpdate) != 0 { + event := new(GuildEmojisUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildEmojisUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildEmojisUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildStickersUpdate: + if len(bot.Handlers.GuildStickersUpdate) != 0 { + event := new(GuildStickersUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildStickersUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildStickersUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildIntegrationsUpdate: + if len(bot.Handlers.GuildIntegrationsUpdate) != 0 { + event := new(GuildIntegrationsUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildIntegrationsUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildIntegrationsUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildMemberAdd: + if len(bot.Handlers.GuildMemberAdd) != 0 { + event := new(GuildMemberAdd) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildMemberAdd, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildMemberAdd { + go handler(event) + } + } + + case FlagGatewayEventNameGuildMemberRemove: + if len(bot.Handlers.GuildMemberRemove) != 0 { + event := new(GuildMemberRemove) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildMemberRemove, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildMemberRemove { + go handler(event) + } + } + + case FlagGatewayEventNameGuildMemberUpdate: + if len(bot.Handlers.GuildMemberUpdate) != 0 { + event := new(GuildMemberUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildMemberUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildMemberUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildRoleCreate: + if len(bot.Handlers.GuildRoleCreate) != 0 { + event := new(GuildRoleCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildRoleCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildRoleCreate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildRoleUpdate: + if len(bot.Handlers.GuildRoleUpdate) != 0 { + event := new(GuildRoleUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildRoleUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildRoleUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildRoleDelete: + if len(bot.Handlers.GuildRoleDelete) != 0 { + event := new(GuildRoleDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildRoleDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildRoleDelete { + go handler(event) + } + } + + case FlagGatewayEventNameGuildScheduledEventCreate: + if len(bot.Handlers.GuildScheduledEventCreate) != 0 { + event := new(GuildScheduledEventCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildScheduledEventCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildScheduledEventCreate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildScheduledEventUpdate: + if len(bot.Handlers.GuildScheduledEventUpdate) != 0 { + event := new(GuildScheduledEventUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildScheduledEventUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildScheduledEventUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameGuildScheduledEventDelete: + if len(bot.Handlers.GuildScheduledEventDelete) != 0 { + event := new(GuildScheduledEventDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildScheduledEventDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildScheduledEventDelete { + go handler(event) + } + } + + case FlagGatewayEventNameGuildScheduledEventUserAdd: + if len(bot.Handlers.GuildScheduledEventUserAdd) != 0 { + event := new(GuildScheduledEventUserAdd) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildScheduledEventUserAdd, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildScheduledEventUserAdd { + go handler(event) + } + } + + case FlagGatewayEventNameGuildScheduledEventUserRemove: + if len(bot.Handlers.GuildScheduledEventUserRemove) != 0 { + event := new(GuildScheduledEventUserRemove) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameGuildScheduledEventUserRemove, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.GuildScheduledEventUserRemove { + go handler(event) + } + } + + case FlagGatewayEventNameIntegrationCreate: + if len(bot.Handlers.IntegrationCreate) != 0 { + event := new(IntegrationCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameIntegrationCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.IntegrationCreate { + go handler(event) + } + } + + case FlagGatewayEventNameIntegrationUpdate: + if len(bot.Handlers.IntegrationUpdate) != 0 { + event := new(IntegrationUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameIntegrationUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.IntegrationUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameIntegrationDelete: + if len(bot.Handlers.IntegrationDelete) != 0 { + event := new(IntegrationDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameIntegrationDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.IntegrationDelete { + go handler(event) + } + } + + case FlagGatewayEventNameInviteCreate: + if len(bot.Handlers.InviteCreate) != 0 { + event := new(InviteCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameInviteCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.InviteCreate { + go handler(event) + } + } + + case FlagGatewayEventNameInviteDelete: + if len(bot.Handlers.InviteDelete) != 0 { + event := new(InviteDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameInviteDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.InviteDelete { + go handler(event) + } + } + + case FlagGatewayEventNameMessageCreate: + if len(bot.Handlers.MessageCreate) != 0 { + event := new(MessageCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageCreate { + go handler(event) + } + } + + case FlagGatewayEventNameMessageUpdate: + if len(bot.Handlers.MessageUpdate) != 0 { + event := new(MessageUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameMessageDelete: + if len(bot.Handlers.MessageDelete) != 0 { + event := new(MessageDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageDelete { + go handler(event) + } + } + + case FlagGatewayEventNameMessageDeleteBulk: + if len(bot.Handlers.MessageDeleteBulk) != 0 { + event := new(MessageDeleteBulk) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageDeleteBulk, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageDeleteBulk { + go handler(event) + } + } + + case FlagGatewayEventNameMessageReactionAdd: + if len(bot.Handlers.MessageReactionAdd) != 0 { + event := new(MessageReactionAdd) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageReactionAdd, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageReactionAdd { + go handler(event) + } + } + + case FlagGatewayEventNameMessageReactionRemove: + if len(bot.Handlers.MessageReactionRemove) != 0 { + event := new(MessageReactionRemove) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageReactionRemove, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageReactionRemove { + go handler(event) + } + } + + case FlagGatewayEventNameMessageReactionRemoveAll: + if len(bot.Handlers.MessageReactionRemoveAll) != 0 { + event := new(MessageReactionRemoveAll) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageReactionRemoveAll, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageReactionRemoveAll { + go handler(event) + } + } + + case FlagGatewayEventNameMessageReactionRemoveEmoji: + if len(bot.Handlers.MessageReactionRemoveEmoji) != 0 { + event := new(MessageReactionRemoveEmoji) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameMessageReactionRemoveEmoji, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.MessageReactionRemoveEmoji { + go handler(event) + } + } + + case FlagGatewayEventNamePresenceUpdate: + if len(bot.Handlers.PresenceUpdate) != 0 { + event := new(PresenceUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNamePresenceUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.PresenceUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameStageInstanceCreate: + if len(bot.Handlers.StageInstanceCreate) != 0 { + event := new(StageInstanceCreate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameStageInstanceCreate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.StageInstanceCreate { + go handler(event) + } + } + + case FlagGatewayEventNameStageInstanceDelete: + if len(bot.Handlers.StageInstanceDelete) != 0 { + event := new(StageInstanceDelete) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameStageInstanceDelete, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.StageInstanceDelete { + go handler(event) + } + } + + case FlagGatewayEventNameStageInstanceUpdate: + if len(bot.Handlers.StageInstanceUpdate) != 0 { + event := new(StageInstanceUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameStageInstanceUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.StageInstanceUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameTypingStart: + if len(bot.Handlers.TypingStart) != 0 { + event := new(TypingStart) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameTypingStart, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.TypingStart { + go handler(event) + } + } + + case FlagGatewayEventNameVoiceStateUpdate: + if len(bot.Handlers.VoiceStateUpdate) != 0 { + event := new(VoiceStateUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameVoiceStateUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.VoiceStateUpdate { + go handler(event) + } + } + + case FlagGatewayEventNameWebhooksUpdate: + if len(bot.Handlers.WebhooksUpdate) != 0 { + event := new(WebhooksUpdate) + if err := json.Unmarshal(data, event); err != nil { + LogEventHandler(Logger.Error(), bot.ApplicationID, eventname).Err(ErrorEvent{ClientID: bot.ApplicationID, Event: FlagGatewayEventNameWebhooksUpdate, Err: err, Action: ErrorEventActionUnmarshal}).Msg("") + return + } + + for _, handler := range bot.Handlers.WebhooksUpdate { + go handler(event) + } + } + } +} + +func (r *BulkOverwriteGlobalApplicationCommands) MarshalJSON() ([]byte, error) { + return json.Marshal(r.ApplicationCommands) // nolint:wrapcheck +} + +func (r *BulkOverwriteGuildApplicationCommands) MarshalJSON() ([]byte, error) { + return json.Marshal(r.ApplicationCommands) // nolint:wrapcheck +} + +func (r *ModifyGuildChannelPositions) MarshalJSON() ([]byte, error) { + return json.Marshal(r.Parameters) // nolint:wrapcheck +} + +func (r *ModifyGuildRolePositions) MarshalJSON() ([]byte, error) { + return json.Marshal(r.Parameters) // nolint:wrapcheck +} + +/**unmarshal.go contains custom UnmarshalJSON() functions. + +This enables json.Unmarshal() to unmarshal into types that contain fields that are interfaces. + +In addition, structs that contain an embedded field - that implements UnmarshalJSON() - will +use the embedded field's implementation of UnmarshalJSON(). As a result, these structs must +also implement UnmarshalJSON() to prevent null pointer dereferences. */ + +/** Unused: Command, Event */ + +/** Nonce +Includes: CreateMessage, Message */ + +func (v *Nonce) UnmarshalJSON(b []byte) error { + var x interface{} + + if err := json.Unmarshal(b, &x); err != nil { + return fmt.Errorf(errUnmarshal, x, err) + } + + switch xValue := x.(type) { + case string: + *v = Nonce(xValue) + + case int: + *v = Nonce(strconv.Itoa(xValue)) + + default: + return fmt.Errorf(errUnmarshal, v, fmt.Errorf("value is type %T", x)) + } + + return nil +} + +/** Value +Includes: ApplicationCommandOptionChoice, ApplicationCommandInteractionDataOption */ + +func (v *Value) UnmarshalJSON(b []byte) error { + var x interface{} + + if err := json.Unmarshal(b, &x); err != nil { + return fmt.Errorf(errUnmarshal, x, err) + } + + switch xValue := x.(type) { + case string: + *v = Value(xValue) + + case int: + *v = Value(strconv.Itoa(xValue)) + + case float64: + *v = Value(strconv.FormatFloat(xValue, 'f', -1, bit64)) + + default: + return fmt.Errorf(errUnmarshal, v, fmt.Errorf("value is type %T", x)) + } + + return nil +} + +/** Component */ + +// unmarshalComponents unmarshals a JSON component array into a slice of Go Interface Components (with underlying structs). +func unmarshalComponents(b []byte) ([]Component, error) { + if len(b) == 0 { + return nil, nil + } + + type unmarshalComponent struct { + + // https://discord.com/developers/docs/interactions/message-components#component-object-example-component + Type Flag `json:"type"` + } + + // Components are always provided in a JSON array. + // Create a variable (of type []unmarshalComponent) that can read all of the Component Types. + var unmarshalledComponents []unmarshalComponent + + // unmarshal the JSON (components.{component.Type}) into unmarshalledComponents. + if err := json.Unmarshal(b, &unmarshalledComponents); err != nil { + return nil, fmt.Errorf(errUnmarshal, unmarshalledComponents, err) + } + + // use the known component types to return a slice of Go Interface Components with underlying structs. + components := make([]Component, len(unmarshalledComponents)) + for i, unmarshalledComponent := range unmarshalledComponents { + // set the component (interface) to an underlying type. + switch unmarshalledComponent.Type { + case FlagComponentTypeActionRow: + components[i] = &ActionsRow{} //nolint:exhaustruct + + case FlagComponentTypeButton: + components[i] = &Button{} //nolint:exhaustruct + + case FlagComponentTypeSelectMenu, + FlagComponentTypeUserSelect, + FlagComponentTypeRoleSelect, + FlagComponentTypeMentionableSelect, + FlagComponentTypeChannelSelect: + components[i] = &SelectMenu{} //nolint:exhaustruct + + case FlagComponentTypeTextInput: + components[i] = &TextInput{} //nolint:exhaustruct + + default: + return nil, fmt.Errorf( + "attempt to unmarshal into unknown component type (%d)", + unmarshalledComponent.Type, + ) + } + } + + return components, nil +} + +func (r *EditOriginalInteractionResponse) UnmarshalJSON(b []byte) error { + // The following pattern is present throughout this file + // in order to prevent a stack overflow (of r.UnmarshalJSON()). + type alias EditOriginalInteractionResponse + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + if err := json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + components, err := unmarshalComponents(unmarshalled.Components) + if err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + unmarshalled.alias.Components = &components + + if r == nil { + r = new(EditOriginalInteractionResponse) + } + + *r = EditOriginalInteractionResponse(unmarshalled.alias) + + return nil +} + +func (r *CreateFollowupMessage) UnmarshalJSON(b []byte) error { + type alias CreateFollowupMessage + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(CreateFollowupMessage) + } + + *r = CreateFollowupMessage(unmarshalled.alias) + + return nil +} + +func (r *EditFollowupMessage) UnmarshalJSON(b []byte) error { + type alias EditFollowupMessage + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + if err := json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + components, err := unmarshalComponents(unmarshalled.Components) + if err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + unmarshalled.alias.Components = &components + + if r == nil { + r = new(EditFollowupMessage) + } + + *r = EditFollowupMessage(unmarshalled.alias) + + return nil +} + +func (r *EditMessage) UnmarshalJSON(b []byte) error { + type alias EditMessage + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + if err := json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + components, err := unmarshalComponents(unmarshalled.Components) + if err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + unmarshalled.alias.Components = &components + + if r == nil { + r = new(EditMessage) + } + + *r = EditMessage(unmarshalled.alias) + + return nil +} + +func (r *ForumThreadMessageParams) UnmarshalJSON(b []byte) error { + type alias ForumThreadMessageParams + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(ForumThreadMessageParams) + } + + *r = ForumThreadMessageParams(unmarshalled.alias) + + return nil +} + +func (r *ExecuteWebhook) UnmarshalJSON(b []byte) error { + type alias ExecuteWebhook + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(ExecuteWebhook) + } + + *r = ExecuteWebhook(unmarshalled.alias) + + return nil +} + +func (r *EditWebhookMessage) UnmarshalJSON(b []byte) error { + type alias EditWebhookMessage + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + if err := json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + components, err := unmarshalComponents(unmarshalled.Components) + if err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + unmarshalled.alias.Components = &components + + if r == nil { + r = new(EditWebhookMessage) + } + + *r = EditWebhookMessage(unmarshalled.alias) + + return nil +} + +func (r *ActionsRow) UnmarshalJSON(b []byte) error { + type alias ActionsRow + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(ActionsRow) + } + + *r = ActionsRow(unmarshalled.alias) + + return nil +} + +func (r *ModalSubmitData) UnmarshalJSON(b []byte) error { + type alias ModalSubmitData + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(ModalSubmitData) + } + + *r = ModalSubmitData(unmarshalled.alias) + + return nil +} + +func (r *Messages) UnmarshalJSON(b []byte) error { + type alias Messages + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(Messages) + } + + *r = Messages(unmarshalled.alias) + + return nil +} + +func (r *Modal) UnmarshalJSON(b []byte) error { + type alias Modal + + var unmarshalled struct { + alias + Components json.RawMessage `json:"components"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(Modal) + } + + *r = Modal(unmarshalled.alias) + + return nil +} + +func (r *Message) UnmarshalJSON(b []byte) error { + type alias Message + + var unmarshalled struct { + Components json.RawMessage `json:"components"` + alias + } + + var err error + if err = json.Unmarshal(b, &unmarshalled); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalled.alias.Components, err = unmarshalComponents(unmarshalled.Components); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(Message) + } + + *r = Message(unmarshalled.alias) + + return nil +} + +/** InteractionData */ + +// unmarshalInteractionData unmarshals a JSON InteractionData object into +// a Go Interface InteractionData (with an underlying struct). +func unmarshalInteractionData(b json.RawMessage, x Flag) (InteractionData, error) { + if len(b) == 0 { + return nil, nil + } + + var interactionData InteractionData + + // use the known Interaction Data type to return + // a Go Interface InteractionData with an underlying struct. + switch x { + case FlagInteractionTypePING: + return nil, nil + + case FlagInteractionTypeAPPLICATION_COMMAND, + FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE: + interactionData = &ApplicationCommandData{} //nolint:exhaustruct + + case FlagInteractionTypeMESSAGE_COMPONENT: + interactionData = &MessageComponentData{} //nolint:exhaustruct + + case FlagInteractionTypeMODAL_SUBMIT: + interactionData = &ModalSubmitData{} //nolint:exhaustruct + } + + if interactionData == nil { + return nil, fmt.Errorf("attempt to unmarshal into unknown interaction data type (%d)", x) + } + + // unmarshal into the underlying struct. + if err := json.Unmarshal(b, interactionData); err != nil { + return nil, fmt.Errorf(errUnmarshal, interactionData, err) + } + + return interactionData, nil +} + +func (r *Interaction) UnmarshalJSON(b []byte) error { + type alias Interaction + + var unmarshalledInteraction struct { + Data json.RawMessage `json:"data,omitempty"` + alias + } + + var err error + if err = json.Unmarshal(b, &unmarshalledInteraction); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalledInteraction.alias.Data, err = + unmarshalInteractionData(unmarshalledInteraction.Data, unmarshalledInteraction.Type); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(Interaction) + } + + *r = Interaction(unmarshalledInteraction.alias) + + return nil +} + +/** InteractionCallbackData */ + +// unmarshalInteractionCallbackData unmarshals a JSON InteractionCallbackData object into +// a Go Interface InteractionCallbackData (with an underlying struct). +func unmarshalInteractionCallbackData(b []byte, x Flag) (InteractionCallbackData, error) { + if len(b) == 0 { + return nil, nil + } + + var interactionCallbackData InteractionCallbackData + + // use the known Interaction Callback Data type to return + // a Go Interface InteractionCallbackData with an underlying struct. + switch x { + case FlagInteractionCallbackTypePONG: + return nil, nil // Ping + + case FlagInteractionCallbackTypeCHANNEL_MESSAGE_WITH_SOURCE, + FlagInteractionCallbackTypeUPDATE_MESSAGE: + interactionCallbackData = &Messages{} //nolint:exhaustruct + + case FlagInteractionCallbackTypeDEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: + return nil, nil // Edit a followup response later. + + case FlagInteractionCallbackTypeDEFERRED_UPDATE_MESSAGE: + return nil, nil // Edit the original response later. + + case FlagInteractionCallbackTypeAPPLICATION_COMMAND_AUTOCOMPLETE_RESULT: + interactionCallbackData = &Autocomplete{} //nolint:exhaustruct + + case FlagInteractionCallbackTypeMODAL: + interactionCallbackData = &Modal{} //nolint:exhaustruct + } + + if interactionCallbackData == nil { + return nil, fmt.Errorf( + "attempt to unmarshal into unknown interaction callback data type (%d)", + x) + } + + // unmarshal into the underlying struct. + if err := json.Unmarshal(b, interactionCallbackData); err != nil { + return nil, fmt.Errorf(errUnmarshal, interactionCallbackData, err) + } + + return interactionCallbackData, nil +} + +func (r *InteractionResponse) UnmarshalJSON(b []byte) error { + type alias InteractionResponse + + var unmarshalledInteractionResponse struct { + alias + Data json.RawMessage `json:"data,omitempty"` + } + + var err error + if err = json.Unmarshal(b, &unmarshalledInteractionResponse); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if unmarshalledInteractionResponse.alias.Data, err = + unmarshalInteractionCallbackData( + unmarshalledInteractionResponse.Data, unmarshalledInteractionResponse.Type); err != nil { + return fmt.Errorf(errUnmarshal, r, err) + } + + if r == nil { + r = new(InteractionResponse) + } + + *r = InteractionResponse(unmarshalledInteractionResponse.alias) + + return nil +} + +/** Structs that contain embedded fields that implement UnmarshalJSON() */ + +func (e *MessageCreate) UnmarshalJSON(b []byte) error { + if err := json.Unmarshal(b, &e.Message); err != nil { + return fmt.Errorf(errUnmarshal, e, err) + } + + return nil +} + +func (e *MessageUpdate) UnmarshalJSON(b []byte) error { + if err := json.Unmarshal(b, &e.Message); err != nil { + return fmt.Errorf(errUnmarshal, e, err) + } + + return nil +} + +func (e *InteractionCreate) UnmarshalJSON(b []byte) error { + if err := json.Unmarshal(b, &e.Interaction); err != nil { + return fmt.Errorf(errUnmarshal, e, err) + } + + return nil +} + +func (e *CreateInteractionResponse) UnmarshalJSON(b []byte) error { + if err := json.Unmarshal(b, &e.InteractionResponse); err != nil { + return fmt.Errorf(errUnmarshal, e, err) + } + + return nil +} + +/**unmarshal_convert.go contains type conversion functions for interfaces. + +This enables users (developers) to easily type convert interfaces. */ + +const ( + errTypeConvert = "attempted to type convert InteractionData of type %v to type %s" +) + +/* Nonce */ + +func (n Nonce) String() string { + return string(n) +} + +func (n Nonce) Int64() (int64, error) { + return strconv.ParseInt(string(n), base10, bit64) //nolint:wrapcheck +} + +/* Value */ + +func (n Value) String() string { + return string(n) +} + +func (n Value) Float64() (float64, error) { + return strconv.ParseFloat(string(n), bit64) //nolint:wrapcheck +} + +func (n Value) Int64() (int64, error) { + return strconv.ParseInt(string(n), base10, bit64) //nolint:wrapcheck +} + +/* InteractionData */ + +// ApplicationCommand type converts an InteractionData field into an ApplicationCommandData struct. +func (i *Interaction) ApplicationCommand() *ApplicationCommandData { + switch i.Data.InteractionDataType() { + case FlagInteractionTypeAPPLICATION_COMMAND, + FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE: + return i.Data.(*ApplicationCommandData) //nolint:forcetypeassert + + case FlagInteractionTypePING: + panic(fmt.Sprintf(errTypeConvert, "Ping", "ApplicationCommandData")) + + case FlagInteractionTypeMESSAGE_COMPONENT: + panic(fmt.Sprintf(errTypeConvert, "MessageComponentData", "ApplicationCommandData")) + + case FlagInteractionTypeMODAL_SUBMIT: + panic(fmt.Sprintf(errTypeConvert, "ModalSubmitData", "ApplicationCommandData")) + } + + panic(fmt.Sprintf(errTypeConvert, i.Data.InteractionDataType(), "ApplicationCommandData")) +} + +// MessageComponent type converts an InteractionData field into a MessageComponentData struct. +func (i *Interaction) MessageComponent() *MessageComponentData { + switch i.Data.InteractionDataType() { + case FlagInteractionTypeMESSAGE_COMPONENT: + return i.Data.(*MessageComponentData) //nolint:forcetypeassert + + case FlagInteractionTypePING: + panic(fmt.Sprintf(errTypeConvert, "Ping", "MessageComponentData")) + + case FlagInteractionTypeAPPLICATION_COMMAND, + FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE: + panic(fmt.Sprintf(errTypeConvert, "ApplicationCommandData", "MessageComponentData")) + + case FlagInteractionTypeMODAL_SUBMIT: + panic(fmt.Sprintf(errTypeConvert, "ModalSubmitData", "MessageComponentData")) + } + + panic(fmt.Sprintf(errTypeConvert, i.Data.InteractionDataType(), "MessageComponentData")) +} + +// ModalSubmit type converts an InteractionData field into a ModalSubmitData struct. +func (i *Interaction) ModalSubmit() *ModalSubmitData { + switch i.Data.InteractionDataType() { + case FlagInteractionTypeMODAL_SUBMIT: + return i.Data.(*ModalSubmitData) //nolint:forcetypeassert + + case FlagInteractionTypePING: + panic(fmt.Sprintf(errTypeConvert, "Ping", "ModalSubmitData")) + + case FlagInteractionTypeAPPLICATION_COMMAND, + FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE: + panic(fmt.Sprintf(errTypeConvert, "ApplicationCommandData", "ModalSubmitData")) + + case FlagInteractionTypeMESSAGE_COMPONENT: + panic(fmt.Sprintf(errTypeConvert, "MessageComponentData", "ModalSubmitData")) + } + + panic(fmt.Sprintf(errTypeConvert, i.Data.InteractionDataType(), "ModalSubmitData")) +} + +// init is called at the start of the application. +func init() { + zerolog.TimeFieldFormat = time.RFC3339Nano + zerolog.SetGlobalLevel(zerolog.Disabled) +} + +var ( + // Logger represents the Disgo Logger used to log information. + Logger = zerolog.New(os.Stdout) +) + +// Logger Contexts +const ( + // LogCtxClient represents the log key for a Client (Bot) Application ID. + LogCtxClient = "client" + + // LogCtxCorrelation represents the log key for a Correlation ID. + LogCtxCorrelation = "xid" + + // LogCtxRequest represents the log key for a Request ID. + LogCtxRequest = "request" + + // LogCtxRoute represents the log key for a Route ID. + LogCtxRoute = "route" + + // LogCtxResource represents the log key for a Resource ID. + LogCtxResource = "resource" + + // LogCtxEndpoint represents the log key for an Endpoint. + LogCtxEndpoint = "endpoint" + + // LogCtxRequestBody represents the log key for an HTTP Request Body. + LogCtxRequestBody = "body" + + // LogCtxBucket represents the log key for a Rate Limit Bucket ID. + LogCtxBucket = "bucket" + + // LogCtxReset represents the log key for a Discord Bucket reset time. + LogCtxReset = "reset" + + // LogCtxResponse represents the log key for an HTTP Request Response. + LogCtxResponse = "response" + + // LogCtxResponseHeader represents the log key for an HTTP Request Response header. + LogCtxResponseHeader = "header" + + // LogCtxResponseBody represents the log key for an HTTP Request Response body. + LogCtxResponseBody = "body" + + // LogCtxSession represents the log key for a Discord Session ID. + LogCtxSession = "session" + + // LogCtxPayload represents the log key for a Discord Gateway Payload. + LogCtxPayload = "payload" + + // LogCtxPayloadOpcode represents the log key for a Discord Gateway Payload opcode. + LogCtxPayloadOpcode = "opcode" + + // LogCtxPayloadData represents the log key for Discord Gateway Payload data. + LogCtxPayloadData = "data" + + // LogCtxEvent represents the log key for a Discord Gateway Event. + LogCtxEvent = "event" + + // LogCtxCommand represents the log key for a Discord Gateway command. + LogCtxCommand = "command" + + // LogCtxCommandOpcode represents the log key for a Discord Gateway command opcode. + LogCtxCommandOpcode = "opcode" + + // LogCtxCommandName represents the log key for a Discord Gateway command name. + LogCtxCommandName = "name" +) + +// LogRequest logs a request. +func LogRequest(log *zerolog.Event, clientid, xid, routeid, resourceid, endpoint string) *zerolog.Event { + return log.Timestamp(). + Str(LogCtxClient, clientid). + Dict(LogCtxRequest, zerolog.Dict(). + Str(LogCtxCorrelation, xid). + Str(LogCtxRoute, routeid). + Str(LogCtxResource, resourceid). + Str(LogCtxEndpoint, endpoint), + ) +} + +// LogRequestBody logs a request with its body. +func LogRequestBody(log *zerolog.Event, clientid, xid, routeid, resourceid, endpoint, body string) *zerolog.Event { + return log.Timestamp(). + Str(LogCtxClient, clientid). + Dict(LogCtxRequest, zerolog.Dict(). + Str(LogCtxCorrelation, xid). + Str(LogCtxRoute, routeid). + Str(LogCtxResource, resourceid). + Str(LogCtxEndpoint, endpoint). + Str(LogCtxRequestBody, body), + ) +} + +// LogResponse logs a response (typically using LogRequest). +func LogResponse(log *zerolog.Event, header, body string) *zerolog.Event { + return log.Dict(LogCtxResponse, zerolog.Dict(). + Str(LogCtxResponseHeader, header). + Str(LogCtxResponseBody, body), + ) +} + +// LogEventHandler logs an event handler action. +func LogEventHandler(log *zerolog.Event, clientid, event string) *zerolog.Event { + return log.Timestamp(). + Str(LogCtxClient, clientid). + Str(LogCtxEvent, event) +} + +// LogSession logs a session. +func LogSession(log *zerolog.Event, sessionid string) *zerolog.Event { + return log.Timestamp(). + Str(LogCtxSession, sessionid) +} + +// LogPayload logs a Discord Gateway Payload (typically using LogSession). +func LogPayload(log *zerolog.Event, op int, data json.RawMessage) *zerolog.Event { + return log.Dict(LogCtxPayload, zerolog.Dict(). + Int(LogCtxPayloadOpcode, op). + Bytes(LogCtxPayloadData, data), + ) +} + +// LogCommand logs a Gateway Command (typically using a LogSession). +func LogCommand(log *zerolog.Event, clientid string, op int, command string) *zerolog.Event { + return log.Str(LogCtxClient, clientid). + Dict(LogCtxCommand, zerolog.Dict(). + Int(LogCtxCommandOpcode, op). + Str(LogCtxCommandName, command), + ) +} + +const ( + grantTypeAuthorizationCodeGrant = "authorization_code" + grantTypeRefreshToken = "refresh_token" + grantTypeClientCredentials = "client_credentials" + amountAuthURLParams = 6 + amountAuthURLParamsBot = 3 +) + +// GenerateAuthorizationURL generates an authorization URL from a given client and response type. +func GenerateAuthorizationURL(bot *Client, response string) string { + params := make([]string, 0, amountAuthURLParams) + + // response_type is the type of response the redirect will return. + if response != "" { + params = append(params, "responsetype="+response) + } + + // client_id is the application client id. + params = append(params, "client_id="+bot.Authorization.ClientID) + + // scope is a list of OAuth2 scopes separated by url encoded spaces (%20). + scope := urlQueryStringScope(bot.Authorization.Scopes) + if scope != "" { + params = append(params, scope) + } + + // redirect_uri is the URL registered while creating the application. + if bot.Authorization.RedirectURI != "" { + params = append(params, "redirect_uri="+url.QueryEscape(bot.Authorization.RedirectURI)) + } + + // state is the unique string mentioned in State and Security. + if bot.Authorization.State != "" { + params = append(params, "state="+bot.Authorization.State) + } + + // prompt controls how the authorization flow handles existing authorizations. + if bot.Authorization.Prompt != "" { + params = append(params, "prompt="+bot.Authorization.Prompt) + } + + return EndpointAuthorizationURL() + "?" + strings.Join(params, "&") +} + +// BotAuthParams represents parameters used to generate a bot authorization URL. +type BotAuthParams struct { + // Bot provides the client_id and scopes parameters. + Bot *Client + + // GuildID pre-selects a guild in the authorization prompt. + GuildID string + + // ResponseType provides the type of response the OAuth2 flow will return. + // + // In the context of bot authorization, response_type is only provided when + // a scope outside of `bot` and `applications.commands` is requested. + ResponseType string + + // Permissions represents the permissions the bot is requesting. + Permissions BitFlag + + // DisableGuildSelect disables the ability to select other guilds + // in the authorization prompt (when GuildID is provided). + DisableGuildSelect bool +} + +// GenerateBotAuthorizationURL generates a bot authorization URL using the given BotAuthParams. +// +// Bot.Scopes must include "bot" to enable the OAuth2 Bot Flow. +func GenerateBotAuthorizationURL(p BotAuthParams) string { + params := make([]string, 0, amountAuthURLParamsBot) + + // permissions is permissions the bot is requesting. + params = append(params, "permissions="+strconv.FormatUint(uint64(p.Permissions), base10)) + + // guild_id is the Guild ID of the guild that is pre-selected in the authorization prompt. + if p.GuildID != "" { + params = append(params, "guild_id="+p.GuildID) + } + + // disable_guild_select determines whether the user will be allowed to select a guild + // other than the guild_id. + params = append(params, "disable_guild_select="+strconv.FormatBool(p.DisableGuildSelect)) + + return GenerateAuthorizationURL(p.Bot, p.ResponseType) + "&" + strings.Join(params, "&") +} + +// AuthorizationCodeGrant performs an OAuth2 authorization code grant. +// +// Send the user a valid Authorization URL, which can be generated using +// GenerateAuthorizationURL(bot, "code"). +// +// When the user visits the Authorization URL, they will be prompted for authorization. +// If the user accepts the prompt, they will be redirected to the `redirect_uri`. +// This issues a GET request to the `redirect_uri` web server which YOU MUST HANDLE +// by parsing the request's URL Query String into a disgo.RedirectURL object. +// +// Retrieve the user's access token by calling THIS FUNCTION (with the disgo.RedirectURL parameter), +// which performs an Access Token Exchange. +// +// Refresh the token by using RefreshAuthorizationCodeGrant(bot, token). +// +// For more information, read https://discord.com/developers/docs/topics/oauth2#authorization-code-grant +func AuthorizationCodeGrant(bot *Client, ru *RedirectURL) (*AccessTokenResponse, error) { + exchange := &AccessTokenExchange{ + ClientID: bot.Authorization.ClientID, + ClientSecret: bot.Authorization.ClientSecret, + GrantType: grantTypeAuthorizationCodeGrant, + Code: ru.Code, + RedirectURI: bot.Authorization.RedirectURI, + } + + return exchange.Send(bot) +} + +// RefreshAuthorizationCodeGrant refreshes an Access Token from an OAuth2 authorization code grant. +func RefreshAuthorizationCodeGrant(bot *Client, token *AccessTokenResponse) (*AccessTokenResponse, error) { + exchange := &RefreshTokenExchange{ + ClientID: bot.Authorization.ClientID, + ClientSecret: bot.Authorization.ClientSecret, + GrantType: grantTypeRefreshToken, + RefreshToken: token.RefreshToken, + } + + return exchange.Send(bot) +} + +// ImplicitGrant converts a RedirectURI (from a simplified OAuth2 grant) to an AccessTokenResponse. +// +// Send the user a valid Authorization URL, which can be generated using +// GenerateAuthorizationURL(bot, "token"). +// +// When the user visits the Authorization URL, they will be prompted for authorization. +// If the user accepts the prompt, they will be redirected to the `redirect_uri`. +// This issues a GET request to the `redirect_uri` web server which YOU MUST HANDLE +// by parsing the request's URI Fragments into a disgo.RedirectURI object. +// +// A disgo.RedirectURI object is equivalent to a disgo.AccessTokenResponse, +// but it does NOT contain a refresh token. +// +// For more information, read https://discord.com/developers/docs/topics/oauth2#implicit-grant +func ImplicitGrant(ru *RedirectURI) *AccessTokenResponse { + return &AccessTokenResponse{ + AccessToken: ru.AccessToken, + TokenType: ru.TokenType, + ExpiresIn: ru.ExpiresIn, + RefreshToken: "", + Scope: ru.Scope, + } +} + +// ClientCredentialsGrant performs a client credential OAuth2 grant for TESTING PURPOSES. +// +// The bot client's Authentication Header will be set to a Basic Authentication Header that +// uses the bot's ClientID as a username and ClientSecret as a password. +// +// A request will be made for a Client Credential grant which returns a disgo.AccessTokenResponse +// that does NOT contain a refresh token. +// +// For more information, read https://discord.com/developers/docs/topics/oauth2#client-credentials-grant +func ClientCredentialsGrant(bot *Client) (*AccessTokenResponse, error) { + bot.Authentication.Header = "Basic " + + base64.StdEncoding.EncodeToString([]byte(bot.Authorization.ClientID+":"+bot.Authorization.ClientSecret)) + + grant := &ClientCredentialsTokenRequest{ + GrantType: grantTypeClientCredentials, + Scope: urlQueryStringScope(bot.Authorization.Scopes), + } + + return grant.Send(bot) +} + +// BotAuthorization performs a specialized OAuth2 flow for users to add bots to guilds. +// +// Send the user a valid Bot Authorization URL, which can be generated using +// GenerateBotAuthorizationURL(disgo.BotAuthParams{...}). +// +// When the user visits the Bot Authorization URL, they will be prompted for authorization. +// If the user accepts the prompt (with a guild), the bot will be added to the selected guild. +// +// For more information read, https://discord.com/developers/docs/topics/oauth2#bot-authorization-flow +func BotAuthorization() {} + +// AdvancedBotAuthorization performs a specialized OAuth2 flow for users to add bots to guilds. +// +// Send the user a valid Bot Authorization URL, which can be generated using +// GenerateBotAuthorizationURL(disgo.BotAuthParams{...}). +// +// If the user accepts the prompt (with a guild), they will be redirected to the `redirect_uri`. +// This issues a GET request to the `redirect_uri` web server which YOU MUST HANDLE +// by parsing the request's URL Query String into a disgo.RedirectURL object. +// +// Retrieve the user's access token by calling THIS FUNCTION (with the disgo.RedirectURL parameter), +// which performs an Access Token Exchange. +// +// Refresh the token by using RefreshAuthorizationCodeGrant(bot, token). +// +// For more information read, https://discord.com/developers/docs/topics/oauth2#advanced-bot-authorization +func AdvancedBotAuthorization(bot *Client, ru *RedirectURL) (*AccessTokenResponse, error) { + return AuthorizationCodeGrant(bot, ru) +} + +// WebhookAuthorization performs a specialized OAuth2 authorization code grant. +// +// Send the user a valid Authorization URL, which can be generated using +// GenerateAuthorizationURL(bot, "code") when bot.Scopes is set to `webhook.incoming`. +// +// When the user visits the Authorization URL, they will be prompted for authorization. +// If the user accepts the prompt (with a channel), they will be redirected to the `redirect_uri`. +// This issues a GET request to the `redirect_uri` web server which YOU MUST HANDLE +// by parsing the request's URL Query String into a disgo.RedirectURL object. +// +// Retrieve the user's access token by calling THIS FUNCTION (with the disgo.RedirectURL parameter), +// which performs an Access Token Exchange. +// +// Refresh the token by using RefreshAuthorizationCodeGrant(bot, token). +// +// For more information read, https://discord.com/developers/docs/topics/oauth2#webhooks +func WebhookAuthorization(bot *Client, ru *RedirectURL) (*AccessTokenResponse, *Webhook, error) { + exchange := &AccessTokenExchange{ + ClientID: bot.Authorization.ClientID, + ClientSecret: bot.Authorization.ClientSecret, + GrantType: grantTypeAuthorizationCodeGrant, + Code: ru.Code, + RedirectURI: bot.Authorization.RedirectURI, + } + + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[1]("1") + query, err := EndpointQueryString(exchange) + if err != nil { + return nil, nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointTokenURL() + "?" + query + + result := new(WebhookTokenResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + // convert the webhook token response to an access token response (and webhook). + token := &AccessTokenResponse{ + AccessToken: result.AccessToken, + TokenType: result.TokenType, + ExpiresIn: result.ExpiresIn, + RefreshToken: result.RefreshToken, + Scope: result.Scope, + } + + return token, result.Webhook, nil +} + +// Send sends an AccessTokenExchange request to Discord and returns an AccessTokenResponse. +func (r *AccessTokenExchange) Send(bot *Client) (*AccessTokenResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[1]("1") + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointTokenURL() + "?" + query + + result := new(AccessTokenResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a RefreshTokenExchange request to Discord and returns an AccessTokenResponse. +// +// Uses the RefreshTokenExchange ClientID and ClientSecret. +func (r *RefreshTokenExchange) Send(bot *Client) (*AccessTokenResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[1]("1") + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointTokenURL() + "?" + query + + result := new(AccessTokenResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ClientCredentialsTokenRequest to Discord and returns a ClientCredentialsTokenRequest. +func (r *ClientCredentialsTokenRequest) Send(bot *Client) (*AccessTokenResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[1]("1") + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointTokenURL() + "?" + query + + result := new(AccessTokenResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// urlQueryStringScope parses a given slice of scopes to generate a valid URL Query String. +func urlQueryStringScope(scopes []string) string { + if len(scopes) > 0 { + var scope strings.Builder + scope.WriteString("scope=") + + for i, s := range scopes { + if i > 0 { + scope.WriteString("%20") + } + + scope.WriteString(s) + } + + return scope.String() + } + + return "" +} + +// rlbpool represents a synchronized Rate Limit Bucket pool. +var rlbpool sync.Pool + +// getBucket gets a Bucket from a pool. +func getBucket() *Bucket { + if b := rlbpool.Get(); b != nil { + return b.(*Bucket) //nolint:forcetypeassert + } + + return new(Bucket) +} + +// putBucket puts a Rate Limit Bucket into the pool. +func putBucket(b *Bucket) { + b.ID = "" + b.Limit = 0 + b.Remaining = 0 + b.Pending = 0 + b.Date = time.Time{} + b.Expiry = time.Time{} + + rlbpool.Put(b) +} + +// spool represents a synchronized Session pool. +var spool sync.Pool + +// NewSession gets a Session from a pool. +func NewSession() *Session { + if s := spool.Get(); s != nil { + return s.(*Session) //nolint:forcetypeassert + } + + return new(Session) +} + +// putSession puts a Session into the pool. +func putSession(s *Session) { + s.Lock() + defer s.Unlock() + + // reset the Session. + s.ID = "" + s.Seq = 0 + s.Endpoint = "" + s.Context = nil + s.Conn = nil + s.heartbeat = nil + s.manager = nil + + spool.Put(s) +} + +// gpool represents a synchronized Gateway Payload pool. +var gpool sync.Pool + +// getPayload gets a Gateway Payload from the pool. +func getPayload() *GatewayPayload { + if g := gpool.Get(); g != nil { + return g.(*GatewayPayload) //nolint:forcetypeassert + } + + return new(GatewayPayload) +} + +// putPayload puts a Gateway Payload into the pool. +func putPayload(g *GatewayPayload) { + // reset the Gateway Payload. + g.Op = 0 + g.Data = nil + g.SequenceNumber = nil + g.EventName = nil + + gpool.Put(g) +} + +const ( + nilRouteBucket = "NIL" +) + +var ( + // IgnoreGlobalRateLimitRouteIDs represents a set of Route IDs that do NOT adhere to the Global Rate Limit. + // + // Interaction endpoints are not bound to the bot's Global Rate Limit. + // https://discord.com/developers/docs/interactions/receiving-and-responding#endpoints + IgnoreGlobalRateLimitRouteIDs = map[string]bool{ + "18": true, "19": true, "20": true, "21": true, "22": true, "23": true, "24": true, "25": true, + } +) + +// RateLimit provides concurrency-safe rate limit functionality by implementing the RateLimiter interface. +type RateLimit struct { + // ids represents a map of Route IDs to Bucket IDs (map[routeID]BucketID). + ids map[string]string + + // buckets represents a map of Bucket IDs to rate limit Bucket (map[BucketID]*Bucket). + buckets map[string]*Bucket + + // entries represents a map of Bucket IDs to a count of references to Routes (map[BucketID]count). + // + // Used to safely remove a Bucket once it's no longer in use. + entries map[string]int + + // DefaultBucket represents a Default Rate Limit Bucket, which is used to control + // the rate of the "first request(s) for any given route". + // + // This is necessary since Discord uses dynamic per-route token rate limits. + // As a result, a route's actual Rate Limit Bucket can NOT be discovered until a request (for that route) is sent. + // + // A Default Rate Limit Bucket can be set at multiple levels. + // Route (RateLimit.DefaultBucket): Used when a per-route request's bucket is NOT initialized (i.e route 16*). + // Resource (Route Bucket Hash): Used when a per-resource request's bucket is NOT initialized (i.e route 16, resource 32*). + // Resource(s) (Resource Bucket Hash): Used when an nth degree per-resource request's bucket is NOT initialized (i.e route 16; resource 32; resource 7*). + // So on and so forth... + // *A request is NOT initialized when it has never been set (to a bucket or nil). + // + // Set the DefaultBucket to `nil` to disable the Default Rate Limit Bucket mechanism. + // + // Use a Default Bucket's Limit field-value to control how many requests of + // a given route can be sent (per second) BEFORE the actual Rate Limit Bucket of that route is known. + DefaultBucket *Bucket + + // muQueue represents a mutex used to process a single request a time. + muQueue sync.Mutex + + // muTx represents a mutex used to access multiple rate limit Buckets as a transaction. + muTx sync.Mutex +} + +func (r *RateLimit) SetBucketID(routeid string, bucketid string) { + currentBucketID := r.ids[routeid] + + // when the current Bucket ID is not the same as the new Bucket ID. + if currentBucketID != bucketid { + // update the entries for the current Bucket ID. + if currentBucketID != "" { + r.entries[currentBucketID]-- + + // when the current Bucket ID is no longer referenced by a Route, + // delete the respective Bucket (and recycle it). + if r.entries[currentBucketID] <= 0 { + if currentBucket := r.buckets[currentBucketID]; currentBucket != nil { + putBucket(currentBucket) + } + delete(r.entries, currentBucketID) + delete(r.buckets, currentBucketID) + + Logger.Info().Timestamp().Str(LogCtxRequest, routeid).Str(LogCtxBucket, currentBucketID).Msg("deleted bucket") + } + } + + // set the Route ID to the new Bucket ID. + r.ids[routeid] = bucketid + + // update the entries for the new Bucket ID. + r.entries[bucketid]++ + + Logger.Info().Timestamp().Str(LogCtxRequest, routeid).Str(LogCtxBucket, bucketid).Msg("set route to bucket") + } +} + +func (r *RateLimit) GetBucketID(routeid string) string { + return r.ids[routeid] +} + +func (r *RateLimit) SetBucketFromID(bucketid string, bucket *Bucket) { + r.buckets[bucketid] = bucket + + Logger.Info().Timestamp().Str(LogCtxBucket, bucketid).Msgf("set bucket to object %p", bucket) +} + +func (r *RateLimit) GetBucketFromID(bucketid string) *Bucket { + return r.buckets[bucketid] +} + +func (r *RateLimit) SetBucket(routeid string, bucket *Bucket) { + r.buckets[r.ids[routeid]] = bucket +} + +func (r *RateLimit) GetBucket(routeid string, resourceid string) *Bucket { + requestid := routeid + resourceid + + // ID 0 is used as a Global Rate Limit Bucket (or nil). + if routeid != GlobalRateLimitRouteID { + switch r.ids[requestid] { + // when a non-global route is initialized and (BucketID == "NIL"), NO rate limit applies. + case nilRouteBucket: + return nil + + // This rate limiter implementation points the Route ID 0 (which is reserved for a + // Global Rate Limit) to Bucket ID "". + // + // As a result (of the Default Bucket mechanism), non-0 Route IDs must be handled accordingly. + case "": + // when a non-global route is uninitialized, set it to the Default Bucket. + // + // While GetBucket() can be called multiple times BEFORE a request is sent, + // this case is only true the FIRST time a GetBucket() call is made (for that request), + // As a result, the Bucket that is allocated from this call will ALWAYS be + // immediately used. + // + // The Route's Bucket ID (Hash) is set to an artificial value while + // the Route ID is pointed to a Default Bucket. This results in + // subsequent calls to the Route's Default Bucket to return to + // the same initialized bucket. + // + // When a Default Bucket is exhausted, it will never expire. + // As a result, the Remaining field-value will remain at 0 until + // the pending request (and its actual Bucket) is confirmed. + // + // requestID = routeid + resourceid + // temporaryBucketID = requestID + r.SetBucketID(requestid, requestid) + + // DefaultBucket (Per-Route) = RateLimit.DefaultBucket + if "" == resourceid { + if r.DefaultBucket == nil { + return nil + } + + b := getBucket() + b.Limit = r.DefaultBucket.Limit + b.Remaining = r.DefaultBucket.Limit + r.SetBucketFromID(requestid, b) + + return b + } + + // DefaultBucket (Per-Resource) = GetBucket(routeid, "") + defaultBucket := r.GetBucket(routeid, "") + if defaultBucket == nil { + return nil + } + + b := getBucket() + b.Limit = defaultBucket.Limit + b.Remaining = defaultBucket.Limit + r.SetBucketFromID(requestid, b) + + return b + } + } + + return r.buckets[r.ids[requestid]] +} + +func (r *RateLimit) SetDefaultBucket(bucket *Bucket) { + r.DefaultBucket = bucket +} + +func (r *RateLimit) Lock() { + r.muQueue.Lock() +} + +func (r *RateLimit) Unlock() { + r.muQueue.Unlock() +} + +func (r *RateLimit) StartTx() { + r.muTx.Lock() +} + +func (r *RateLimit) EndTx() { + r.muTx.Unlock() +} + +type hash func(routeid string, parameters ...string) (string, string) + +// Hash returns a hashing function which hashes a request using its routeID. +// +// n represents the degree of resources used to hash the request. +// Per-Route: n = 0 +// Per-Resource: n = 1 +// ... +func Hash(n int) hash { + return func(r string, p ...string) (string, string) { + return r, strings.Join(p[:n], "") + } +} + +var ( + // HashPerRoute hashes a request that uses a per-route rate limit algorithm. + HashPerRoute = Hash(0) +) + +var ( + // RateLimitHashFuncs represents a map of routes to respective rate limit algorithms. + // + // used to determine the hashing function for routes during runtime (map[routeID]algorithm). + RateLimitHashFuncs = map[uint8]hash{ + RouteIDs["OAuth"]: HashPerRoute, + RouteIDs["GetGlobalApplicationCommands"]: HashPerRoute, + RouteIDs["CreateGlobalApplicationCommand"]: HashPerRoute, + RouteIDs["GetGlobalApplicationCommand"]: HashPerRoute, + RouteIDs["EditGlobalApplicationCommand"]: HashPerRoute, + RouteIDs["DeleteGlobalApplicationCommand"]: HashPerRoute, + RouteIDs["BulkOverwriteGlobalApplicationCommands"]: HashPerRoute, + RouteIDs["GetGuildApplicationCommands"]: HashPerRoute, + RouteIDs["CreateGuildApplicationCommand"]: HashPerRoute, + RouteIDs["GetGuildApplicationCommand"]: HashPerRoute, + RouteIDs["EditGuildApplicationCommand"]: HashPerRoute, + RouteIDs["DeleteGuildApplicationCommand"]: HashPerRoute, + RouteIDs["BulkOverwriteGuildApplicationCommands"]: HashPerRoute, + RouteIDs["GetGuildApplicationCommandPermissions"]: HashPerRoute, + RouteIDs["GetApplicationCommandPermissions"]: HashPerRoute, + RouteIDs["EditApplicationCommandPermissions"]: HashPerRoute, + RouteIDs["BatchEditApplicationCommandPermissions"]: HashPerRoute, + RouteIDs["CreateInteractionResponse"]: HashPerRoute, + RouteIDs["GetOriginalInteractionResponse"]: HashPerRoute, + RouteIDs["EditOriginalInteractionResponse"]: HashPerRoute, + RouteIDs["DeleteOriginalInteractionResponse"]: HashPerRoute, + RouteIDs["CreateFollowupMessage"]: HashPerRoute, + RouteIDs["GetFollowupMessage"]: HashPerRoute, + RouteIDs["EditFollowupMessage"]: HashPerRoute, + RouteIDs["DeleteFollowupMessage"]: HashPerRoute, + RouteIDs["GetGuildAuditLog"]: HashPerRoute, + RouteIDs["ListAutoModerationRulesForGuild"]: HashPerRoute, + RouteIDs["GetAutoModerationRule"]: HashPerRoute, + RouteIDs["CreateAutoModerationRule"]: HashPerRoute, + RouteIDs["ModifyAutoModerationRule"]: HashPerRoute, + RouteIDs["DeleteAutoModerationRule"]: HashPerRoute, + RouteIDs["GetChannel"]: HashPerRoute, + RouteIDs["ModifyChannel"]: HashPerRoute, + RouteIDs["ModifyChannelGroupDM"]: HashPerRoute, + RouteIDs["ModifyChannelGuild"]: HashPerRoute, + RouteIDs["ModifyChannelThread"]: HashPerRoute, + RouteIDs["DeleteCloseChannel"]: HashPerRoute, + RouteIDs["GetChannelMessages"]: HashPerRoute, + RouteIDs["GetChannelMessage"]: HashPerRoute, + RouteIDs["CreateMessage"]: HashPerRoute, + RouteIDs["CrosspostMessage"]: HashPerRoute, + RouteIDs["CreateReaction"]: HashPerRoute, + RouteIDs["DeleteOwnReaction"]: HashPerRoute, + RouteIDs["DeleteUserReaction"]: HashPerRoute, + RouteIDs["GetReactions"]: HashPerRoute, + RouteIDs["DeleteAllReactions"]: HashPerRoute, + RouteIDs["DeleteAllReactionsforEmoji"]: HashPerRoute, + RouteIDs["EditMessage"]: HashPerRoute, + RouteIDs["DeleteMessage"]: HashPerRoute, + RouteIDs["BulkDeleteMessages"]: HashPerRoute, + RouteIDs["EditChannelPermissions"]: HashPerRoute, + RouteIDs["GetChannelInvites"]: HashPerRoute, + RouteIDs["CreateChannelInvite"]: HashPerRoute, + RouteIDs["DeleteChannelPermission"]: HashPerRoute, + RouteIDs["FollowAnnouncementChannel"]: HashPerRoute, + RouteIDs["TriggerTypingIndicator"]: HashPerRoute, + RouteIDs["GetPinnedMessages"]: HashPerRoute, + RouteIDs["PinMessage"]: HashPerRoute, + RouteIDs["UnpinMessage"]: HashPerRoute, + RouteIDs["GroupDMAddRecipient"]: HashPerRoute, + RouteIDs["GroupDMRemoveRecipient"]: HashPerRoute, + RouteIDs["StartThreadfromMessage"]: HashPerRoute, + RouteIDs["StartThreadwithoutMessage"]: HashPerRoute, + RouteIDs["StartThreadinForumChannel"]: HashPerRoute, + RouteIDs["JoinThread"]: HashPerRoute, + RouteIDs["AddThreadMember"]: HashPerRoute, + RouteIDs["LeaveThread"]: HashPerRoute, + RouteIDs["RemoveThreadMember"]: HashPerRoute, + RouteIDs["GetThreadMember"]: HashPerRoute, + RouteIDs["ListThreadMembers"]: HashPerRoute, + RouteIDs["ListPublicArchivedThreads"]: HashPerRoute, + RouteIDs["ListPrivateArchivedThreads"]: HashPerRoute, + RouteIDs["ListJoinedPrivateArchivedThreads"]: HashPerRoute, + RouteIDs["ListGuildEmojis"]: HashPerRoute, + RouteIDs["GetGuildEmoji"]: HashPerRoute, + RouteIDs["CreateGuildEmoji"]: HashPerRoute, + RouteIDs["ModifyGuildEmoji"]: HashPerRoute, + RouteIDs["DeleteGuildEmoji"]: HashPerRoute, + RouteIDs["CreateGuild"]: HashPerRoute, + RouteIDs["GetGuild"]: HashPerRoute, + RouteIDs["GetGuildPreview"]: HashPerRoute, + RouteIDs["ModifyGuild"]: HashPerRoute, + RouteIDs["DeleteGuild"]: HashPerRoute, + RouteIDs["CreateDM"]: HashPerRoute, + RouteIDs["GetGuildChannels"]: HashPerRoute, + RouteIDs["CreateGuildChannel"]: HashPerRoute, + RouteIDs["ModifyGuildChannelPositions"]: HashPerRoute, + RouteIDs["ListActiveGuildThreads"]: HashPerRoute, + RouteIDs["GetGuildMember"]: HashPerRoute, + RouteIDs["ListGuildMembers"]: HashPerRoute, + RouteIDs["SearchGuildMembers"]: HashPerRoute, + RouteIDs["AddGuildMember"]: HashPerRoute, + RouteIDs["ModifyGuildMember"]: HashPerRoute, + RouteIDs["ModifyCurrentMember"]: HashPerRoute, + RouteIDs["AddGuildMemberRole"]: HashPerRoute, + RouteIDs["RemoveGuildMemberRole"]: HashPerRoute, + RouteIDs["RemoveGuildMember"]: HashPerRoute, + RouteIDs["GetGuildBans"]: HashPerRoute, + RouteIDs["GetGuildBan"]: HashPerRoute, + RouteIDs["CreateGuildBan"]: HashPerRoute, + RouteIDs["RemoveGuildBan"]: HashPerRoute, + RouteIDs["GetGuildRoles"]: HashPerRoute, + RouteIDs["CreateGuildRole"]: HashPerRoute, + RouteIDs["ModifyGuildRolePositions"]: HashPerRoute, + RouteIDs["ModifyGuildRole"]: HashPerRoute, + RouteIDs["DeleteGuildRole"]: HashPerRoute, + RouteIDs["ModifyGuildMFALevel"]: HashPerRoute, + RouteIDs["GetGuildPruneCount"]: HashPerRoute, + RouteIDs["BeginGuildPrune"]: HashPerRoute, + RouteIDs["GetGuildVoiceRegions"]: HashPerRoute, + RouteIDs["GetGuildInvites"]: HashPerRoute, + RouteIDs["GetGuildIntegrations"]: HashPerRoute, + RouteIDs["DeleteGuildIntegration"]: HashPerRoute, + RouteIDs["GetGuildWidgetSettings"]: HashPerRoute, + RouteIDs["ModifyGuildWidget"]: HashPerRoute, + RouteIDs["GetGuildWidget"]: HashPerRoute, + RouteIDs["GetGuildVanityURL"]: HashPerRoute, + RouteIDs["GetGuildWidgetImage"]: HashPerRoute, + RouteIDs["GetGuildWelcomeScreen"]: HashPerRoute, + RouteIDs["ModifyGuildWelcomeScreen"]: HashPerRoute, + RouteIDs["ModifyCurrentUserVoiceState"]: HashPerRoute, + RouteIDs["ModifyUserVoiceState"]: HashPerRoute, + RouteIDs["ListScheduledEventsforGuild"]: HashPerRoute, + RouteIDs["CreateGuildScheduledEvent"]: HashPerRoute, + RouteIDs["GetGuildScheduledEvent"]: HashPerRoute, + RouteIDs["ModifyGuildScheduledEvent"]: HashPerRoute, + RouteIDs["DeleteGuildScheduledEvent"]: HashPerRoute, + RouteIDs["GetGuildScheduledEventUsers"]: HashPerRoute, + RouteIDs["GetGuildTemplate"]: HashPerRoute, + RouteIDs["CreateGuildfromGuildTemplate"]: HashPerRoute, + RouteIDs["GetGuildTemplates"]: HashPerRoute, + RouteIDs["CreateGuildTemplate"]: HashPerRoute, + RouteIDs["SyncGuildTemplate"]: HashPerRoute, + RouteIDs["ModifyGuildTemplate"]: HashPerRoute, + RouteIDs["DeleteGuildTemplate"]: HashPerRoute, + RouteIDs["GetInvite"]: HashPerRoute, + RouteIDs["DeleteInvite"]: HashPerRoute, + RouteIDs["CreateStageInstance"]: HashPerRoute, + RouteIDs["GetStageInstance"]: HashPerRoute, + RouteIDs["ModifyStageInstance"]: HashPerRoute, + RouteIDs["DeleteStageInstance"]: HashPerRoute, + RouteIDs["GetSticker"]: HashPerRoute, + RouteIDs["ListNitroStickerPacks"]: HashPerRoute, + RouteIDs["ListGuildStickers"]: HashPerRoute, + RouteIDs["GetGuildSticker"]: HashPerRoute, + RouteIDs["CreateGuildSticker"]: HashPerRoute, + RouteIDs["ModifyGuildSticker"]: HashPerRoute, + RouteIDs["DeleteGuildSticker"]: HashPerRoute, + RouteIDs["GetCurrentUser"]: HashPerRoute, + RouteIDs["GetUser"]: HashPerRoute, + RouteIDs["ModifyCurrentUser"]: HashPerRoute, + RouteIDs["GetCurrentUserGuilds"]: HashPerRoute, + RouteIDs["GetCurrentUserGuildMember"]: HashPerRoute, + RouteIDs["LeaveGuild"]: HashPerRoute, + RouteIDs["CreateGroupDM"]: HashPerRoute, + RouteIDs["GetUserConnections"]: HashPerRoute, + RouteIDs["ListVoiceRegions"]: HashPerRoute, + RouteIDs["CreateWebhook"]: HashPerRoute, + RouteIDs["GetChannelWebhooks"]: HashPerRoute, + RouteIDs["GetGuildWebhooks"]: HashPerRoute, + RouteIDs["GetWebhook"]: HashPerRoute, + RouteIDs["GetWebhookwithToken"]: HashPerRoute, + RouteIDs["ModifyWebhook"]: HashPerRoute, + RouteIDs["ModifyWebhookwithToken"]: HashPerRoute, + RouteIDs["DeleteWebhook"]: HashPerRoute, + RouteIDs["DeleteWebhookwithToken"]: HashPerRoute, + RouteIDs["ExecuteWebhook"]: HashPerRoute, + RouteIDs["ExecuteSlackCompatibleWebhook"]: HashPerRoute, + RouteIDs["ExecuteGitHubCompatibleWebhook"]: HashPerRoute, + RouteIDs["GetWebhookMessage"]: HashPerRoute, + RouteIDs["EditWebhookMessage"]: HashPerRoute, + RouteIDs["DeleteWebhookMessage"]: HashPerRoute, + RouteIDs["GetGateway"]: HashPerRoute, + RouteIDs["GetGatewayBot"]: HashPerRoute, + RouteIDs["GetCurrentBotApplicationInformation"]: HashPerRoute, + RouteIDs["GetCurrentAuthorizationInformation"]: HashPerRoute, + } +) + +const ( + GlobalRateLimitRouteID = "0" +) + +// RateLimiter represents an interface for rate limits. +// +// RateLimiter is an interface which allows developers to use multi-application architectures, +// which run multiple applications on separate processes or servers. +type RateLimiter interface { + // SetBucketID maps a Route ID to a Rate Limit Bucket ID (Discord Hash). + // + // ID 0 is reserved for a Global Rate Limit Bucket or nil. + SetBucketID(routeid string, bucketid string) + + // GetBucketID gets a Rate Limit Bucket ID (Discord Hash) using a Route ID. + GetBucketID(routeid string) string + + // SetBucketFromID maps a Bucket ID to a Rate Limit Bucket. + SetBucketFromID(bucketid string, bucket *Bucket) + + // GetBucketFromID gets a Rate Limit Bucket using the given Bucket ID. + GetBucketFromID(bucketid string) *Bucket + + // SetBucket maps a Route ID to a Rate Limit Bucket. + // + // ID 0 is reserved for a Global Rate Limit Bucket or nil. + SetBucket(routeid string, bucket *Bucket) + + // GetBucket gets a Rate Limit Bucket using the given Route ID + Resource ID. + // + // Implements the Default Bucket mechanism by assigning the GetBucketID(routeid) when applicable. + GetBucket(routeid string, resourceid string) *Bucket + + // SetDefaultBucket sets the Default Bucket for per-route rate limits. + SetDefaultBucket(bucket *Bucket) + + // Lock locks the rate limiter. + // + // If the lock is already in use, the calling goroutine blocks until the rate limiter is available. + // + // This prevents multiple requests from being PROCESSED at once, which prevents race conditions. + // In other words, a single request is PROCESSED from a rate limiter when Lock is implemented and called. + // + // This does NOT prevent multiple requests from being SENT at a time. + Lock() + + // Unlock unlocks the rate limiter. + // + // If the rate limiter holds multiple locks, unlocking will unblock another goroutine, + // which allows another request to be processed. + Unlock() + + // StartTx starts a transaction with the rate limiter. + // + // If a transaction is already started, the calling goroutine blocks until the rate limiter is available. + // + // This prevents the transaction (of Rate Limit Bucket reads and writes) from concurrent manipulation. + StartTx() + + // EndTx ends a transaction with the rate limiter. + // + // If the rate limiter holds multiple transactions, ending one will unblock another goroutine, + // which allows another transaction to start. + EndTx() +} + +// Bucket represents a Discord API Rate Limit Bucket. +type Bucket struct { + // Date represents the time at which Discord received the last request of the Bucket. + // + // Date is only applicable to Global Rate Limit Buckets. + Date time.Time + + // Expiry represents the time at which the Bucket will reset (or become outdated). + Expiry time.Time + + // ID represents the Bucket ID. + ID string + + // Limit represents the amount of requests a Bucket can send per reset. + Limit int16 + + // Remaining represents the amount of requests a Bucket can send until the next reset. + Remaining int16 + + // Pending represents the amount of requests that are sent and awaiting a response. + Pending int16 +} + +// Reset resets a Discord API Rate Limit Bucket and sets its expiry. +func (b *Bucket) Reset(expiry time.Time) { + b.Expiry = expiry + + // Remaining = Limit - Pending + b.Remaining = b.Limit - b.Pending +} + +// Use uses the given amount of tokens for a Discord API Rate Limit Bucket. +func (b *Bucket) Use(amount int16) { + b.Remaining -= amount + b.Pending += amount +} + +// ConfirmDate confirms the usage of a given amount of tokens for a Discord API Rate Limit Bucket, +// using the bucket's current expiry and given (Discord Header) Date time. +// +// Used for the Global Rate Limit Bucket. +func (b *Bucket) ConfirmDate(amount int16, date time.Time) { + b.Pending -= amount + + switch { + // Date is zero when a request has never been sent to Discord. + // + // set the Date of the current Bucket to the date of the current Discord Bucket. + case b.Date.IsZero(): + b.Date = date + + // The EXACT reset period of Discord's Global Rate Limit Bucket will always occur + // BEFORE the current Bucket resets (due to this implementation). + // + // reset the current Bucket with an expiry that occurs [0, 1) seconds + // AFTER the Discord Global Rate Limit Bucket will be reset. + // + // This results in a Bucket's expiry that is eventually consistent with + // Discord's Bucket expiry over time (once determined between requests). + b.Expiry = time.Now().Add(time.Second) + + // Date is EQUAL to the Discord Bucket's Date when the request applies to the current Bucket. + case b.Date.Equal(date): + + // Date occurs BEFORE a Discord Bucket's Date when the request applies to the next Bucket. + // + // update the current Bucket to the next Bucket. + case b.Date.Before(date): + b.Date = date + + // align the current Bucket's expiry to Discord's Bucket expiry. + b.Expiry = time.Now().Add(time.Second) + + // Date occurs AFTER a Discord Bucket's Date when the request applied to a previous Bucket. + case b.Date.After(date): + b.Remaining += amount + } +} + +// ConfirmHeader confirms the usage of a given amount of tokens for a Discord API Rate Limit Bucket, +// using a given Route ID and respective Discord Rate Limit Header. +// +// Used for Route Rate Limits. +func (b *Bucket) ConfirmHeader(amount int16, header RateLimitHeader) { + b.Pending -= amount + + // determine the reset time. + // + // Discord recommends to rely on the `Retry-After` header. + // https://discord.com/developers/docs/topics/rate-limits#exceeding-a-rate-limit + reset := time.Now().Add(time.Millisecond*time.Duration(header.ResetAfter*msPerSecond) + time.Millisecond) + + // Expiry is zero when a request from the Route ID has never been sent to Discord. + // + // set the current Bucket to the current Discord Bucket. + if b.Expiry.IsZero() { + b.Limit = int16(header.Limit) + b.Remaining = int16(header.Remaining) - b.Pending + b.Expiry = reset + + return + } + + switch { + // Expiry is EQUAL to the Discord Bucket's Reset when the request applies to the current Bucket. + case b.Expiry == reset: + + // Expiry occurs BEFORE a Discord Bucket's Reset when the request applies to the next Bucket. + // + // update the current Bucket to the next Bucket. + case b.Expiry.Before(reset): + b.Limit = int16(header.Limit) + b.Expiry = reset + + // Expiry occurs AFTER a Discord Bucket's Reset when the request applied to a previous Bucket. + case b.Expiry.After(reset): + b.Remaining += amount + } +} + +// Conversion Constants. +const ( + base10 = 10 + bit64 = 64 + msPerSecond float64 = 1000 +) + +// Content Types +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type +var ( + // ContentTypeURLQueryString is an HTTP Header Content Type that indicates + // a payload with an encoded URL Query String. + ContentTypeURLQueryString = []byte("application/x-www-form-urlencoded") + + // ContentTypeJSON is an HTTP Header Content Type that indicates a payload with a JSON body. + ContentTypeJSON = []byte("application/json") + + // ContentTypeMultipartForm is an HTTP Header Content Type that indicates + // a payload with multiple content types. + ContentTypeMultipartForm = []byte("multipart/form-data") + + // ContentTypeJPEG is an HTTP Header Content Type that indicates a payload with a JPEG image. + ContentTypeJPEG = []byte("image/jpeg") + + // ContentTypePNG is an HTTP Header Content Type that indicates a payload with a PNG image. + ContentTypePNG = []byte("image/png") + + // ContentTypeWebP is an HTTP Header Content Type that indicates a payload with a WebP image. + ContentTypeWebP = []byte("image/webp") + + // ContentTypeGIF is an HTTP Header Content Type that indicates a payload with a GIF animated image. + ContentTypeGIF = []byte("image/gif") +) + +// HTTP Header Variables. +const ( + // headerAuthorizationKey represents the key for an "Authorization" HTTP Header. + headerAuthorizationKey = "Authorization" +) + +// HTTP Header Rate Limit Variables. +var ( + // headerDate represents a byte representation of "Date" for HTTP Header functionality. + headerDate = []byte(FlagRateLimitHeaderDate) + + // headerRetryAfter represents a byte representation of "Retry-After" for HTTP Header functionality. + headerRateLimitRetryAfter = []byte(FlagRateLimitHeaderRetryAfter) + + // headerRateLimit represents a byte representation of "X-RateLimit-Limit" for HTTP Header functionality. + headerRateLimit = []byte(FlagRateLimitHeaderLimit) + + // headerRateLimitRemaining represents a byte representation of "X-RateLimit-Remaining" for HTTP Header functionality. + headerRateLimitRemaining = []byte(FlagRateLimitHeaderRemaining) + + // headerRateLimitReset represents a byte representation of "X-RateLimit-Reset" for HTTP Header functionality. + headerRateLimitReset = []byte(FlagRateLimitHeaderReset) + + // headerRateLimitResetAfter represents a byte representation of "X-RateLimit-Reset-After" for HTTP Header functionality. + headerRateLimitResetAfter = []byte(FlagRateLimitHeaderResetAfter) + + // headerRateLimitBucket represents a byte representation of "X-RateLimit-Bucket" for HTTP Header functionality. + headerRateLimitBucket = []byte(FlagRateLimitHeaderBucket) + + // headerRateLimitGlobal represents a byte representation of "X-RateLimit-Global" for HTTP Header functionality. + headerRateLimitGlobal = []byte(FlagRateLimitHeaderGlobal) + + // headerRateLimitScope represents a byte representation of "X-RateLimit-Scope" for HTTP Header functionality. + headerRateLimitScope = []byte(FlagRateLimitHeaderScope) +) + +// peekDate peeks an HTTP Header for the Date. +func peekDate(r *fasthttp.Response) (time.Time, error) { + date, err := time.Parse(time.RFC1123, string(r.Header.PeekBytes(headerDate))) + if err != nil { + return time.Time{}, fmt.Errorf("error occurred parsing the \"Date\" HTTP Header: %w", err) + } + + return date, nil +} + +// peekHeaderRetryAfter peeks an HTTP Header for the Rate Limit Header "Retry-After". +func peekHeaderRetryAfter(r *fasthttp.Response) (float64, error) { + retryafter, err := strconv.ParseFloat(string(r.Header.PeekBytes(headerRateLimitRetryAfter)), bit64) + if err != nil { + return 0, fmt.Errorf(errRateLimit, string(headerRateLimitRetryAfter), err) + } + + return retryafter, nil +} + +// peekHeaderRateLimit peeks an HTTP Header for Discord Rate Limit Header values. +func peekHeaderRateLimit(r *fasthttp.Response) RateLimitHeader { + limit, _ := strconv.Atoi(string(r.Header.PeekBytes(headerRateLimit))) + remaining, _ := strconv.Atoi(string(r.Header.PeekBytes(headerRateLimitRemaining))) + reset, _ := strconv.ParseFloat(string(r.Header.PeekBytes(headerRateLimitReset)), bit64) + resetafter, _ := strconv.ParseFloat(string(r.Header.PeekBytes(headerRateLimitResetAfter)), bit64) + global, _ := strconv.ParseBool(string(r.Header.PeekBytes(headerRateLimitGlobal))) + + return RateLimitHeader{ + Limit: limit, + Remaining: remaining, + Reset: reset, + ResetAfter: resetafter, + Bucket: string(r.Header.PeekBytes(headerRateLimitBucket)), + Global: global, + Scope: string(r.Header.PeekBytes(headerRateLimitScope)), + } +} + +// SendRequest sends a fasthttp.Request using the given route ID, HTTP method, URI, content type and body, +// then parses the response into dst. +func SendRequest(bot *Client, xid, routeid, resourceid, method, uri string, content, body []byte, dst any) error { //nolint:gocyclo,maintidx + retries := 0 + requestid := routeid + resourceid + request := fasthttp.AcquireRequest() + defer fasthttp.ReleaseRequest(request) + request.Header.SetMethod(method) + request.Header.SetContentTypeBytes(content) + request.Header.Set(headerAuthorizationKey, bot.Authentication.Header) + request.SetRequestURI(uri) + request.SetBodyRaw(body) + response := fasthttp.AcquireResponse() + defer fasthttp.ReleaseResponse(response) + + // Certain endpoints are not bound to the bot's Global Rate Limit. + if IgnoreGlobalRateLimitRouteIDs[requestid] { + goto SEND + } + +RATELIMIT: + // a single request or response is PROCESSED at any point in time. + bot.Config.Request.RateLimiter.Lock() + + LogRequest(Logger.Trace(), bot.ApplicationID, xid, routeid, resourceid, uri).Msg("processing request") + if Logger.GetLevel() == zerolog.TraceLevel { + LogRequestBody(Logger.Trace(), bot.ApplicationID, xid, routeid, resourceid, uri, string(body)).Msg("") + } + + // check Global and Route Rate Limit Buckets prior to sending the current request. + for { + bot.Config.Request.RateLimiter.StartTx() + + globalBucket := bot.Config.Request.RateLimiter.GetBucket(GlobalRateLimitRouteID, "") + + // stop waiting when the Global Rate Limit Bucket is NOT empty. + if isNotEmpty(globalBucket) { + routeBucket := bot.Config.Request.RateLimiter.GetBucket(routeid, resourceid) + + if isNotEmpty(routeBucket) { + break + } + + if isExpired(routeBucket) { + // When a Route Bucket expires, its new expiry becomes unknown. + // As a result, it will never reset (again) until a pending request's + // response sets a new expiry. + routeBucket.Reset(time.Time{}) + } + + var wait time.Time + if routeBucket != nil { + wait = routeBucket.Expiry + } + + // do NOT block other requests due to a Route Rate Limit. + bot.Config.Request.RateLimiter.EndTx() + bot.Config.Request.RateLimiter.Unlock() + + // reduce CPU usage by blocking the current goroutine + // until it's eligible for action. + if routeBucket != nil { + <-time.After(time.Until(wait)) + } + + goto RATELIMIT + } + + // reset the Global Rate Limit Bucket when the current Bucket has passed its expiry. + if isExpired(globalBucket) { + globalBucket.Reset(time.Now().Add(time.Second)) + } + + bot.Config.Request.RateLimiter.EndTx() + } + + if globalBucket := bot.Config.Request.RateLimiter.GetBucket(GlobalRateLimitRouteID, ""); globalBucket != nil { + globalBucket.Use(1) + } + + if routeBucket := bot.Config.Request.RateLimiter.GetBucket(routeid, resourceid); routeBucket != nil { + routeBucket.Use(1) + } + + bot.Config.Request.RateLimiter.EndTx() + bot.Config.Request.RateLimiter.Unlock() + +SEND: + LogRequest(Logger.Trace(), bot.ApplicationID, xid, routeid, resourceid, uri).Msg("sending request") + + // send the request. + if err := bot.Config.Request.Client.DoTimeout(request, response, bot.Config.Request.Timeout); err != nil { + return fmt.Errorf("%w", err) + } + + LogResponse(LogRequest(Logger.Info(), bot.ApplicationID, xid, routeid, resourceid, uri), + response.Header.String(), string(response.Body()), + ).Msg("") + + var header RateLimitHeader + + // confirm the response with the rate limiter. + // + // Certain endpoints are not bound to the bot's Global Rate Limit. + if !IgnoreGlobalRateLimitRouteIDs[requestid] { + // parse the Rate Limit Header for per-route rate limit functionality. + header = peekHeaderRateLimit(response) + + // parse the Date header for Global Rate Limit functionality. + date, err := peekDate(response) + if err != nil { + return fmt.Errorf("%w", err) + } + + bot.Config.Request.RateLimiter.StartTx() + + // confirm the Global Rate Limit Bucket. + globalBucket := bot.Config.Request.RateLimiter.GetBucket(GlobalRateLimitRouteID, "") + if globalBucket != nil { + globalBucket.ConfirmDate(1, date) + } + + // confirm the Route Rate Limit Bucket (if applicable). + routeBucket := bot.Config.Request.RateLimiter.GetBucket(routeid, resourceid) + switch { + // when there is no Discord Bucket, remove the route's mapping to a rate limit Bucket. + case header.Bucket == "": + if routeBucket != nil { + bot.Config.Request.RateLimiter.SetBucketID(requestid, nilRouteBucket) + routeBucket = nil + } + + // when the route's Bucket ID does NOT match the Discord Bucket, update it. + case routeBucket == nil && header.Bucket != "" || routeBucket.ID != header.Bucket: + var pending int16 + if routeBucket != nil { + pending = routeBucket.Pending + } + + // update the route ID mapping to a rate limit Bucket ID. + bot.Config.Request.RateLimiter.SetBucketID(requestid, header.Bucket) + + // map the Bucket ID to the updated Rate Limit Bucket. + if bucket := bot.Config.Request.RateLimiter.GetBucketFromID(header.Bucket); bucket != nil { + routeBucket = bucket + } else { + routeBucket = getBucket() + bot.Config.Request.RateLimiter.SetBucketFromID(header.Bucket, routeBucket) + } + + routeBucket.Pending += pending + routeBucket.ID = header.Bucket + } + + if routeBucket != nil { + routeBucket.ConfirmHeader(1, header) + } + + if response.StatusCode() != fasthttp.StatusTooManyRequests { + bot.Config.Request.RateLimiter.EndTx() + } + } + + // handle the response. + switch response.StatusCode() { + case fasthttp.StatusOK, fasthttp.StatusCreated: + // parse the response data. + if err := json.Unmarshal(response.Body(), dst); err != nil { + return fmt.Errorf(errUnmarshal, dst, err) + } + + return nil + + case fasthttp.StatusNoContent: + return nil + + // process the rate limit. + case fasthttp.StatusTooManyRequests: + retry := retries < bot.Config.Request.Retries + retries++ + + switch header.Scope { //nolint:gocritic + // Discord per-resource (shared) rate limit headers include the per-route (user) bucket. + // + // when a per-resource rate limit is encountered, send another request or return. + case RateLimitScopeValueShared: + bot.Config.Request.RateLimiter.EndTx() + + if retry || bot.Config.Request.RetryShared { + goto RATELIMIT + } + + return StatusCodeError(response.StatusCode()) + } + + // parse the rate limit response data for `retry_after`. + var data RateLimitResponse + if err := json.Unmarshal(response.Body(), &data); err != nil { + return fmt.Errorf("%w", err) + } + + // determine the reset time. + var reset time.Time + if data.RetryAfter == 0 { + // when the 429 is from Discord, use the `retry_after` value (s). + reset = time.Now().Add(time.Millisecond * time.Duration(data.RetryAfter*msPerSecond)) + } else { + // when the 429 is from a Cloudflare Ban, use the `"Retry-After"` value (s). + retryafter, err := peekHeaderRetryAfter(response) + if err != nil { + return fmt.Errorf("%w", err) + } + + reset = time.Now().Add(time.Millisecond * time.Duration(retryafter*msPerSecond)) + } + + LogRequest(Logger.Debug(), bot.ApplicationID, xid, routeid, resourceid, uri). + Time(LogCtxReset, reset).Msg("") + + switch header.Global { + // when the global request rate limit is encountered. + case true: + // when the current time is BEFORE the reset time, + // all requests must wait until the 429 expires. + if time.Now().Before(reset) { + if globalBucket := bot.Config.Request.RateLimiter.GetBucket(GlobalRateLimitRouteID, ""); globalBucket != nil { + globalBucket.Remaining = 0 + globalBucket.Expiry = reset.Add(time.Millisecond) + } + } + + bot.Config.Request.RateLimiter.EndTx() + + // when a per-route (user) rate limit is encountered. + case false: + // do NOT block other requests while waiting for a Route Rate Limit. + bot.Config.Request.RateLimiter.EndTx() + + // when the current time is BEFORE the reset time, + // requests with the same Rate Limit Bucket must wait until the 429 expires. + if time.Now().Before(reset) { + if routeBucket := bot.Config.Request.RateLimiter.GetBucket(routeid, resourceid); routeBucket != nil { + routeBucket.Remaining = 0 + routeBucket.Expiry = reset.Add(time.Millisecond) + } + } + } + + if retry { + goto RATELIMIT + } + + return StatusCodeError(fasthttp.StatusTooManyRequests) + + // retry the request on a bad gateway server error. + case fasthttp.StatusBadGateway: + if retries < bot.Config.Request.Retries { + retries++ + + goto RATELIMIT + } + + return StatusCodeError(fasthttp.StatusBadGateway) + + default: + return StatusCodeError(response.StatusCode()) + } +} + +// isExpired determines whether a rate limit Bucket is expired. +func isExpired(b *Bucket) bool { + // a rate limit bucket is expired when + // 1. the bucket exists AND + // 2. the current time occurs after the non-zero expiry time. + return b != nil && !b.Expiry.IsZero() && time.Now().After(b.Expiry) +} + +// isNotEmpty determines whether a rate limit Bucket is NOT empty. +func isNotEmpty(b *Bucket) bool { + // a rate limit bucket is NOT empty when + // 1. the bucket does not exist OR + // 2. there is one or more remaining request token(s). + return b == nil || b.Remaining > 0 +} + +// boundary represents the boundary that is used in every multipart form. +var boundary = randomBoundary() + +// randomBoundary generates a random value to be used as a boundary in multipart forms. +// +// Implemented from the mime/multipart package. +func randomBoundary() string { + var buf [30]byte + _, err := io.ReadFull(rand.Reader, buf[:]) + if err != nil { + panic(err) + } + + return fmt.Sprintf("%x", buf[:]) +} + +// quoteEscaper escapes quotes and backslashes in a multipart form. +var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") + +// createMultipartForm creates a multipart/form for Discord using a given JSON body and files. +func createMultipartForm(json []byte, files ...*File) ([]byte, []byte, error) { + form := bytes.NewBuffer(nil) + + // set the boundary. + multipartWriter := multipart.NewWriter(form) + err := multipartWriter.SetBoundary(boundary) + if err != nil { + return nil, nil, fmt.Errorf("error setting multipart form boundary: %w", err) + } + + // add the `payload_json` JSON to the form. + multipartPayloadJSONPart, err := createPayloadJSONForm(multipartWriter) + if err != nil { + return nil, nil, fmt.Errorf("error adding JSON payload header to multipart form: %w", err) + } + + if _, err := multipartPayloadJSONPart.Write(json); err != nil { + return nil, nil, fmt.Errorf("error writing JSON payload data to multipart form: %w", err) + } + + // add the remaining files to the form. + for i, file := range files { + name := strings.Join([]string{"files[", strconv.Itoa(i), "]"}, "") + multipartFilePart, err := createFormFile(multipartWriter, name, file.Name, file.ContentType) + if err != nil { + return nil, nil, fmt.Errorf("error adding a file %q to a multipart form: %w", file.Name, err) + } + + if _, err := multipartFilePart.Write(file.Data); err != nil { + return nil, nil, fmt.Errorf("error writing file %q data to multipart form: %w", file.Name, err) + } + } + + // write the trailing boundary. + if err := multipartWriter.Close(); err != nil { + return nil, nil, fmt.Errorf("error closing the multipart form: %w", err) + } + + return []byte(multipartWriter.FormDataContentType()), form.Bytes(), nil +} + +var ( + // contentTypeJSONString is an HTTP Header Content Type that indicates a payload with a JSON body. + contentTypeJSONString = "application/json" + + // contentTypeOctetStreamString is an HTTP Header Content Type that indicates a payload with binary data. + contentTypeOctetStreamString = "application/octet-stream" +) + +// createPayloadJSONForm creates a form-data header for the `payload_json` file in a multipart form. +func createPayloadJSONForm(m *multipart.Writer) (io.Writer, error) { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", `form-data; name="payload_json"`) + h.Set("Content-Type", contentTypeJSONString) + + return m.CreatePart(h) //nolint:wrapcheck +} + +// createFormFile creates a form-data header for file attachments in a multipart form. +func createFormFile(m *multipart.Writer, name, filename, contentType string) (io.Writer, error) { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="%s"; filename="%s"`, name, quoteEscaper.Replace(filename))) + + if "" == contentType { + contentType = contentTypeOctetStreamString + } + + h.Set("Content-Type", contentType) + + return m.CreatePart(h) //nolint:wrapcheck +} + +var ( + // qsEncoder is used to create URL Query Strings from objects. + qsEncoder = schema.NewEncoder() +) + +// init runs at the start of the program. +func init() { + // use `url` tags for the URL Query String encoder and decoder. + qsEncoder.SetAliasTag("url") +} + +// EndpointQueryString returns a URL Query String from a given object. +func EndpointQueryString(dst any) (string, error) { + params := url.Values{} + err := qsEncoder.Encode(dst, params) + if err != nil { + return "", err //nolint:wrapcheck + } + + return params.Encode(), nil +} + +var ( + // RouteIDs represents a map of Routes to Route IDs (map[string]uint8). + RouteIDs = map[string]uint8{ + "": 0, + "OAuth": 1, + "GetGlobalApplicationCommands": 2, + "CreateGlobalApplicationCommand": 3, + "GetGlobalApplicationCommand": 4, + "EditGlobalApplicationCommand": 5, + "DeleteGlobalApplicationCommand": 6, + "BulkOverwriteGlobalApplicationCommands": 7, + "GetGuildApplicationCommands": 8, + "CreateGuildApplicationCommand": 9, + "GetGuildApplicationCommand": 10, + "EditGuildApplicationCommand": 11, + "DeleteGuildApplicationCommand": 12, + "BulkOverwriteGuildApplicationCommands": 13, + "GetGuildApplicationCommandPermissions": 14, + "GetApplicationCommandPermissions": 15, + "EditApplicationCommandPermissions": 16, + "BatchEditApplicationCommandPermissions": 17, + "CreateInteractionResponse": 18, + "GetOriginalInteractionResponse": 19, + "EditOriginalInteractionResponse": 20, + "DeleteOriginalInteractionResponse": 21, + "CreateFollowupMessage": 22, + "GetFollowupMessage": 23, + "EditFollowupMessage": 24, + "DeleteFollowupMessage": 25, + "GetGuildAuditLog": 26, + "ListAutoModerationRulesForGuild": 27, + "GetAutoModerationRule": 28, + "CreateAutoModerationRule": 29, + "ModifyAutoModerationRule": 30, + "DeleteAutoModerationRule": 31, + "GetChannel": 32, + "ModifyChannel": 33, + "ModifyChannelGroupDM": 34, + "ModifyChannelGuild": 35, + "ModifyChannelThread": 36, + "DeleteCloseChannel": 37, + "GetChannelMessages": 38, + "GetChannelMessage": 39, + "CreateMessage": 40, + "CrosspostMessage": 41, + "CreateReaction": 42, + "DeleteOwnReaction": 43, + "DeleteUserReaction": 44, + "GetReactions": 45, + "DeleteAllReactions": 46, + "DeleteAllReactionsforEmoji": 47, + "EditMessage": 48, + "DeleteMessage": 49, + "BulkDeleteMessages": 50, + "EditChannelPermissions": 51, + "GetChannelInvites": 52, + "CreateChannelInvite": 53, + "DeleteChannelPermission": 54, + "FollowAnnouncementChannel": 55, + "TriggerTypingIndicator": 56, + "GetPinnedMessages": 57, + "PinMessage": 58, + "UnpinMessage": 59, + "GroupDMAddRecipient": 60, + "GroupDMRemoveRecipient": 61, + "StartThreadfromMessage": 62, + "StartThreadwithoutMessage": 63, + "StartThreadinForumChannel": 64, + "JoinThread": 65, + "AddThreadMember": 66, + "LeaveThread": 67, + "RemoveThreadMember": 68, + "GetThreadMember": 69, + "ListThreadMembers": 70, + "ListPublicArchivedThreads": 71, + "ListPrivateArchivedThreads": 72, + "ListJoinedPrivateArchivedThreads": 73, + "ListGuildEmojis": 74, + "GetGuildEmoji": 75, + "CreateGuildEmoji": 76, + "ModifyGuildEmoji": 77, + "DeleteGuildEmoji": 78, + "CreateGuild": 79, + "GetGuild": 80, + "GetGuildPreview": 81, + "ModifyGuild": 82, + "DeleteGuild": 83, + "GetGuildChannels": 84, + "CreateGuildChannel": 85, + "ModifyGuildChannelPositions": 86, + "ListActiveGuildThreads": 87, + "GetGuildMember": 88, + "ListGuildMembers": 89, + "SearchGuildMembers": 90, + "AddGuildMember": 91, + "ModifyGuildMember": 92, + "ModifyCurrentMember": 93, + "AddGuildMemberRole": 94, + "RemoveGuildMemberRole": 95, + "RemoveGuildMember": 96, + "GetGuildBans": 97, + "GetGuildBan": 98, + "CreateGuildBan": 99, + "RemoveGuildBan": 100, + "GetGuildRoles": 101, + "CreateGuildRole": 102, + "ModifyGuildRolePositions": 103, + "ModifyGuildRole": 104, + "DeleteGuildRole": 105, + "ModifyGuildMFALevel": 106, + "GetGuildPruneCount": 107, + "BeginGuildPrune": 108, + "GetGuildVoiceRegions": 109, + "GetGuildInvites": 110, + "GetGuildIntegrations": 111, + "DeleteGuildIntegration": 112, + "GetGuildWidgetSettings": 113, + "ModifyGuildWidget": 114, + "GetGuildWidget": 115, + "GetGuildVanityURL": 116, + "GetGuildWidgetImage": 117, + "GetGuildWelcomeScreen": 118, + "ModifyGuildWelcomeScreen": 119, + "ModifyCurrentUserVoiceState": 120, + "ModifyUserVoiceState": 121, + "ListScheduledEventsforGuild": 122, + "CreateGuildScheduledEvent": 123, + "GetGuildScheduledEvent": 124, + "ModifyGuildScheduledEvent": 125, + "DeleteGuildScheduledEvent": 126, + "GetGuildScheduledEventUsers": 127, + "GetGuildTemplate": 128, + "CreateGuildfromGuildTemplate": 129, + "GetGuildTemplates": 130, + "CreateGuildTemplate": 131, + "SyncGuildTemplate": 132, + "ModifyGuildTemplate": 133, + "DeleteGuildTemplate": 134, + "GetInvite": 135, + "DeleteInvite": 136, + "CreateStageInstance": 137, + "GetStageInstance": 138, + "ModifyStageInstance": 139, + "DeleteStageInstance": 140, + "GetSticker": 141, + "ListNitroStickerPacks": 142, + "ListGuildStickers": 143, + "GetGuildSticker": 144, + "CreateGuildSticker": 145, + "ModifyGuildSticker": 146, + "DeleteGuildSticker": 147, + "GetCurrentUser": 148, + "GetUser": 149, + "ModifyCurrentUser": 150, + "GetCurrentUserGuilds": 151, + "GetCurrentUserGuildMember": 152, + "LeaveGuild": 153, + "CreateDM": 154, + "CreateGroupDM": 155, + "GetUserConnections": 156, + "ListVoiceRegions": 157, + "CreateWebhook": 158, + "GetChannelWebhooks": 159, + "GetGuildWebhooks": 160, + "GetWebhook": 161, + "GetWebhookwithToken": 162, + "ModifyWebhook": 163, + "ModifyWebhookwithToken": 164, + "DeleteWebhook": 165, + "DeleteWebhookwithToken": 166, + "ExecuteWebhook": 167, + "ExecuteSlackCompatibleWebhook": 168, + "ExecuteGitHubCompatibleWebhook": 169, + "GetWebhookMessage": 170, + "EditWebhookMessage": 171, + "DeleteWebhookMessage": 172, + "GetGateway": 173, + "GetGatewayBot": 174, + "GetCurrentBotApplicationInformation": 175, + "GetCurrentAuthorizationInformation": 176, + } +) + +// Send sends a GetGlobalApplicationCommands request to Discord and returns a []*ApplicationCommand. +func (r *GetGlobalApplicationCommands) Send(bot *Client) ([]*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[2]("2") + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGlobalApplicationCommands(bot.ApplicationID) + "?" + query + + result := make([]*ApplicationCommand, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGlobalApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *CreateGlobalApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[3]("3") + endpoint := EndpointCreateGlobalApplicationCommand(bot.ApplicationID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGlobalApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *GetGlobalApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[4]("4", "297ffb1f"+r.CommandID) + endpoint := EndpointGetGlobalApplicationCommand(bot.ApplicationID, r.CommandID) + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a EditGlobalApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *EditGlobalApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[5]("5", "297ffb1f"+r.CommandID) + endpoint := EndpointEditGlobalApplicationCommand(bot.ApplicationID, r.CommandID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGlobalApplicationCommand request to Discord and returns a error. +func (r *DeleteGlobalApplicationCommand) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[6]("6", "297ffb1f"+r.CommandID) + endpoint := EndpointDeleteGlobalApplicationCommand(bot.ApplicationID, r.CommandID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a BulkOverwriteGlobalApplicationCommands request to Discord and returns a []*ApplicationCommand. +func (r *BulkOverwriteGlobalApplicationCommands) Send(bot *Client) ([]*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[7]("7") + endpoint := EndpointBulkOverwriteGlobalApplicationCommands(bot.ApplicationID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := make([]*ApplicationCommand, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildApplicationCommands request to Discord and returns a []*ApplicationCommand. +func (r *GetGuildApplicationCommands) Send(bot *Client) ([]*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[8]("8", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildApplicationCommands(bot.ApplicationID, r.GuildID) + "?" + query + + result := make([]*ApplicationCommand, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *CreateGuildApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[9]("9", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildApplicationCommand(bot.ApplicationID, r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *GetGuildApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[10]("10", "45892a5d"+r.GuildID, "297ffb1f"+r.CommandID) + endpoint := EndpointGetGuildApplicationCommand(bot.ApplicationID, r.GuildID, r.CommandID) + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a EditGuildApplicationCommand request to Discord and returns a ApplicationCommand. +func (r *EditGuildApplicationCommand) Send(bot *Client) (*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[11]("11", "45892a5d"+r.GuildID, "297ffb1f"+r.CommandID) + endpoint := EndpointEditGuildApplicationCommand(bot.ApplicationID, r.GuildID, r.CommandID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(ApplicationCommand) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildApplicationCommand request to Discord and returns a error. +func (r *DeleteGuildApplicationCommand) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[12]("12", "45892a5d"+r.GuildID, "297ffb1f"+r.CommandID) + endpoint := EndpointDeleteGuildApplicationCommand(bot.ApplicationID, r.GuildID, r.CommandID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a BulkOverwriteGuildApplicationCommands request to Discord and returns a []*ApplicationCommand. +func (r *BulkOverwriteGuildApplicationCommands) Send(bot *Client) ([]*ApplicationCommand, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[13]("13", "45892a5d"+r.GuildID) + endpoint := EndpointBulkOverwriteGuildApplicationCommands(bot.ApplicationID, r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := make([]*ApplicationCommand, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildApplicationCommandPermissions request to Discord and returns a GuildApplicationCommandPermissions. +func (r *GetGuildApplicationCommandPermissions) Send(bot *Client) (*GuildApplicationCommandPermissions, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[14]("14", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildApplicationCommandPermissions(bot.ApplicationID, r.GuildID) + + result := new(GuildApplicationCommandPermissions) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetApplicationCommandPermissions request to Discord and returns a GuildApplicationCommandPermissions. +func (r *GetApplicationCommandPermissions) Send(bot *Client) (*GuildApplicationCommandPermissions, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[15]("15", "45892a5d"+r.GuildID, "297ffb1f"+r.CommandID) + endpoint := EndpointGetApplicationCommandPermissions(bot.ApplicationID, r.GuildID, r.CommandID) + + result := new(GuildApplicationCommandPermissions) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a EditApplicationCommandPermissions request to Discord and returns a GuildApplicationCommandPermissions. +func (r *EditApplicationCommandPermissions) Send(bot *Client) (*GuildApplicationCommandPermissions, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[16]("16", "45892a5d"+r.GuildID, "297ffb1f"+r.CommandID) + endpoint := EndpointEditApplicationCommandPermissions(bot.ApplicationID, r.GuildID, r.CommandID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildApplicationCommandPermissions) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a BatchEditApplicationCommandPermissions request to Discord and returns a GuildApplicationCommandPermissions. +func (r *BatchEditApplicationCommandPermissions) Send(bot *Client) (*GuildApplicationCommandPermissions, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[17]("17", "45892a5d"+r.GuildID) + endpoint := EndpointBatchEditApplicationCommandPermissions(bot.ApplicationID, r.GuildID) + + result := new(GuildApplicationCommandPermissions) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateInteractionResponse request to Discord and returns a error. +func (r *CreateInteractionResponse) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[18]("18", "beb3d0e6"+r.InteractionID, "cb69bb28"+r.InteractionToken) + endpoint := EndpointCreateInteractionResponse(r.InteractionID, r.InteractionToken) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetOriginalInteractionResponse request to Discord and returns a error. +func (r *GetOriginalInteractionResponse) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[19]("19", "cb69bb28"+r.InteractionToken) + query, err := EndpointQueryString(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetOriginalInteractionResponse(bot.ApplicationID, r.InteractionToken) + "?" + query + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeURLQueryString, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a EditOriginalInteractionResponse request to Discord and returns a Message. +func (r *EditOriginalInteractionResponse) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[20]("20", "cb69bb28"+r.InteractionToken) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointEditOriginalInteractionResponse(bot.ApplicationID, r.InteractionToken) + "?" + query + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteOriginalInteractionResponse request to Discord and returns a error. +func (r *DeleteOriginalInteractionResponse) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[21]("21", "cb69bb28"+r.InteractionToken) + endpoint := EndpointDeleteOriginalInteractionResponse(bot.ApplicationID, r.InteractionToken) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a CreateFollowupMessage request to Discord and returns a Message. +func (r *CreateFollowupMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[22]("22", "cb69bb28"+r.InteractionToken) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointCreateFollowupMessage(bot.ApplicationID, r.InteractionToken) + "?" + query + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetFollowupMessage request to Discord and returns a Message. +func (r *GetFollowupMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[23]("23", "cb69bb28"+r.InteractionToken, "d57d6589"+r.MessageID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetFollowupMessage(bot.ApplicationID, r.InteractionToken, r.MessageID) + "?" + query + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a EditFollowupMessage request to Discord and returns a Message. +func (r *EditFollowupMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[24]("24", "cb69bb28"+r.InteractionToken, "d57d6589"+r.MessageID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointEditFollowupMessage(bot.ApplicationID, r.InteractionToken, r.MessageID) + "?" + query + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteFollowupMessage request to Discord and returns a error. +func (r *DeleteFollowupMessage) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[25]("25", "cb69bb28"+r.InteractionToken, "d57d6589"+r.MessageID) + endpoint := EndpointDeleteFollowupMessage(bot.ApplicationID, r.InteractionToken, r.MessageID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildAuditLog request to Discord and returns a AuditLog. +func (r *GetGuildAuditLog) Send(bot *Client) (*AuditLog, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[26]("26", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildAuditLog(r.GuildID) + "?" + query + + result := new(AuditLog) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListAutoModerationRulesForGuild request to Discord and returns a []*AutoModerationAction. +func (r *ListAutoModerationRulesForGuild) Send(bot *Client) ([]*AutoModerationAction, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[27]("27", "45892a5d"+r.GuildID) + endpoint := EndpointListAutoModerationRulesForGuild(r.GuildID) + + result := make([]*AutoModerationAction, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetAutoModerationRule request to Discord and returns a AutoModerationRule. +func (r *GetAutoModerationRule) Send(bot *Client) (*AutoModerationRule, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[28]("28", "45892a5d"+r.GuildID, "1b7efe5d"+r.AutoModerationRuleID) + endpoint := EndpointGetAutoModerationRule(r.GuildID, r.AutoModerationRuleID) + + result := new(AutoModerationRule) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateAutoModerationRule request to Discord and returns a AutoModerationRule. +func (r *CreateAutoModerationRule) Send(bot *Client) (*AutoModerationRule, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[29]("29", "45892a5d"+r.GuildID) + endpoint := EndpointCreateAutoModerationRule(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(AutoModerationRule) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyAutoModerationRule request to Discord and returns a AutoModerationRule. +func (r *ModifyAutoModerationRule) Send(bot *Client) (*AutoModerationRule, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[30]("30", "45892a5d"+r.GuildID, "1b7efe5d"+r.AutoModerationRuleID) + endpoint := EndpointModifyAutoModerationRule(r.GuildID, r.AutoModerationRuleID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(AutoModerationRule) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteAutoModerationRule request to Discord and returns a error. +func (r *DeleteAutoModerationRule) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[31]("31", "45892a5d"+r.GuildID, "1b7efe5d"+r.AutoModerationRuleID) + endpoint := EndpointDeleteAutoModerationRule(r.GuildID, r.AutoModerationRuleID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetChannel request to Discord and returns a Channel. +func (r *GetChannel) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[32]("32", "e5416649"+r.ChannelID) + endpoint := EndpointGetChannel(r.ChannelID) + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyChannel request to Discord and returns a Channel. +func (r *ModifyChannel) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[33]("33", "e5416649"+r.ChannelID) + endpoint := EndpointModifyChannel(r.ChannelID) + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyChannelGroupDM request to Discord and returns a Channel. +func (r *ModifyChannelGroupDM) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[34]("34", "e5416649"+r.ChannelID) + endpoint := EndpointModifyChannelGroupDM(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyChannelGuild request to Discord and returns a Channel. +func (r *ModifyChannelGuild) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[35]("35", "e5416649"+r.ChannelID) + endpoint := EndpointModifyChannelGuild(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyChannelThread request to Discord and returns a Channel. +func (r *ModifyChannelThread) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[36]("36", "e5416649"+r.ChannelID) + endpoint := EndpointModifyChannelThread(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteCloseChannel request to Discord and returns a Channel. +func (r *DeleteCloseChannel) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[37]("37", "e5416649"+r.ChannelID) + endpoint := EndpointDeleteCloseChannel(r.ChannelID) + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetChannelMessages request to Discord and returns a []*Message. +func (r *GetChannelMessages) Send(bot *Client) ([]*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[38]("38", "e5416649"+r.ChannelID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetChannelMessages(r.ChannelID) + "?" + query + + result := make([]*Message, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetChannelMessage request to Discord and returns a Message. +func (r *GetChannelMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[39]("39", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointGetChannelMessage(r.ChannelID, r.MessageID) + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateMessage request to Discord and returns a Message. +func (r *CreateMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[40]("40", "e5416649"+r.ChannelID) + endpoint := EndpointCreateMessage(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CrosspostMessage request to Discord and returns a Message. +func (r *CrosspostMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[41]("41", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointCrosspostMessage(r.ChannelID, r.MessageID) + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateReaction request to Discord and returns a error. +func (r *CreateReaction) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[42]("42", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID, "033ebcdd"+r.Emoji) + endpoint := EndpointCreateReaction(r.ChannelID, r.MessageID, r.Emoji) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a DeleteOwnReaction request to Discord and returns a error. +func (r *DeleteOwnReaction) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[43]("43", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID, "033ebcdd"+r.Emoji) + endpoint := EndpointDeleteOwnReaction(r.ChannelID, r.MessageID, r.Emoji) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a DeleteUserReaction request to Discord and returns a error. +func (r *DeleteUserReaction) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[44]("44", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID, "033ebcdd"+r.Emoji, "209c92df"+r.UserID) + endpoint := EndpointDeleteUserReaction(r.ChannelID, r.MessageID, r.Emoji, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetReactions request to Discord and returns a []*User. +func (r *GetReactions) Send(bot *Client) ([]*User, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[45]("45", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID, "033ebcdd"+r.Emoji) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetReactions(r.ChannelID, r.MessageID, r.Emoji) + "?" + query + + result := make([]*User, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteAllReactions request to Discord and returns a error. +func (r *DeleteAllReactions) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[46]("46", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointDeleteAllReactions(r.ChannelID, r.MessageID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a DeleteAllReactionsforEmoji request to Discord and returns a error. +func (r *DeleteAllReactionsforEmoji) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[47]("47", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID, "033ebcdd"+r.Emoji) + endpoint := EndpointDeleteAllReactionsforEmoji(r.ChannelID, r.MessageID, r.Emoji) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a EditMessage request to Discord and returns a Message. +func (r *EditMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[48]("48", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointEditMessage(r.ChannelID, r.MessageID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteMessage request to Discord and returns a error. +func (r *DeleteMessage) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[49]("49", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointDeleteMessage(r.ChannelID, r.MessageID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a BulkDeleteMessages request to Discord and returns a error. +func (r *BulkDeleteMessages) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[50]("50", "e5416649"+r.ChannelID) + endpoint := EndpointBulkDeleteMessages(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a EditChannelPermissions request to Discord and returns a error. +func (r *EditChannelPermissions) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[51]("51", "e5416649"+r.ChannelID, "9167175f"+r.OverwriteID) + endpoint := EndpointEditChannelPermissions(r.ChannelID, r.OverwriteID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetChannelInvites request to Discord and returns a []*Invite. +func (r *GetChannelInvites) Send(bot *Client) ([]*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[52]("52", "e5416649"+r.ChannelID) + endpoint := EndpointGetChannelInvites(r.ChannelID) + + result := make([]*Invite, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateChannelInvite request to Discord and returns a Invite. +func (r *CreateChannelInvite) Send(bot *Client) (*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[53]("53", "e5416649"+r.ChannelID) + endpoint := EndpointCreateChannelInvite(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Invite) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteChannelPermission request to Discord and returns a error. +func (r *DeleteChannelPermission) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[54]("54", "e5416649"+r.ChannelID, "9167175f"+r.OverwriteID) + endpoint := EndpointDeleteChannelPermission(r.ChannelID, r.OverwriteID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a FollowAnnouncementChannel request to Discord and returns a FollowedChannel. +func (r *FollowAnnouncementChannel) Send(bot *Client) (*FollowedChannel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[55]("55", "e5416649"+r.ChannelID) + endpoint := EndpointFollowAnnouncementChannel(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(FollowedChannel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a TriggerTypingIndicator request to Discord and returns a error. +func (r *TriggerTypingIndicator) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[56]("56", "e5416649"+r.ChannelID) + endpoint := EndpointTriggerTypingIndicator(r.ChannelID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetPinnedMessages request to Discord and returns a []*Message. +func (r *GetPinnedMessages) Send(bot *Client) ([]*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[57]("57", "e5416649"+r.ChannelID) + endpoint := EndpointGetPinnedMessages(r.ChannelID) + + result := make([]*Message, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a PinMessage request to Discord and returns a error. +func (r *PinMessage) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[58]("58", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointPinMessage(r.ChannelID, r.MessageID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a UnpinMessage request to Discord and returns a error. +func (r *UnpinMessage) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[59]("59", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointUnpinMessage(r.ChannelID, r.MessageID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GroupDMAddRecipient request to Discord and returns a error. +func (r *GroupDMAddRecipient) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[60]("60", "e5416649"+r.ChannelID, "209c92df"+r.UserID) + endpoint := EndpointGroupDMAddRecipient(r.ChannelID, r.UserID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GroupDMRemoveRecipient request to Discord and returns a error. +func (r *GroupDMRemoveRecipient) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[61]("61", "e5416649"+r.ChannelID, "209c92df"+r.UserID) + endpoint := EndpointGroupDMRemoveRecipient(r.ChannelID, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a StartThreadfromMessage request to Discord and returns a Channel. +func (r *StartThreadfromMessage) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[62]("62", "e5416649"+r.ChannelID, "d57d6589"+r.MessageID) + endpoint := EndpointStartThreadfromMessage(r.ChannelID, r.MessageID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a StartThreadwithoutMessage request to Discord and returns a Channel. +func (r *StartThreadwithoutMessage) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[63]("63", "e5416649"+r.ChannelID) + endpoint := EndpointStartThreadwithoutMessage(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a StartThreadinForumChannel request to Discord and returns a Channel. +func (r *StartThreadinForumChannel) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[64]("64", "e5416649"+r.ChannelID) + endpoint := EndpointStartThreadinForumChannel(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a JoinThread request to Discord and returns a error. +func (r *JoinThread) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[65]("65", "e5416649"+r.ChannelID) + endpoint := EndpointJoinThread(r.ChannelID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a AddThreadMember request to Discord and returns a error. +func (r *AddThreadMember) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[66]("66", "e5416649"+r.ChannelID, "209c92df"+r.UserID) + endpoint := EndpointAddThreadMember(r.ChannelID, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a LeaveThread request to Discord and returns a error. +func (r *LeaveThread) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[67]("67", "e5416649"+r.ChannelID) + endpoint := EndpointLeaveThread(r.ChannelID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a RemoveThreadMember request to Discord and returns a error. +func (r *RemoveThreadMember) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[68]("68", "e5416649"+r.ChannelID, "209c92df"+r.UserID) + endpoint := EndpointRemoveThreadMember(r.ChannelID, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetThreadMember request to Discord and returns a ThreadMember. +func (r *GetThreadMember) Send(bot *Client) (*ThreadMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[69]("69", "e5416649"+r.ChannelID, "209c92df"+r.UserID) + endpoint := EndpointGetThreadMember(r.ChannelID, r.UserID) + + result := new(ThreadMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListThreadMembers request to Discord and returns a []*ThreadMember. +func (r *ListThreadMembers) Send(bot *Client) ([]*ThreadMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[70]("70", "e5416649"+r.ChannelID) + endpoint := EndpointListThreadMembers(r.ChannelID) + + result := make([]*ThreadMember, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListPublicArchivedThreads request to Discord and returns a ListPublicArchivedThreadsResponse. +func (r *ListPublicArchivedThreads) Send(bot *Client) (*ListPublicArchivedThreadsResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[71]("71", "e5416649"+r.ChannelID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointListPublicArchivedThreads(r.ChannelID) + "?" + query + + result := new(ListPublicArchivedThreadsResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListPrivateArchivedThreads request to Discord and returns a ListPrivateArchivedThreadsResponse. +func (r *ListPrivateArchivedThreads) Send(bot *Client) (*ListPrivateArchivedThreadsResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[72]("72", "e5416649"+r.ChannelID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointListPrivateArchivedThreads(r.ChannelID) + "?" + query + + result := new(ListPrivateArchivedThreadsResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListJoinedPrivateArchivedThreads request to Discord and returns a ListJoinedPrivateArchivedThreadsResponse. +func (r *ListJoinedPrivateArchivedThreads) Send(bot *Client) (*ListJoinedPrivateArchivedThreadsResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[73]("73", "e5416649"+r.ChannelID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointListJoinedPrivateArchivedThreads(r.ChannelID) + "?" + query + + result := new(ListJoinedPrivateArchivedThreadsResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListGuildEmojis request to Discord and returns a []*Emoji. +func (r *ListGuildEmojis) Send(bot *Client) ([]*Emoji, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[74]("74", "45892a5d"+r.GuildID) + endpoint := EndpointListGuildEmojis(r.GuildID) + + result := make([]*Emoji, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildEmoji request to Discord and returns a Emoji. +func (r *GetGuildEmoji) Send(bot *Client) (*Emoji, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[75]("75", "45892a5d"+r.GuildID, "67c175a8"+r.EmojiID) + endpoint := EndpointGetGuildEmoji(r.GuildID, r.EmojiID) + + result := new(Emoji) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildEmoji request to Discord and returns a Emoji. +func (r *CreateGuildEmoji) Send(bot *Client) (*Emoji, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[76]("76", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildEmoji(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Emoji) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildEmoji request to Discord and returns a Emoji. +func (r *ModifyGuildEmoji) Send(bot *Client) (*Emoji, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[77]("77", "45892a5d"+r.GuildID, "67c175a8"+r.EmojiID) + endpoint := EndpointModifyGuildEmoji(r.GuildID, r.EmojiID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Emoji) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildEmoji request to Discord and returns a error. +func (r *DeleteGuildEmoji) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[78]("78", "45892a5d"+r.GuildID, "67c175a8"+r.EmojiID) + endpoint := EndpointDeleteGuildEmoji(r.GuildID, r.EmojiID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a CreateGuild request to Discord and returns a Guild. +func (r *CreateGuild) Send(bot *Client) (*Guild, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[79]("79") + endpoint := EndpointCreateGuild() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Guild) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuild request to Discord and returns a Guild. +func (r *GetGuild) Send(bot *Client) (*Guild, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[80]("80", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuild(r.GuildID) + "?" + query + + result := new(Guild) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildPreview request to Discord and returns a GuildPreview. +func (r *GetGuildPreview) Send(bot *Client) (*GuildPreview, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[81]("81", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildPreview(r.GuildID) + + result := new(GuildPreview) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuild request to Discord and returns a Guild. +func (r *ModifyGuild) Send(bot *Client) (*Guild, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[82]("82", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuild(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Guild) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuild request to Discord and returns a error. +func (r *DeleteGuild) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[83]("83", "45892a5d"+r.GuildID) + endpoint := EndpointDeleteGuild(r.GuildID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildChannels request to Discord and returns a []*Channel. +func (r *GetGuildChannels) Send(bot *Client) ([]*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[84]("84", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildChannels(r.GuildID) + + result := make([]*Channel, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildChannel request to Discord and returns a Channel. +func (r *CreateGuildChannel) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[85]("85", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildChannel(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildChannelPositions request to Discord and returns a error. +func (r *ModifyGuildChannelPositions) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[86]("86", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuildChannelPositions(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ListActiveGuildThreads request to Discord and returns a ListActiveGuildThreadsResponse. +func (r *ListActiveGuildThreads) Send(bot *Client) (*ListActiveGuildThreadsResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[87]("87", "45892a5d"+r.GuildID) + endpoint := EndpointListActiveGuildThreads(r.GuildID) + + result := new(ListActiveGuildThreadsResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildMember request to Discord and returns a GuildMember. +func (r *GetGuildMember) Send(bot *Client) (*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[88]("88", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointGetGuildMember(r.GuildID, r.UserID) + + result := new(GuildMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListGuildMembers request to Discord and returns a []*GuildMember. +func (r *ListGuildMembers) Send(bot *Client) ([]*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[89]("89", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointListGuildMembers(r.GuildID) + "?" + query + + result := make([]*GuildMember, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a SearchGuildMembers request to Discord and returns a []*GuildMember. +func (r *SearchGuildMembers) Send(bot *Client) ([]*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[90]("90", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointSearchGuildMembers(r.GuildID) + "?" + query + + result := make([]*GuildMember, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a AddGuildMember request to Discord and returns a GuildMember. +func (r *AddGuildMember) Send(bot *Client) (*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[91]("91", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointAddGuildMember(r.GuildID, r.UserID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildMember request to Discord and returns a GuildMember. +func (r *ModifyGuildMember) Send(bot *Client) (*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[92]("92", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointModifyGuildMember(r.GuildID, r.UserID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyCurrentMember request to Discord and returns a GuildMember. +func (r *ModifyCurrentMember) Send(bot *Client) (*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[93]("93", "45892a5d"+r.GuildID) + endpoint := EndpointModifyCurrentMember(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a AddGuildMemberRole request to Discord and returns a error. +func (r *AddGuildMemberRole) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[94]("94", "45892a5d"+r.GuildID, "209c92df"+r.UserID, "3cf7dd7c"+r.RoleID) + endpoint := EndpointAddGuildMemberRole(r.GuildID, r.UserID, r.RoleID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a RemoveGuildMemberRole request to Discord and returns a error. +func (r *RemoveGuildMemberRole) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[95]("95", "45892a5d"+r.GuildID, "209c92df"+r.UserID, "3cf7dd7c"+r.RoleID) + endpoint := EndpointRemoveGuildMemberRole(r.GuildID, r.UserID, r.RoleID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a RemoveGuildMember request to Discord and returns a error. +func (r *RemoveGuildMember) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[96]("96", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointRemoveGuildMember(r.GuildID, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildBans request to Discord and returns a []*Ban. +func (r *GetGuildBans) Send(bot *Client) ([]*Ban, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[97]("97", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildBans(r.GuildID) + "?" + query + + result := make([]*Ban, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildBan request to Discord and returns a Ban. +func (r *GetGuildBan) Send(bot *Client) (*Ban, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[98]("98", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointGetGuildBan(r.GuildID, r.UserID) + + result := new(Ban) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildBan request to Discord and returns a error. +func (r *CreateGuildBan) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[99]("99", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointCreateGuildBan(r.GuildID, r.UserID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a RemoveGuildBan request to Discord and returns a error. +func (r *RemoveGuildBan) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[100]("100", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointRemoveGuildBan(r.GuildID, r.UserID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildRoles request to Discord and returns a []*Role. +func (r *GetGuildRoles) Send(bot *Client) ([]*Role, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[101]("101", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildRoles(r.GuildID) + + result := make([]*Role, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildRole request to Discord and returns a Role. +func (r *CreateGuildRole) Send(bot *Client) (*Role, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[102]("102", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildRole(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Role) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildRolePositions request to Discord and returns a []*Role. +func (r *ModifyGuildRolePositions) Send(bot *Client) ([]*Role, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[103]("103", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuildRolePositions(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := make([]*Role, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildRole request to Discord and returns a Role. +func (r *ModifyGuildRole) Send(bot *Client) (*Role, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[104]("104", "45892a5d"+r.GuildID, "3cf7dd7c"+r.RoleID) + endpoint := EndpointModifyGuildRole(r.GuildID, r.RoleID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Role) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildRole request to Discord and returns a error. +func (r *DeleteGuildRole) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[105]("105", "45892a5d"+r.GuildID, "3cf7dd7c"+r.RoleID) + endpoint := EndpointDeleteGuildRole(r.GuildID, r.RoleID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ModifyGuildMFALevel request to Discord and returns a ModifyGuildMFALevelResponse. +func (r *ModifyGuildMFALevel) Send(bot *Client) (*ModifyGuildMFALevelResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[106]("106", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuildMFALevel(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(ModifyGuildMFALevelResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildPruneCount request to Discord and returns a GetGuildPruneCountResponse. +func (r *GetGuildPruneCount) Send(bot *Client) (*GetGuildPruneCountResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[107]("107", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildPruneCount(r.GuildID) + "?" + query + + result := new(GetGuildPruneCountResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a BeginGuildPrune request to Discord and returns a error. +func (r *BeginGuildPrune) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[108]("108", "45892a5d"+r.GuildID) + endpoint := EndpointBeginGuildPrune(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildVoiceRegions request to Discord and returns a []*VoiceRegion. +func (r *GetGuildVoiceRegions) Send(bot *Client) ([]*VoiceRegion, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[109]("109", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildVoiceRegions(r.GuildID) + + result := make([]*VoiceRegion, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildInvites request to Discord and returns a []*Invite. +func (r *GetGuildInvites) Send(bot *Client) ([]*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[110]("110", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildInvites(r.GuildID) + + result := make([]*Invite, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildIntegrations request to Discord and returns a []*Integration. +func (r *GetGuildIntegrations) Send(bot *Client) ([]*Integration, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[111]("111", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildIntegrations(r.GuildID) + + result := make([]*Integration, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildIntegration request to Discord and returns a error. +func (r *DeleteGuildIntegration) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[112]("112", "45892a5d"+r.GuildID, "cb4479f8"+r.IntegrationID) + endpoint := EndpointDeleteGuildIntegration(r.GuildID, r.IntegrationID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildWidgetSettings request to Discord and returns a GuildWidget. +func (r *GetGuildWidgetSettings) Send(bot *Client) (*GuildWidget, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[113]("113", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildWidgetSettings(r.GuildID) + + result := new(GuildWidget) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildWidget request to Discord and returns a GuildWidget. +func (r *ModifyGuildWidget) Send(bot *Client) (*GuildWidget, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[114]("114", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuildWidget(r.GuildID) + + result := new(GuildWidget) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildWidget request to Discord and returns a GuildWidget. +func (r *GetGuildWidget) Send(bot *Client) (*GuildWidget, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[115]("115", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildWidget(r.GuildID) + + result := new(GuildWidget) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildVanityURL request to Discord and returns a Invite. +func (r *GetGuildVanityURL) Send(bot *Client) (*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[116]("116", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildVanityURL(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Invite) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildWidgetImage request to Discord and returns a EmbedImage. +func (r *GetGuildWidgetImage) Send(bot *Client) (*EmbedImage, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[117]("117", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildWidgetImage(r.GuildID) + "?" + query + + result := new(EmbedImage) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildWelcomeScreen request to Discord and returns a WelcomeScreen. +func (r *GetGuildWelcomeScreen) Send(bot *Client) (*WelcomeScreen, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[118]("118", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildWelcomeScreen(r.GuildID) + + result := new(WelcomeScreen) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildWelcomeScreen request to Discord and returns a WelcomeScreen. +func (r *ModifyGuildWelcomeScreen) Send(bot *Client) (*WelcomeScreen, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[119]("119", "45892a5d"+r.GuildID) + endpoint := EndpointModifyGuildWelcomeScreen(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(WelcomeScreen) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyCurrentUserVoiceState request to Discord and returns a error. +func (r *ModifyCurrentUserVoiceState) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[120]("120", "45892a5d"+r.GuildID) + endpoint := EndpointModifyCurrentUserVoiceState(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ModifyUserVoiceState request to Discord and returns a error. +func (r *ModifyUserVoiceState) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[121]("121", "45892a5d"+r.GuildID, "209c92df"+r.UserID) + endpoint := EndpointModifyUserVoiceState(r.GuildID, r.UserID) + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ListScheduledEventsforGuild request to Discord and returns a []*GuildScheduledEvent. +func (r *ListScheduledEventsforGuild) Send(bot *Client) ([]*GuildScheduledEvent, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[122]("122", "45892a5d"+r.GuildID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointListScheduledEventsforGuild(r.GuildID) + "?" + query + + result := make([]*GuildScheduledEvent, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildScheduledEvent request to Discord and returns a GuildScheduledEvent. +func (r *CreateGuildScheduledEvent) Send(bot *Client) (*GuildScheduledEvent, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[123]("123", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildScheduledEvent(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildScheduledEvent) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildScheduledEvent request to Discord and returns a GuildScheduledEvent. +func (r *GetGuildScheduledEvent) Send(bot *Client) (*GuildScheduledEvent, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[124]("124", "45892a5d"+r.GuildID, "522412fc"+r.GuildScheduledEventID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildScheduledEvent(r.GuildID, r.GuildScheduledEventID) + "?" + query + + result := new(GuildScheduledEvent) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildScheduledEvent request to Discord and returns a GuildScheduledEvent. +func (r *ModifyGuildScheduledEvent) Send(bot *Client) (*GuildScheduledEvent, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[125]("125", "45892a5d"+r.GuildID, "522412fc"+r.GuildScheduledEventID) + endpoint := EndpointModifyGuildScheduledEvent(r.GuildID, r.GuildScheduledEventID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildScheduledEvent) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildScheduledEvent request to Discord and returns a error. +func (r *DeleteGuildScheduledEvent) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[126]("126", "45892a5d"+r.GuildID, "522412fc"+r.GuildScheduledEventID) + endpoint := EndpointDeleteGuildScheduledEvent(r.GuildID, r.GuildScheduledEventID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGuildScheduledEventUsers request to Discord and returns a []*GuildScheduledEventUser. +func (r *GetGuildScheduledEventUsers) Send(bot *Client) ([]*GuildScheduledEventUser, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[127]("127", "45892a5d"+r.GuildID, "522412fc"+r.GuildScheduledEventID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetGuildScheduledEventUsers(r.GuildID, r.GuildScheduledEventID) + "?" + query + + result := make([]*GuildScheduledEventUser, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildTemplate request to Discord and returns a GuildTemplate. +func (r *GetGuildTemplate) Send(bot *Client) (*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[128]("128", "61437152"+r.TemplateCode) + endpoint := EndpointGetGuildTemplate(r.TemplateCode) + + result := new(GuildTemplate) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildfromGuildTemplate request to Discord and returns a []*GuildTemplate. +func (r *CreateGuildfromGuildTemplate) Send(bot *Client) ([]*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[129]("129", "61437152"+r.TemplateCode) + endpoint := EndpointCreateGuildfromGuildTemplate(r.TemplateCode) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := make([]*GuildTemplate, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildTemplates request to Discord and returns a []*GuildTemplate. +func (r *GetGuildTemplates) Send(bot *Client) ([]*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[130]("130", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildTemplates(r.GuildID) + + result := make([]*GuildTemplate, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildTemplate request to Discord and returns a GuildTemplate. +func (r *CreateGuildTemplate) Send(bot *Client) (*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[131]("131", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildTemplate(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildTemplate) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a SyncGuildTemplate request to Discord and returns a GuildTemplate. +func (r *SyncGuildTemplate) Send(bot *Client) (*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[132]("132", "45892a5d"+r.GuildID, "61437152"+r.TemplateCode) + endpoint := EndpointSyncGuildTemplate(r.GuildID, r.TemplateCode) + + result := new(GuildTemplate) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPut, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildTemplate request to Discord and returns a GuildTemplate. +func (r *ModifyGuildTemplate) Send(bot *Client) (*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[133]("133", "45892a5d"+r.GuildID, "61437152"+r.TemplateCode) + endpoint := EndpointModifyGuildTemplate(r.GuildID, r.TemplateCode) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(GuildTemplate) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildTemplate request to Discord and returns a GuildTemplate. +func (r *DeleteGuildTemplate) Send(bot *Client) (*GuildTemplate, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[134]("134", "45892a5d"+r.GuildID, "61437152"+r.TemplateCode) + endpoint := EndpointDeleteGuildTemplate(r.GuildID, r.TemplateCode) + + result := new(GuildTemplate) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetInvite request to Discord and returns a Invite. +func (r *GetInvite) Send(bot *Client) (*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[135]("135", "781d4865"+r.InviteCode) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetInvite(r.InviteCode) + "?" + query + + result := new(Invite) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteInvite request to Discord and returns a Invite. +func (r *DeleteInvite) Send(bot *Client) (*Invite, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[136]("136", "781d4865"+r.InviteCode) + endpoint := EndpointDeleteInvite(r.InviteCode) + + result := new(Invite) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateStageInstance request to Discord and returns a StageInstance. +func (r *CreateStageInstance) Send(bot *Client) (*StageInstance, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[137]("137") + endpoint := EndpointCreateStageInstance() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(StageInstance) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetStageInstance request to Discord and returns a StageInstance. +func (r *GetStageInstance) Send(bot *Client) (*StageInstance, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[138]("138", "e5416649"+r.ChannelID) + endpoint := EndpointGetStageInstance(r.ChannelID) + + result := new(StageInstance) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyStageInstance request to Discord and returns a StageInstance. +func (r *ModifyStageInstance) Send(bot *Client) (*StageInstance, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[139]("139", "e5416649"+r.ChannelID) + endpoint := EndpointModifyStageInstance(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(StageInstance) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteStageInstance request to Discord and returns a error. +func (r *DeleteStageInstance) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[140]("140", "e5416649"+r.ChannelID) + endpoint := EndpointDeleteStageInstance(r.ChannelID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetSticker request to Discord and returns a Sticker. +func (r *GetSticker) Send(bot *Client) (*Sticker, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[141]("141", "6eeeabf1"+r.StickerID) + endpoint := EndpointGetSticker(r.StickerID) + + result := new(Sticker) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListNitroStickerPacks request to Discord and returns a ListNitroStickerPacksResponse. +func (r *ListNitroStickerPacks) Send(bot *Client) (*ListNitroStickerPacksResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[142]("142") + endpoint := EndpointListNitroStickerPacks() + + result := new(ListNitroStickerPacksResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListGuildStickers request to Discord and returns a []*Sticker. +func (r *ListGuildStickers) Send(bot *Client) ([]*Sticker, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[143]("143", "45892a5d"+r.GuildID) + endpoint := EndpointListGuildStickers(r.GuildID) + + result := make([]*Sticker, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildSticker request to Discord and returns a Sticker. +func (r *GetGuildSticker) Send(bot *Client) (*Sticker, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[144]("144", "45892a5d"+r.GuildID, "6eeeabf1"+r.StickerID) + endpoint := EndpointGetGuildSticker(r.GuildID, r.StickerID) + + result := new(Sticker) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGuildSticker request to Discord and returns a Sticker. +func (r *CreateGuildSticker) Send(bot *Client) (*Sticker, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[145]("145", "45892a5d"+r.GuildID) + endpoint := EndpointCreateGuildSticker(r.GuildID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + var contentType []byte + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, &r.File); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + + result := new(Sticker) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyGuildSticker request to Discord and returns a Sticker. +func (r *ModifyGuildSticker) Send(bot *Client) (*Sticker, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[146]("146", "45892a5d"+r.GuildID, "6eeeabf1"+r.StickerID) + endpoint := EndpointModifyGuildSticker(r.GuildID, r.StickerID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Sticker) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteGuildSticker request to Discord and returns a error. +func (r *DeleteGuildSticker) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[147]("147", "45892a5d"+r.GuildID, "6eeeabf1"+r.StickerID) + endpoint := EndpointDeleteGuildSticker(r.GuildID, r.StickerID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetCurrentUser request to Discord and returns a User. +func (r *GetCurrentUser) Send(bot *Client) (*User, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[148]("148") + endpoint := EndpointGetCurrentUser() + + result := new(User) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetUser request to Discord and returns a User. +func (r *GetUser) Send(bot *Client) (*User, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[149]("149", "209c92df"+r.UserID) + endpoint := EndpointGetUser(r.UserID) + + result := new(User) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyCurrentUser request to Discord and returns a User. +func (r *ModifyCurrentUser) Send(bot *Client) (*User, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[150]("150") + endpoint := EndpointModifyCurrentUser() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(User) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetCurrentUserGuilds request to Discord and returns a []*Guild. +func (r *GetCurrentUserGuilds) Send(bot *Client) ([]*Guild, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[151]("151") + endpoint := EndpointGetCurrentUserGuilds() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := make([]*Guild, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeJSON, body, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetCurrentUserGuildMember request to Discord and returns a GuildMember. +func (r *GetCurrentUserGuildMember) Send(bot *Client) (*GuildMember, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[152]("152", "45892a5d"+r.GuildID) + endpoint := EndpointGetCurrentUserGuildMember(r.GuildID) + + result := new(GuildMember) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a LeaveGuild request to Discord and returns a error. +func (r *LeaveGuild) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[153]("153", "45892a5d"+r.GuildID) + endpoint := EndpointLeaveGuild(r.GuildID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a CreateDM request to Discord and returns a Channel. +func (r *CreateDM) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[154]("154") + endpoint := EndpointCreateDM() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateGroupDM request to Discord and returns a Channel. +func (r *CreateGroupDM) Send(bot *Client) (*Channel, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[155]("155") + endpoint := EndpointCreateGroupDM() + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Channel) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetUserConnections request to Discord and returns a []*Connection. +func (r *GetUserConnections) Send(bot *Client) ([]*Connection, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[156]("156") + endpoint := EndpointGetUserConnections() + + result := make([]*Connection, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ListVoiceRegions request to Discord and returns a []*VoiceRegion. +func (r *ListVoiceRegions) Send(bot *Client) ([]*VoiceRegion, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[157]("157") + endpoint := EndpointListVoiceRegions() + + result := make([]*VoiceRegion, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a CreateWebhook request to Discord and returns a Webhook. +func (r *CreateWebhook) Send(bot *Client) (*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[158]("158", "e5416649"+r.ChannelID) + endpoint := EndpointCreateWebhook(r.ChannelID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Webhook) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetChannelWebhooks request to Discord and returns a []*Webhook. +func (r *GetChannelWebhooks) Send(bot *Client) ([]*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[159]("159", "e5416649"+r.ChannelID) + endpoint := EndpointGetChannelWebhooks(r.ChannelID) + + result := make([]*Webhook, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGuildWebhooks request to Discord and returns a []*Webhook. +func (r *GetGuildWebhooks) Send(bot *Client) ([]*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[160]("160", "45892a5d"+r.GuildID) + endpoint := EndpointGetGuildWebhooks(r.GuildID) + + result := make([]*Webhook, 0) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, &result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetWebhook request to Discord and returns a Webhook. +func (r *GetWebhook) Send(bot *Client) (*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[161]("161", "6d62b21b"+r.WebhookID) + endpoint := EndpointGetWebhook(r.WebhookID) + + result := new(Webhook) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetWebhookwithToken request to Discord and returns a Webhook. +func (r *GetWebhookwithToken) Send(bot *Client) (*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[162]("162", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + endpoint := EndpointGetWebhookwithToken(r.WebhookID, r.WebhookToken) + + result := new(Webhook) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyWebhook request to Discord and returns a Webhook. +func (r *ModifyWebhook) Send(bot *Client) (*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[163]("163", "6d62b21b"+r.WebhookID) + endpoint := EndpointModifyWebhook(r.WebhookID) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Webhook) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a ModifyWebhookwithToken request to Discord and returns a Webhook. +func (r *ModifyWebhookwithToken) Send(bot *Client) (*Webhook, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[164]("164", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + endpoint := EndpointModifyWebhookwithToken(r.WebhookID, r.WebhookToken) + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + result := new(Webhook) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, ContentTypeJSON, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteWebhook request to Discord and returns a error. +func (r *DeleteWebhook) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[165]("165", "6d62b21b"+r.WebhookID) + endpoint := EndpointDeleteWebhook(r.WebhookID) + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a DeleteWebhookwithToken request to Discord and returns a error. +func (r *DeleteWebhookwithToken) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[166]("166", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + endpoint := EndpointDeleteWebhookwithToken(r.WebhookID, r.WebhookToken) -// Package disgo provides an API for Discord. -package disgo + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, nil, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ExecuteWebhook request to Discord and returns a error. +func (r *ExecuteWebhook) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[167]("167", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + query, err := EndpointQueryString(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointExecuteWebhook(r.WebhookID, r.WebhookToken) + "?" + query + + body, err := json.Marshal(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, contentType, body, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ExecuteSlackCompatibleWebhook request to Discord and returns a error. +func (r *ExecuteSlackCompatibleWebhook) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[168]("168", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + query, err := EndpointQueryString(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointExecuteSlackCompatibleWebhook(r.WebhookID, r.WebhookToken) + "?" + query + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a ExecuteGitHubCompatibleWebhook request to Discord and returns a error. +func (r *ExecuteGitHubCompatibleWebhook) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[169]("169", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken) + query, err := EndpointQueryString(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointExecuteGitHubCompatibleWebhook(r.WebhookID, r.WebhookToken) + "?" + query + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPost, endpoint, ContentTypeURLQueryString, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetWebhookMessage request to Discord and returns a Message. +func (r *GetWebhookMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[170]("170", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken, "d57d6589"+r.MessageID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointGetWebhookMessage(r.WebhookID, r.WebhookToken, r.MessageID) + "?" + query + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, ContentTypeURLQueryString, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a EditWebhookMessage request to Discord and returns a Message. +func (r *EditWebhookMessage) Send(bot *Client) (*Message, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[171]("171", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken, "d57d6589"+r.MessageID) + query, err := EndpointQueryString(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointEditWebhookMessage(r.WebhookID, r.WebhookToken, r.MessageID) + "?" + query + + body, err := json.Marshal(r) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: fmt.Errorf(errSendMarshal, err), + } + } + + contentType := ContentTypeJSON + if len(r.Files) != 0 { + var multipartErr error + if contentType, body, multipartErr = createMultipartForm(body, r.Files...); multipartErr != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + } + + result := new(Message) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodPatch, endpoint, contentType, body, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a DeleteWebhookMessage request to Discord and returns a error. +func (r *DeleteWebhookMessage) Send(bot *Client) error { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[172]("172", "6d62b21b"+r.WebhookID, "8954ac33"+r.WebhookToken, "d57d6589"+r.MessageID) + query, err := EndpointQueryString(r) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: "", + Err: err, + } + } + endpoint := EndpointDeleteWebhookMessage(r.WebhookID, r.WebhookToken, r.MessageID) + "?" + query + + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodDelete, endpoint, ContentTypeURLQueryString, nil, nil) + if err != nil { + return ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return nil +} + +// Send sends a GetGateway request to Discord and returns a GetGatewayBotResponse. +func (r *GetGateway) Send(bot *Client) (*GetGatewayBotResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[173]("173") + endpoint := EndpointGetGateway() + + result := new(GetGatewayBotResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetGatewayBot request to Discord and returns a GetGatewayBotResponse. +func (r *GetGatewayBot) Send(bot *Client) (*GetGatewayBotResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[174]("174") + endpoint := EndpointGetGatewayBot() + + result := new(GetGatewayBotResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetCurrentBotApplicationInformation request to Discord and returns a Application. +func (r *GetCurrentBotApplicationInformation) Send(bot *Client) (*Application, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[175]("175") + endpoint := EndpointGetCurrentBotApplicationInformation() + + result := new(Application) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +// Send sends a GetCurrentAuthorizationInformation request to Discord and returns a CurrentAuthorizationInformationResponse. +func (r *GetCurrentAuthorizationInformation) Send(bot *Client) (*CurrentAuthorizationInformationResponse, error) { + var err error + xid := xid.New().String() + routeid, resourceid := RateLimitHashFuncs[176]("176") + endpoint := EndpointGetCurrentAuthorizationInformation() + + result := new(CurrentAuthorizationInformationResponse) + err = SendRequest(bot, xid, routeid, resourceid, fasthttp.MethodGet, endpoint, nil, nil, result) + if err != nil { + return nil, ErrorRequest{ + ClientID: bot.ApplicationID, + CorrelationID: xid, + RouteID: routeid, + ResourceID: resourceid, + Endpoint: endpoint, + Err: err, + } + } + + return result, nil +} + +const ( + gatewayEndpointParams = "?v=" + VersionDiscordAPI + "&encoding=json" + invalidSessionWaitTime = 1 * time.Second + maxIdentifyLargeThreshold = 250 +) + +// Session represents a Discord Gateway WebSocket Session. +type Session struct { + // Context carries request-scoped data for the Discord Gateway Connection. + // + // Context is also used as a signal for the Session's goroutines. + Context context.Context + + // manager represents a manager of a Session's goroutines. + manager *manager + + // Conn represents a connection to the Discord Gateway. + Conn *websocket.Conn + + // heartbeat contains the fields required to implement the heartbeat mechanism. + heartbeat *heartbeat + + // Endpoint represents the endpoint that is used to reconnect to the Gateway. + Endpoint string + + // ID represents the session ID of the Session. + ID string + + // Seq represents the last sequence number received by the client. + // + // https://discord.com/developers/docs/topics/gateway#heartbeat + Seq int64 + + // RWMutex is used to protect the Session's variables from data races + // by providing transactional functionality. + sync.RWMutex +} + +// isConnected returns whether the session is connected. +func (s *Session) isConnected() bool { + if s.Context == nil { + return false + } + + select { + case <-s.Context.Done(): + return false + default: + return true + } +} + +// canReconnect determines whether the session is in a valid state to reconnect. +func (s *Session) canReconnect() bool { + return s.ID != "" && s.Endpoint != "" && atomic.LoadInt64(&s.Seq) != 0 +} + +// Connect connects a session to the Discord Gateway (WebSocket Connection). +func (s *Session) Connect(bot *Client) error { + s.Lock() + defer s.Unlock() + + LogSession(Logger.Info(), s.ID).Str(LogCtxClient, bot.ApplicationID).Msg("connecting session") + + return s.connect(bot) +} + +// connect connects a session to a WebSocket Connection. +func (s *Session) connect(bot *Client) error { + if s.isConnected() { + return fmt.Errorf("session %q is already connected", s.ID) + } + + // request a valid Gateway URL endpoint from the Discord API. + gatewayEndpoint := s.Endpoint + if gatewayEndpoint == "" || !s.canReconnect() { + gateway := GetGateway{} + response, err := gateway.Send(bot) + if err != nil { + return fmt.Errorf("error getting the Gateway API Endpoint: %w", err) + } + + gatewayEndpoint = response.URL + gatewayEndpointParams + + // set the maximum allowed (Identify) concurrency rate limit. + // + // https://discord.com/developers/docs/topics/gateway#rate-limiting + bot.Config.Gateway.RateLimiter.StartTx() + + identifyBucket := bot.Config.Gateway.RateLimiter.GetBucketFromID(FlagGatewaySendEventNameIdentify) + if identifyBucket == nil { + identifyBucket = getBucket() + bot.Config.Gateway.RateLimiter.SetBucketFromID(FlagGatewaySendEventNameIdentify, identifyBucket) + } + + identifyBucket.Limit = int16(response.SessionStartLimit.MaxConcurrency) + 1 + identifyBucket.Remaining = identifyBucket.Limit + identifyBucket.Expiry = time.Now().Add(FlagGlobalRateLimitIdentifyInterval) + + bot.Config.Gateway.RateLimiter.EndTx() + } + + var err error + + // connect to the Discord Gateway Websocket. + s.manager = new(manager) + s.Context, s.manager.cancel = context.WithCancel(context.Background()) + if s.Conn, _, err = websocket.Dial(s.Context, gatewayEndpoint, nil); err != nil { + return fmt.Errorf("error connecting to the Discord Gateway: %w", err) + } + + // handle the incoming Hello event upon connecting to the Gateway. + hello := new(Hello) + if err := readEvent(s, FlagGatewayEventNameHello, hello); err != nil { + err = fmt.Errorf("error reading initial Hello event: %w", err) + sessionErr := ErrorSession{SessionID: s.ID, Err: err} + if disconnectErr := s.disconnect(FlagClientCloseEventCodeNormal); disconnectErr != nil { + sessionErr.Err = ErrorDisconnect{ + Action: err, + Err: disconnectErr, + Connection: ErrConnectionSession, + } + } + + return sessionErr + } + + for _, handler := range bot.Handlers.Hello { + go handler(hello) + } + + // begin sending heartbeat payloads every heartbeat_interval ms. + ms := time.Millisecond * time.Duration(hello.HeartbeatInterval) + s.heartbeat = &heartbeat{ + interval: ms, + ticker: time.NewTicker(ms), + send: make(chan Heartbeat), + + // add a HeartbeatACK to the HeartbeatACK channel to prevent + // the length of the HeartbeatACK channel from being 0 immediately, + // which results in an attempt to reconnect. + acks: 1, + } + + // create a goroutine group for the Session. + s.manager.Group, s.manager.signal = errgroup.WithContext(s.Context) + s.manager.err = make(chan error, 1) + + // spawn the heartbeat pulse goroutine. + s.manager.routines.Add(1) + atomic.AddInt32(&s.manager.pulses, 1) + s.manager.Go(func() error { + s.pulse() + return nil + }) + + // spawn the heartbeat beat goroutine. + s.manager.routines.Add(1) + s.manager.Go(func() error { + if err := s.beat(bot); err != nil { + return ErrorSession{ + SessionID: s.ID, + Err: fmt.Errorf("heartbeat: %w", err), + } + } + + return nil + }) + + // send the initial Identify or Resumed packet. + if err := s.initial(bot, 0); err != nil { + sessionErr := ErrorSession{SessionID: s.ID, Err: err} + if disconnectErr := s.disconnect(FlagClientCloseEventCodeNormal); disconnectErr != nil { + sessionErr.Err = ErrorDisconnect{ + Action: err, + Err: disconnectErr, + Connection: ErrConnectionSession, + } + } + + return sessionErr + } + + // spawn the event listener listen goroutine. + s.manager.routines.Add(1) + s.manager.Go(func() error { + if err := s.listen(bot); err != nil { + return ErrorSession{ + SessionID: s.ID, + Err: fmt.Errorf("listen: %w", err), + } + } + + return nil + }) + + // spawn the manager goroutine. + s.manager.routines.Add(1) + go s.manage(bot) + + // ensure that the Session's goroutines are spawned. + s.manager.routines.Wait() + + return nil +} + +// initial sends the initial Identify or Resume packet required to connect to the Gateway, +// then handles the incoming Ready or Resumed packet that indicates a successful connection. +func (s *Session) initial(bot *Client, attempt int) error { + if !s.canReconnect() { + // send an Opcode 2 Identify to the Discord Gateway. + identify := Identify{ + Token: bot.Authentication.Token, + Properties: IdentifyConnectionProperties{ + OS: runtime.GOOS, + Browser: module, + Device: module, + }, + Compress: Pointer(true), + LargeThreshold: Pointer(maxIdentifyLargeThreshold), + Shard: nil, // SHARD: set shard information using s.Shard. + Presence: bot.Config.Gateway.GatewayPresenceUpdate, + Intents: bot.Config.Gateway.Intents, + } + + if err := identify.SendEvent(bot, s); err != nil { + return err + } + } else { + // send an Opcode 6 Resume to the Discord Gateway to reconnect the session. + resume := Resume{ + Token: bot.Authentication.Token, + SessionID: s.ID, + Seq: atomic.LoadInt64(&s.Seq), + } + + if err := resume.SendEvent(bot, s); err != nil { + return err + } + } + + // handle the incoming Ready, Resumed or Replayed event (or Opcode 9 Invalid Session). + payload := new(GatewayPayload) + if err := socket.Read(s.Context, s.Conn, payload); err != nil { + return fmt.Errorf("error reading initial payload: %w", err) + } + + LogPayload(LogSession(Logger.Info(), s.ID), payload.Op, payload.Data).Msg("received initial payload") + + switch payload.Op { + case FlagGatewayOpcodeDispatch: + switch { + // When a connection is successful, the Discord Gateway will respond with a Ready event. + case *payload.EventName == FlagGatewayEventNameReady: + ready := new(Ready) + if err := json.Unmarshal(payload.Data, ready); err != nil { + return fmt.Errorf("error reading ready event: %w", err) + } + + s.ID = ready.SessionID + atomic.StoreInt64(&s.Seq, 0) + s.Endpoint = ready.ResumeGatewayURL + // SHARD: set shard information using r.Shard + bot.ApplicationID = ready.Application.ID + + LogSession(Logger.Info(), s.ID).Msg("received Ready event") + + for _, handler := range bot.Handlers.Ready { + go handler(ready) + } + + // When a reconnection is successful, the Discord Gateway will respond + // by replaying all missed events in order, finalized by a Resumed event. + case *payload.EventName == FlagGatewayEventNameResumed: + LogSession(Logger.Info(), s.ID).Msg("received Resumed event") + + for _, handler := range bot.Handlers.Resumed { + go handler(&Resumed{}) + } + + // When a reconnection is successful, the Discord Gateway will respond + // by replaying all missed events in order, finalized by a Resumed event. + default: + // handle the initial payload(s) until a Resumed event is encountered. + go bot.handle(*payload.EventName, payload.Data) + + for { + replayed := new(GatewayPayload) + if err := socket.Read(s.Context, s.Conn, replayed); err != nil { + return fmt.Errorf("error replaying events: %w", err) + } + + if replayed.Op == FlagGatewayOpcodeDispatch && *replayed.EventName == FlagGatewayEventNameResumed { + LogSession(Logger.Info(), s.ID).Msg("received Resumed event") + + for _, handler := range bot.Handlers.Resumed { + go handler(&Resumed{}) + } + + return nil + } + + go bot.handle(*payload.EventName, payload.Data) + } + } + + // When the maximum concurrency limit has been reached while connecting, or when + // the session does NOT reconnect in time, the Discord Gateway send an Opcode 9 Invalid Session. + case FlagGatewayOpcodeInvalidSession: + if attempt < 1 { + // wait for Discord to close the session, then complete a fresh connect. + <-time.NewTimer(invalidSessionWaitTime).C + + s.ID = "" + atomic.StoreInt64(&s.Seq, 0) + if err := s.initial(bot, attempt+1); err != nil { + return err + } + + return nil + } + + return fmt.Errorf("session %q couldn't connect to the Discord Gateway or has invalidated an active session", s.ID) + default: + return fmt.Errorf("session %q received payload %d during connection which is unexpected", s.ID, payload.Op) + } + + return nil +} + +// Disconnect disconnects a session from the Discord Gateway using the given status code. +func (s *Session) Disconnect() error { + s.Lock() + + if !s.isConnected() { + s.Unlock() + + return fmt.Errorf("session %q is already disconnected", s.ID) + } + + id := s.ID + LogSession(Logger.Info(), id).Msgf("disconnecting session with code %d", FlagClientCloseEventCodeNormal) + + s.manager.signal = context.WithValue(s.manager.signal, keySignal, signalDisconnect) + + if err := s.disconnect(FlagClientCloseEventCodeNormal); err != nil { + s.Unlock() + + return ErrorDisconnect{ + Connection: ErrConnectionSession, + Action: nil, + Err: err, + } + } + + s.Unlock() + + if err := <-s.manager.err; err != nil { + return err + } + + putSession(s) + + LogSession(Logger.Info(), id).Msgf("disconnected session with code %d", FlagClientCloseEventCodeNormal) + + return nil +} + +// disconnect disconnects a session from a WebSocket Connection using the given status code. +func (s *Session) disconnect(code int) error { + // cancel the context to kill the goroutines of the Session. + defer s.manager.cancel() + + if err := s.Conn.Close(websocket.StatusCode(code), ""); err != nil { + return fmt.Errorf("%w", err) + } + + return nil +} + +// Reconnect reconnects an already connected session to the Discord Gateway +// by disconnecting the session, then connecting again. +func (s *Session) Reconnect(bot *Client) error { + s.reconnect("reconnecting") + + if err := <-s.manager.err; err != nil { + return err + } + + // connect to the Discord Gateway again. + if err := s.Connect(bot); err != nil { + return fmt.Errorf("error reconnecting session %q: %w", s.ID, err) + } + + return nil +} + +// readEvent is a helper function for reading events from the WebSocket Session. +func readEvent(s *Session, name string, dst any) error { + payload := new(GatewayPayload) + if err := socket.Read(s.Context, s.Conn, payload); err != nil { + return fmt.Errorf("readEvent: %w", err) + } + + if err := json.Unmarshal(payload.Data, dst); err != nil { + return fmt.Errorf("readEvent: %w", err) + } + + return nil +} + +// writeEvent is a helper function for writing events to the WebSocket Session. +func writeEvent(bot *Client, s *Session, op int, name string, dst any) error { +RATELIMIT: + // a single command is PROCESSED at any point in time. + bot.Config.Gateway.RateLimiter.Lock() + + LogCommand(LogSession(Logger.Trace(), s.ID), bot.ApplicationID, op, name).Msg("processing gateway command") + + for { + bot.Config.Gateway.RateLimiter.StartTx() + + globalBucket := bot.Config.Gateway.RateLimiter.GetBucket(GlobalRateLimitRouteID, "") + + // stop waiting when the Global Rate Limit Bucket is NOT empty. + if isNotEmpty(globalBucket) { + switch op { + case FlagGatewayOpcodeIdentify: + identifyBucket := bot.Config.Gateway.RateLimiter.GetBucketFromID(FlagGatewaySendEventNameIdentify) + + if isNotEmpty(identifyBucket) { + if globalBucket != nil { + globalBucket.Remaining-- + } + + if identifyBucket != nil { + identifyBucket.Remaining-- + } + + bot.Config.Gateway.RateLimiter.EndTx() + + goto SEND + } + + if isExpired(identifyBucket) { + if globalBucket != nil { + globalBucket.Remaining-- + } + + if identifyBucket != nil { + identifyBucket.Reset(time.Now().Add(FlagGlobalRateLimitIdentifyInterval)) + identifyBucket.Remaining-- + } + + bot.Config.Gateway.RateLimiter.EndTx() + + goto SEND + } + + var wait time.Time + if identifyBucket != nil { + wait = identifyBucket.Expiry + } + + // do NOT block other requests due to a Command Rate Limit. + bot.Config.Gateway.RateLimiter.EndTx() + bot.Config.Gateway.RateLimiter.Unlock() + + // reduce CPU usage by blocking the current goroutine + // until it's eligible for action. + if identifyBucket != nil { + <-time.After(time.Until(wait)) + } + + goto RATELIMIT + + default: + if globalBucket != nil { + globalBucket.Remaining-- + } + + bot.Config.Gateway.RateLimiter.EndTx() + + goto SEND + } + } + + // reset the Global Rate Limit Bucket when the current Bucket has passed its expiry. + if isExpired(globalBucket) { + globalBucket.Reset(time.Now().Add(time.Minute)) + } + + bot.Config.Gateway.RateLimiter.EndTx() + } + +SEND: + bot.Config.Gateway.RateLimiter.Unlock() + + LogCommand(LogSession(Logger.Trace(), s.ID), bot.ApplicationID, op, name).Msg("sending gateway command") + + // write the event to the WebSocket Connection. + event, err := json.Marshal(dst) + if err != nil { + return fmt.Errorf("writeEvent: %w", err) + } + + if err = socket.Write(s.Context, s.Conn, websocket.MessageBinary, + GatewayPayload{ //nolint:exhaustruct + Op: op, + Data: event, + }); err != nil { + return fmt.Errorf("writeEvent: %w", err) + } + + LogCommand(LogSession(Logger.Trace(), s.ID), bot.ApplicationID, op, name).Msg("sent gateway command") + + return nil +} + +// SendEvent sends an Opcode 1 Heartbeat event to the Discord Gateway. +func (c *Heartbeat) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodeHeartbeat, FlagGatewaySendEventNameHeartbeat, c); err != nil { + return err + } + + return nil +} + +// SendEvent sends an Opcode 2 Identify event to the Discord Gateway. +func (c *Identify) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodeIdentify, FlagGatewaySendEventNameIdentify, c); err != nil { + return err + } + + return nil +} + +// SendEvent sends an Opcode 3 UpdatePresence event to the Discord Gateway. +func (c *GatewayPresenceUpdate) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodePresenceUpdate, FlagGatewaySendEventNameUpdatePresence, c); err != nil { + return err + } + + return nil +} + +// SendEvent sends an Opcode 4 UpdateVoiceState event to the Discord Gateway. +func (c *VoiceStateUpdate) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodeVoiceStateUpdate, FlagGatewaySendEventNameUpdateVoiceState, c); err != nil { + return err + } + + return nil +} + +// SendEvent sends an Opcode 6 Resume event to the Discord Gateway. +func (c *Resume) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodeResume, FlagGatewaySendEventNameResume, c); err != nil { + return err + } + + return nil +} + +// SendEvent sends an Opcode 8 RequestGuildMembers event to the Discord Gateway. +func (c *RequestGuildMembers) SendEvent(bot *Client, session *Session) error { + if err := writeEvent(bot, session, FlagGatewayOpcodeRequestGuildMembers, FlagGatewaySendEventNameRequestGuildMembers, c); err != nil { + return err + } + + return nil +} + +// heartbeat represents the heartbeat mechanism for a Session. +type heartbeat struct { + ticker *time.Ticker + send chan Heartbeat + interval time.Duration + acks uint32 +} + +// Monitor returns the current amount of HeartbeatACKs for a Session's heartbeat. +func (s *Session) Monitor() uint32 { + s.Lock() + acks := atomic.LoadUint32(&s.heartbeat.acks) + s.Unlock() + + return acks +} + +// beat listens for pulses to send Opcode 1 Heartbeats to the Discord Gateway (to verify the connection is alive). +func (s *Session) beat(bot *Client) error { + s.manager.routines.Done() + + // ensure that all pulse routines are closed prior to closing. + defer func() { + for { + select { + case <-s.heartbeat.send: + case <-s.Context.Done(): + if atomic.LoadInt32(&s.manager.pulses) != 0 { + break + } + + s.logClose("heartbeat") + + return + } + } + }() + + for { + select { + case hb := <-s.heartbeat.send: + s.Lock() + + // close the connection if the last sent Heartbeat never received a HeartbeatACK. + if atomic.LoadUint32(&s.heartbeat.acks) == 0 { + s.Unlock() + + s.reconnect("attempting to reconnect session due to no HeartbeatACK") + + return nil + } + + // prevent two Heartbeat Payloads being sent to the Discord Gateway consecutively within nanoseconds, + // when the ticker queues a Heartbeat while the listen thread (onPayload) queues a Heartbeat + // (in response to the Discord Gateway). + // + // clear queued (outdated) heartbeats. + for len(s.heartbeat.send) > 0 { + // ensure the latest sequence is sent. + if h := <-s.heartbeat.send; h.Data > hb.Data { + hb.Data = h.Data + } + } + + // send a Heartbeat to the Discord Gateway (WebSocket Connection). + if err := hb.SendEvent(bot, s); err != nil { + s.Unlock() + + return err + } + + // reset the ticker (and empty existing ticks). + s.heartbeat.ticker.Reset(s.heartbeat.interval) + for len(s.heartbeat.ticker.C) > 0 { + <-s.heartbeat.ticker.C + } + + // reset the amount of HeartbeatACKs since the last heartbeat. + atomic.StoreUint32(&s.heartbeat.acks, 0) + + LogSession(Logger.Info(), s.ID).Msg("sent heartbeat") + + s.Unlock() + + case <-s.Context.Done(): + return nil + } + } +} + +// pulse generates Opcode 1 Heartbeats for a Session's heartbeat channel. +func (s *Session) pulse() { + s.manager.routines.Done() + defer s.decrementPulses() + + // send an Opcode 1 Heartbeat payload after heartbeat_interval * jitter milliseconds + // (where jitter is a random value between 0 and 1). + s.Lock() + s.heartbeat.send <- Heartbeat{Data: atomic.LoadInt64(&s.Seq)} + LogSession(Logger.Info(), s.ID).Msg("queued jitter heartbeat") + s.Unlock() + + for { + select { + // every Heartbeat Interval... + case <-s.heartbeat.ticker.C: + s.Lock() + + // queue a heartbeat. + s.heartbeat.send <- Heartbeat{Data: atomic.LoadInt64(&s.Seq)} + + LogSession(Logger.Info(), s.ID).Msg("queued heartbeat") + + s.Unlock() + + case <-s.Context.Done(): + s.Lock() + s.logClose("pulse") + s.Unlock() + + return + } + } +} + +// respond responds to Opcode 1 Heartbeats from the Discord Gateway. +func (s *Session) respond(data json.RawMessage) error { + defer s.decrementPulses() + + var heartbeat Heartbeat + if err := json.Unmarshal(data, &heartbeat); err != nil { + return fmt.Errorf("error unmarshalling incoming Heartbeat: %w", err) + } + + atomic.StoreInt64(&s.Seq, heartbeat.Data) + + s.Lock() + + // ensure that the heartbeat routine has not been closed. + if atomic.LoadInt32(&s.manager.pulses) <= 1 { + s.Unlock() + + return nil + } + + // heartbeat() checks for the amount of HeartbeatACKs received since the last Heartbeat. + // There is a possibility for this value to be 0 due to latency rather than a dead connection. + // For example, when a Heartbeat is queued, sent, responded, and sent. + // + // Prevent this possibility by treating this response from Discord as an indication that the + // connection is still alive. + atomic.AddUint32(&s.heartbeat.acks, 1) + + // send an Opcode 1 Heartbeat without waiting the remainder of the current interval. + s.heartbeat.send <- heartbeat + + LogSession(Logger.Info(), s.ID).Msg("responded to heartbeat") + + s.Unlock() + + return nil +} + +// listen listens to the connection for payloads from the Discord Gateway. +func (s *Session) listen(bot *Client) error { + s.manager.routines.Done() + + var err error + + for { + payload := getPayload() + if err = socket.Read(s.Context, s.Conn, payload); err != nil { + break + } + + LogPayload(LogSession(Logger.Info(), s.ID), payload.Op, payload.Data).Msg("received payload") + + if err = s.onPayload(bot, *payload); err != nil { + break + } + } + + s.Lock() + defer s.Unlock() + defer s.logClose("listen") + + select { + case <-s.Context.Done(): + return nil + + default: + return err + } +} + +// onPayload handles an Discord Gateway Payload. +func (s *Session) onPayload(bot *Client, payload GatewayPayload) error { + defer putPayload(&payload) + + // https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes + switch payload.Op { + // run the bot's event handlers. + case FlagGatewayOpcodeDispatch: + atomic.StoreInt64(&s.Seq, *payload.SequenceNumber) + go bot.handle(*payload.EventName, payload.Data) + + // send an Opcode 1 Heartbeat to the Discord Gateway. + case FlagGatewayOpcodeHeartbeat: + s.Lock() + atomic.AddInt32(&s.manager.pulses, 1) + s.Unlock() + + s.manager.Go(func() error { + if err := s.respond(payload.Data); err != nil { + return fmt.Errorf("respond: %w", err) + } + + return nil + }) + + // handle the successful acknowledgement of the client's last heartbeat. + case FlagGatewayOpcodeHeartbeatACK: + s.Lock() + atomic.AddUint32(&s.heartbeat.acks, 1) + s.Unlock() + + // occurs when the Discord Gateway is shutting down the connection, while signalling the client to reconnect. + case FlagGatewayOpcodeReconnect: + s.reconnect("reconnecting session due to Opcode 7 Reconnect") + + return nil + + // in the context of onPayload, an Invalid Session occurs when an active session is invalidated. + case FlagGatewayOpcodeInvalidSession: + // wait for Discord to close the session, then complete a fresh connect. + <-time.NewTimer(invalidSessionWaitTime).C + + s.Lock() + defer s.Unlock() + + if err := s.initial(bot, 0); err != nil { + return err + } + } + + return nil +} + +// signal represents a manager Context Signal. +type signal string + +// manager Context Signals. +const ( + // keySignal represents the Context key for a manager's signals. + keySignal = signal("signal") + + // keyReason represents the Context key for a manager's reason for disconnection. + keyReason = signal("reason") + + // signalDisconnect indicates that a Disconnection was called purposefully. + signalDisconnect = 1 + + // signalReconnect signals the manager to reconnect upon a successful disconnection. + signalReconnect = 2 +) + +// manager represents a manager of a Session's goroutines. +type manager struct { + signal context.Context + cancel context.CancelFunc + err chan error + *errgroup.Group + routines sync.WaitGroup + pulses int32 +} + +// decrementPulses safely decrements the pulses counter of a Session manager. +func (s *Session) decrementPulses() { + s.Lock() + defer s.Unlock() + + atomic.AddInt32(&s.manager.pulses, -1) +} + +// logClose safely logs the close of a Session's goroutine. +func (s *Session) logClose(routine string) { + LogSession(Logger.Info(), s.ID).Msgf("closed %s routine", routine) +} + +// reconnect spawns a goroutine for reconnection which prompts the manager +// to reconnect upon a disconnection. +func (s *Session) reconnect(reason string) { + s.manager.Go(func() error { + s.Lock() + defer s.logClose("reconnect") + defer s.Unlock() + + LogSession(Logger.Info(), s.ID).Msg(reason) + + s.manager.signal = context.WithValue(s.manager.signal, keySignal, signalReconnect) + if err := s.disconnect(FlagClientCloseEventCodeReconnect); err != nil { + return fmt.Errorf("reconnect: %w", err) + } + + return nil + }) +} + +// manage manages a Session's goroutines. +func (s *Session) manage(bot *Client) { + s.manager.routines.Done() + defer func() { + s.Lock() + s.logClose("manager") + s.Unlock() + }() + + // wait until all of a Session's goroutines are closed. + err := s.manager.Wait() + + // log the reason for disconnection (if applicable). + if reason := s.manager.signal.Value(keyReason); reason != nil { + LogSession(Logger.Info(), s.ID).Msgf("%v", reason) + } + + // when a signal is provided, it indicates that the disconnection was purposeful. + signal := s.manager.signal.Value(keySignal) + switch signal { + case signalDisconnect: + LogSession(Logger.Info(), s.ID).Msg("successfully disconnected") + + s.manager.err <- nil + + return + + case signalReconnect: + LogSession(Logger.Info(), s.ID).Msg("successfully disconnected (while reconnecting)") + + // allow Discord to close the session. + <-time.After(time.Second) + + s.manager.err <- nil + + return + } + + // when an error caused goroutines to close, manage the state of disconnection. + if err != nil { + disconnectErr := new(ErrorDisconnect) + closeErr := new(websocket.CloseError) + switch { + // when an error occurs from a purposeful disconnection. + case errors.As(err, disconnectErr): + s.manager.err <- err + + // when an error occurs from a WebSocket Close Error. + case errors.As(err, closeErr): + s.manager.err <- s.handleGatewayCloseError(bot, closeErr) + + default: + if cErr := s.Conn.Close(websocket.StatusCode(FlagClientCloseEventCodeAway), ""); cErr != nil { + s.manager.err <- ErrorDisconnect{ + Action: err, + Err: cErr, + Connection: ErrConnectionSession, + } + + return + } + + s.manager.err <- err + } + + return + } + + s.manager.err <- nil +} + +// handleGatewayCloseError handles a WebSocket CloseError. +func (s *Session) handleGatewayCloseError(bot *Client, closeErr *websocket.CloseError) error { + code, ok := GatewayCloseEventCodes[int(closeErr.Code)] + switch ok { + // Gateway Close Event Code is known. + case true: + LogSession(Logger.Info(), s.ID). + Msgf("received Gateway Close Event Code %d %s: %s", + code.Code, code.Description, code.Explanation, + ) + + if code.Reconnect { + s.reconnect(fmt.Sprintf("reconnecting due to Gateway Close Event Code %d", code.Code)) + + return nil + } + + return closeErr + + // Gateway Close Event Code is unknown. + default: + + // when another goroutine calls disconnect(), + // s.Conn.Close is called before s.cancel which will result in + // a CloseError with the close code that Disgo uses to reconnect. + if closeErr.Code == websocket.StatusCode(FlagClientCloseEventCodeReconnect) { + return nil + } + + LogSession(Logger.Info(), s.ID). + Msgf("received unknown Gateway Close Event Code %d with reason %q", + closeErr.Code, closeErr.Reason, + ) + + return closeErr + } +} diff --git a/go.mod b/go.mod index bc01206..22047e4 100644 --- a/go.mod +++ b/go.mod @@ -3,20 +3,20 @@ module github.com/switchupcb/disgo go 1.18 require ( - github.com/goccy/go-json v0.9.11 + github.com/goccy/go-json v0.10.0 github.com/gorilla/schema v1.2.0 github.com/rs/xid v1.4.0 github.com/rs/zerolog v1.28.0 github.com/switchupcb/websocket v1.8.8 - github.com/valyala/fasthttp v1.41.0 + github.com/valyala/fasthttp v1.43.0 golang.org/x/sync v0.1.0 ) require ( github.com/andybalholm/brotli v1.0.4 // indirect - github.com/klauspost/compress v1.15.9 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/klauspost/compress v1.15.12 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect + golang.org/x/sys v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index d371578..fcbfb11 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= @@ -19,12 +19,15 @@ github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlI github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= +github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -34,8 +37,8 @@ github.com/switchupcb/websocket v1.8.8 h1:0x7RIs90NJ8YggqcLdKeb/LTofJ1BY79n784pk github.com/switchupcb/websocket v1.8.8/go.mod h1:HdhyzCLfOFPrBv+QNcnDSbv8L8rfJ7ZCulrBKZJHip0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= -github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/fasthttp v1.43.0 h1:Gy4sb32C98fbzVWZlTM1oTMdLWGyvxR03VhM6cBIU4g= +github.com/valyala/fasthttp v1.43.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -47,8 +50,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/go.work.sum b/go.work.sum index e69de29..af45210 100644 --- a/go.work.sum +++ b/go.work.sum @@ -0,0 +1 @@ +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= diff --git a/tools/interaction.go b/tools/interaction.go index d3c40d5..0f54ad6 100644 --- a/tools/interaction.go +++ b/tools/interaction.go @@ -1,7 +1,7 @@ package tools import ( - disgo "github.com/switchupcb/disgo/wrapper" + "github.com/switchupcb/disgo" ) // OptionsToMap parses an array of options and suboptions into an OptionMap. diff --git a/tools/tools.go b/tools/tools.go index 6118d4d..67ffba9 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -6,7 +6,7 @@ import ( "os/signal" "syscall" - disgo "github.com/switchupcb/disgo/wrapper" + "github.com/switchupcb/disgo" "golang.org/x/sync/errgroup" ) diff --git a/wrapper/client.go b/wrapper/client.go index 481586a..340635e 100644 --- a/wrapper/client.go +++ b/wrapper/client.go @@ -71,9 +71,6 @@ type Authorization struct { // ClientSecret represents the application's client_secret. ClientSecret string - // Scopes represents a list of OAuth2 scopes. - Scopes []string - // RedirectURI represents the registered URL of the application. // // The URL should be non-url-encoded (i.e "https://localhost"), @@ -86,15 +83,18 @@ type Authorization struct { // prompt controls how the authorization flow handles existing authorizations. Prompt string + + // Scopes represents a list of OAuth2 scopes. + Scopes []string } // Config represents parameters used to perform various actions by the client. type Config struct { - // Request holds configuration variables that pertain to the Discord HTTP API. - Request Request - // Gateway holds configuration variables that pertain to the Discord Gateway. Gateway Gateway + + // Request holds configuration variables that pertain to the Discord HTTP API. + Request Request } // DefaultConfig returns a default client configuration. @@ -108,6 +108,9 @@ func DefaultConfig() *Config { // Request represents Discord Request parameters used to perform various actions by the client. type Request struct { + // RateLimiter represents an object that provides rate limit functionality. + RateLimiter RateLimiter + // Client is used to send requests. // // Use Client to set a custom User-Agent in the HTTP Request Header. @@ -130,9 +133,6 @@ type Request struct { // set RetryShared to true (default) to retry a request (within the per-route rate limit) // until it's successful or until it experiences a non-shared 429 status code. RetryShared bool - - // RateLimiter represents an object that provides rate limit functionality. - RateLimiter RateLimiter } const ( @@ -166,16 +166,19 @@ func DefaultRequest() Request { ) return Request{ + RateLimiter: ratelimiter, Client: client, Timeout: defaultRequestTimeout, Retries: 1, RetryShared: true, - RateLimiter: ratelimiter, } } // Gateway represents Discord Gateway parameters used to perform various actions by the client. type Gateway struct { + // RateLimiter represents an object that provides rate limit functionality. + RateLimiter RateLimiter + // Intents represents a Discord Gateway Intent. // // You must specify a Gateway Intent in order to receive specific information from an event. @@ -195,9 +198,6 @@ type Gateway struct { // // https://discord.com/developers/docs/topics/gateway#update-presence GatewayPresenceUpdate *GatewayPresenceUpdate - - // RateLimiter represents an object that provides rate limit functionality. - RateLimiter RateLimiter } const ( diff --git a/wrapper/errors.go b/wrapper/errors.go index df17fc8..7b0562b 100644 --- a/wrapper/errors.go +++ b/wrapper/errors.go @@ -13,6 +13,9 @@ const ( // ErrorRequest represents an HTTP Request error that occurs when an attempt to send a request fails. type ErrorRequest struct { + // Err represents the error that occurred while performing the action. + Err error + // ClientID represents the Application ID of the request sender. ClientID string @@ -27,9 +30,6 @@ type ErrorRequest struct { // Endpoint represents the endpoint the request was sent to. Endpoint string - - // Err represents the error that occurred while performing the action. - Err error } func (e ErrorRequest) Error() string { @@ -76,14 +76,14 @@ const ( // ErrorEventHandler represents an Event Handler error that occurs when an attempt to // add or remove an event handler fails. type ErrorEventHandler struct { + // Err represents the error that occurred while performing the action. + Err error + // ClientID represents the Application ID of the event handler owner. ClientID string // Event represents the event of the involved handler. Event string - - // Err represents the error that occurred while performing the action. - Err error } func (e ErrorEventHandler) Error() string { @@ -126,11 +126,11 @@ func (e ErrorEvent) Error() string { // ErrorSession represents a WebSocket Session error that occurs during an active session. type ErrorSession struct { - // SessionID represents the ID of the Session. - SessionID string - // Err represents the error that occurred. Err error + + // SessionID represents the ID of the Session. + SessionID string } func (e ErrorSession) Error() string { @@ -144,14 +144,14 @@ const ( // ErrorDisconnect represents a disconnection error that occurs when // an attempt to gracefully disconnect from a connection fails. type ErrorDisconnect struct { - // Connection represents the name of the connection. - Connection string - // Action represents the error that prompted the disconnection (if applicable). Action error // Err represents the error that occurred while disconnecting. Err error + + // Connection represents the name of the connection. + Connection string } func (e ErrorDisconnect) Error() string { diff --git a/wrapper/json_unmarshal.go b/wrapper/json_unmarshal.go index 7ebc909..60b4c70 100644 --- a/wrapper/json_unmarshal.go +++ b/wrapper/json_unmarshal.go @@ -129,8 +129,8 @@ func (r *EditOriginalInteractionResponse) UnmarshalJSON(b []byte) error { type alias EditOriginalInteractionResponse var unmarshalled struct { - alias Components json.RawMessage `json:"components"` + alias } if err := json.Unmarshal(b, &unmarshalled); err != nil { @@ -157,8 +157,8 @@ func (r *CreateFollowupMessage) UnmarshalJSON(b []byte) error { type alias CreateFollowupMessage var unmarshalled struct { - alias Components json.RawMessage `json:"components"` + alias } var err error diff --git a/wrapper/oauth2.go b/wrapper/oauth2.go index e1a2216..4f63229 100644 --- a/wrapper/oauth2.go +++ b/wrapper/oauth2.go @@ -59,21 +59,21 @@ type BotAuthParams struct { // Bot provides the client_id and scopes parameters. Bot *Client - // Permissions represents the permissions the bot is requesting. - Permissions BitFlag - // GuildID pre-selects a guild in the authorization prompt. GuildID string - // DisableGuildSelect disables the ability to select other guilds - // in the authorization prompt (when GuildID is provided). - DisableGuildSelect bool - // ResponseType provides the type of response the OAuth2 flow will return. // // In the context of bot authorization, response_type is only provided when // a scope outside of `bot` and `applications.commands` is requested. ResponseType string + + // Permissions represents the permissions the bot is requesting. + Permissions BitFlag + + // DisableGuildSelect disables the ability to select other guilds + // in the authorization prompt (when GuildID is provided). + DisableGuildSelect bool } // GenerateBotAuthorizationURL generates a bot authorization URL using the given BotAuthParams. diff --git a/wrapper/ratelimit.go b/wrapper/ratelimit.go index 3ce0af3..8dc2af5 100644 --- a/wrapper/ratelimit.go +++ b/wrapper/ratelimit.go @@ -31,12 +31,6 @@ type RateLimit struct { // Used to safely remove a Bucket once it's no longer in use. entries map[string]int - // muQueue represents a mutex used to process a single request a time. - muQueue sync.Mutex - - // muTx represents a mutex used to access multiple rate limit Buckets as a transaction. - muTx sync.Mutex - // DefaultBucket represents a Default Rate Limit Bucket, which is used to control // the rate of the "first request(s) for any given route". // @@ -55,6 +49,12 @@ type RateLimit struct { // Use a Default Bucket's Limit field-value to control how many requests of // a given route can be sent (per second) BEFORE the actual Rate Limit Bucket of that route is known. DefaultBucket *Bucket + + // muQueue represents a mutex used to process a single request a time. + muQueue sync.Mutex + + // muTx represents a mutex used to access multiple rate limit Buckets as a transaction. + muTx sync.Mutex } func (r *RateLimit) SetBucketID(routeid string, bucketid string) { diff --git a/wrapper/ratelimiter.go b/wrapper/ratelimiter.go index 383852c..73fbd7b 100644 --- a/wrapper/ratelimiter.go +++ b/wrapper/ratelimiter.go @@ -72,6 +72,14 @@ type RateLimiter interface { // Bucket represents a Discord API Rate Limit Bucket. type Bucket struct { + // Date represents the time at which Discord received the last request of the Bucket. + // + // Date is only applicable to Global Rate Limit Buckets. + Date time.Time + + // Expiry represents the time at which the Bucket will reset (or become outdated). + Expiry time.Time + // ID represents the Bucket ID. ID string @@ -83,14 +91,6 @@ type Bucket struct { // Pending represents the amount of requests that are sent and awaiting a response. Pending int16 - - // Date represents the time at which Discord received the last request of the Bucket. - // - // Date is only applicable to Global Rate Limit Buckets. - Date time.Time - - // Expiry represents the time at which the Bucket will reset (or become outdated). - Expiry time.Time } // Reset resets a Discord API Rate Limit Bucket and sets its expiry. diff --git a/wrapper/session.go b/wrapper/session.go index 230c1b0..3cfd4d2 100644 --- a/wrapper/session.go +++ b/wrapper/session.go @@ -8,8 +8,8 @@ import ( "sync/atomic" "time" - "github.com/goccy/go-json" - "github.com/switchupcb/disgo/wrapper/internal/socket" + json "github.com/goccy/go-json" + "github.com/switchupcb/disgo/wrapper/socket" "github.com/switchupcb/websocket" "golang.org/x/sync/errgroup" ) @@ -132,9 +132,9 @@ func (s *Session) connect(bot *Client) error { sessionErr := ErrorSession{SessionID: s.ID, Err: err} if disconnectErr := s.disconnect(FlagClientCloseEventCodeNormal); disconnectErr != nil { sessionErr.Err = ErrorDisconnect{ - Connection: ErrConnectionSession, Action: err, Err: disconnectErr, + Connection: ErrConnectionSession, } } @@ -188,9 +188,9 @@ func (s *Session) connect(bot *Client) error { sessionErr := ErrorSession{SessionID: s.ID, Err: err} if disconnectErr := s.disconnect(FlagClientCloseEventCodeNormal); disconnectErr != nil { sessionErr.Err = ErrorDisconnect{ - Connection: ErrConnectionSession, Action: err, Err: disconnectErr, + Connection: ErrConnectionSession, } } @@ -274,7 +274,7 @@ func (s *Session) initial(bot *Client, attempt int) error { } s.ID = ready.SessionID - s.Seq = 0 + atomic.StoreInt64(&s.Seq, 0) s.Endpoint = ready.ResumeGatewayURL // SHARD: set shard information using r.Shard bot.ApplicationID = ready.Application.ID @@ -328,7 +328,7 @@ func (s *Session) initial(bot *Client, attempt int) error { <-time.NewTimer(invalidSessionWaitTime).C s.ID = "" - s.Seq = 0 + atomic.StoreInt64(&s.Seq, 0) if err := s.initial(bot, attempt+1); err != nil { return err } diff --git a/wrapper/session_heartbeat.go b/wrapper/session_heartbeat.go index 5d4143a..c9a0179 100644 --- a/wrapper/session_heartbeat.go +++ b/wrapper/session_heartbeat.go @@ -113,7 +113,7 @@ func (s *Session) pulse() { // send an Opcode 1 Heartbeat payload after heartbeat_interval * jitter milliseconds // (where jitter is a random value between 0 and 1). s.Lock() - s.heartbeat.send <- Heartbeat{Data: s.Seq} + s.heartbeat.send <- Heartbeat{Data: atomic.LoadInt64(&s.Seq)} LogSession(Logger.Info(), s.ID).Msg("queued jitter heartbeat") s.Unlock() @@ -124,7 +124,7 @@ func (s *Session) pulse() { s.Lock() // queue a heartbeat. - s.heartbeat.send <- Heartbeat{Data: s.Seq} + s.heartbeat.send <- Heartbeat{Data: atomic.LoadInt64(&s.Seq)} LogSession(Logger.Info(), s.ID).Msg("queued heartbeat") diff --git a/wrapper/session_listener.go b/wrapper/session_listener.go index e30c9ac..af100a0 100644 --- a/wrapper/session_listener.go +++ b/wrapper/session_listener.go @@ -5,7 +5,7 @@ import ( "sync/atomic" "time" - "github.com/switchupcb/disgo/wrapper/internal/socket" + "github.com/switchupcb/disgo/wrapper/socket" ) // listen listens to the connection for payloads from the Discord Gateway. diff --git a/wrapper/session_manager.go b/wrapper/session_manager.go index 3836eb8..a1721c4 100644 --- a/wrapper/session_manager.go +++ b/wrapper/session_manager.go @@ -178,9 +178,9 @@ func (s *Session) manage(bot *Client) { default: if cErr := s.Conn.Close(websocket.StatusCode(FlagClientCloseEventCodeAway), ""); cErr != nil { s.manager.err <- ErrorDisconnect{ - Connection: ErrConnectionSession, - Err: cErr, Action: err, + Err: cErr, + Connection: ErrConnectionSession, } return diff --git a/wrapper/internal/socket/bpool.go b/wrapper/socket/bpool.go similarity index 100% rename from wrapper/internal/socket/bpool.go rename to wrapper/socket/bpool.go diff --git a/wrapper/internal/socket/socket.go b/wrapper/socket/socket.go similarity index 98% rename from wrapper/internal/socket/socket.go rename to wrapper/socket/socket.go index a84e3d6..389752e 100644 --- a/wrapper/internal/socket/socket.go +++ b/wrapper/socket/socket.go @@ -5,7 +5,7 @@ import ( "context" "fmt" - "github.com/goccy/go-json" + json "github.com/goccy/go-json" "github.com/switchupcb/websocket" ) diff --git a/wrapper/tests/integration/coverage_test.go b/wrapper/tests/integration/coverage_test.go index a417261..6a2bcfb 100644 --- a/wrapper/tests/integration/coverage_test.go +++ b/wrapper/tests/integration/coverage_test.go @@ -11,7 +11,7 @@ import ( "golang.org/x/sync/errgroup" "github.com/rs/zerolog" - . "github.com/switchupcb/disgo/wrapper" + . "github.com/switchupcb/disgo" ) // Error Format Strings diff --git a/wrapper/tests/integration/ratelimit_test.go b/wrapper/tests/integration/ratelimit_test.go index 4e3e0e2..f01909a 100644 --- a/wrapper/tests/integration/ratelimit_test.go +++ b/wrapper/tests/integration/ratelimit_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/rs/zerolog" - . "github.com/switchupcb/disgo/wrapper" + . "github.com/switchupcb/disgo" "golang.org/x/sync/errgroup" ) diff --git a/wrapper/tests/integration/session_test.go b/wrapper/tests/integration/session_test.go index 03cb0b5..76f2c01 100644 --- a/wrapper/tests/integration/session_test.go +++ b/wrapper/tests/integration/session_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/rs/zerolog" - . "github.com/switchupcb/disgo/wrapper" + . "github.com/switchupcb/disgo" ) // TestConnect tests Connect(), Disconnect(), heartbeat(), listen(), and onPayload() diff --git a/wrapper/tests/unit/handle_test.go b/wrapper/tests/unit/handle_test.go index 9ea9fc8..2f3fb54 100644 --- a/wrapper/tests/unit/handle_test.go +++ b/wrapper/tests/unit/handle_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - . "github.com/switchupcb/disgo/wrapper" + . "github.com/switchupcb/disgo" ) const ( diff --git a/wrapper/tests/unit/oauth2_test.go b/wrapper/tests/unit/oauth2_test.go index 1247784..3adc763 100644 --- a/wrapper/tests/unit/oauth2_test.go +++ b/wrapper/tests/unit/oauth2_test.go @@ -3,7 +3,7 @@ package unit_test import ( "testing" - . "github.com/switchupcb/disgo/wrapper" + . "github.com/switchupcb/disgo" ) // testOAuth2 represents parameters used to test GenerateAuthorizationURL. @@ -30,10 +30,10 @@ func TestGenerateAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "988406086973444138", ClientSecret: "", - Scopes: []string{"scope1", "scope2"}, RedirectURI: "https://localhost", State: "state", Prompt: "prompt", + Scopes: []string{"scope1", "scope2"}, }, }, response: "code", @@ -45,10 +45,10 @@ func TestGenerateAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "983406086973444138", ClientSecret: "", - Scopes: []string{"bot", "applications.commands"}, RedirectURI: "https://localhost", State: "", Prompt: "", + Scopes: []string{"bot", "applications.commands"}, }, }, response: "", @@ -60,10 +60,10 @@ func TestGenerateAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "406086983973444138", ClientSecret: "", - Scopes: []string{}, RedirectURI: "https://localhost", State: "", Prompt: "", + Scopes: []string{}, }, }, response: "", @@ -89,16 +89,16 @@ func TestGenerateBotAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "988406086973444138", ClientSecret: "", - Scopes: []string{"scope1", "scope2"}, RedirectURI: "https://github.com", State: "state", Prompt: "prompt", + Scopes: []string{"scope1", "scope2"}, }, }, + ResponseType: "", Permissions: 1, GuildID: "9862629927296967350", DisableGuildSelect: false, - ResponseType: "", }, output: EndpointAuthorizationURL() + "?client_id=988406086973444138&scope=scope1%20scope2&redirect_uri=https%3A%2F%2Fgithub.com&state=state&prompt=prompt&permissions=1&guild_id=9862629927296967350&disable_guild_select=false", }, @@ -109,16 +109,16 @@ func TestGenerateBotAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "983406086973444138", ClientSecret: "", - Scopes: []string{"bot", "applications.commands"}, RedirectURI: "https://github.com", State: "", Prompt: "", + Scopes: []string{"bot", "applications.commands"}, }, }, - Permissions: 10, GuildID: "2909267986263572999", - DisableGuildSelect: true, ResponseType: "code", + Permissions: 10, + DisableGuildSelect: true, }, output: EndpointAuthorizationURL() + "?responsetype=code&client_id=983406086973444138&scope=bot%20applications.commands&redirect_uri=https%3A%2F%2Fgithub.com&permissions=10&guild_id=2909267986263572999&disable_guild_select=true", }, @@ -129,16 +129,16 @@ func TestGenerateBotAuthorizationURL(t *testing.T) { Authorization: &Authorization{ ClientID: "406086983973444138", ClientSecret: "", - Scopes: []string{}, RedirectURI: "https://localhost", State: "", Prompt: "", + Scopes: []string{}, }, }, - Permissions: 10, GuildID: "2909267986263572999", - DisableGuildSelect: true, ResponseType: "code", + Permissions: 10, + DisableGuildSelect: true, }, output: EndpointAuthorizationURL() + "?responsetype=code&client_id=406086983973444138&redirect_uri=https%3A%2F%2Flocalhost&permissions=10&guild_id=2909267986263572999&disable_guild_select=true", },