Add file upload support for Discord
This commit is contained in:
parent
89e8371787
commit
00864842b3
|
@ -7,8 +7,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -187,13 +189,15 @@ type CreateMessageRequest struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMessage(ctx context.Context, channelID string, payloadJSON string) (*Message, error) {
|
func CreateMessage(ctx context.Context, channelID string, payloadJSON string, files ...FileUpload) (*Message, error) {
|
||||||
const name = "Create Message"
|
const name = "Create Message"
|
||||||
|
|
||||||
|
contentType, body := makeNewMessageBody(payloadJSON, files)
|
||||||
|
|
||||||
path := fmt.Sprintf("/channels/%s/messages", channelID)
|
path := fmt.Sprintf("/channels/%s/messages", channelID)
|
||||||
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
||||||
req := makeRequest(ctx, http.MethodPost, path, []byte(payloadJSON))
|
req := makeRequest(ctx, http.MethodPost, path, body)
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", contentType)
|
||||||
return req
|
return req
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -568,6 +572,41 @@ func CreateInteractionResponse(ctx context.Context, interactionID, interactionTo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EditOriginalInteractionResponse(ctx context.Context, interactionToken string, payloadJSON string, files ...FileUpload) (*Message, error) {
|
||||||
|
const name = "Edit Original Interaction Response"
|
||||||
|
|
||||||
|
contentType, body := makeNewMessageBody(payloadJSON, files)
|
||||||
|
|
||||||
|
path := fmt.Sprintf("/webhooks/%s/%s/messages/@original", config.Config.Discord.BotUserID, interactionToken)
|
||||||
|
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
||||||
|
req := makeRequest(ctx, http.MethodPatch, path, body)
|
||||||
|
req.Header.Add("Content-Type", contentType)
|
||||||
|
return req
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode >= 400 {
|
||||||
|
logErrorResponse(ctx, name, res, "")
|
||||||
|
return nil, oops.New(nil, "received error from Discord")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBytes, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg Message
|
||||||
|
err = json.Unmarshal(bodyBytes, &msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, oops.New(err, "failed to unmarshal Discord message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetAuthorizeUrl(state string) string {
|
func GetAuthorizeUrl(state string) string {
|
||||||
params := make(url.Values)
|
params := make(url.Values)
|
||||||
params.Set("response_type", "code")
|
params.Set("response_type", "code")
|
||||||
|
@ -578,6 +617,43 @@ func GetAuthorizeUrl(state string) string {
|
||||||
return fmt.Sprintf("https://discord.com/api/oauth2/authorize?%s", params.Encode())
|
return fmt.Sprintf("https://discord.com/api/oauth2/authorize?%s", params.Encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileUpload struct {
|
||||||
|
Name string
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNewMessageBody(payloadJSON string, files []FileUpload) (contentType string, body []byte) {
|
||||||
|
if len(files) == 0 {
|
||||||
|
contentType = "application/json"
|
||||||
|
body = []byte(payloadJSON)
|
||||||
|
} else {
|
||||||
|
var bodyBuffer bytes.Buffer
|
||||||
|
w := multipart.NewWriter(&bodyBuffer)
|
||||||
|
contentType = w.FormDataContentType()
|
||||||
|
|
||||||
|
jsonHeader := textproto.MIMEHeader{}
|
||||||
|
jsonHeader.Set("Content-Disposition", `form-data; name="payload_json"`)
|
||||||
|
jsonHeader.Set("Content-Type", "application/json")
|
||||||
|
jsonWriter, _ := w.CreatePart(jsonHeader)
|
||||||
|
jsonWriter.Write([]byte(payloadJSON))
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
formFile, _ := w.CreateFormFile("file", f.Name)
|
||||||
|
formFile.Write(f.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
body = bodyBuffer.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(body) == 0 {
|
||||||
|
panic("somehow we generated an empty body for Discord")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func logErrorResponse(ctx context.Context, name string, res *http.Response, msg string) {
|
func logErrorResponse(ctx context.Context, name string, res *http.Response, msg string) {
|
||||||
dump, err := httputil.DumpResponse(res, true)
|
dump, err := httputil.DumpResponse(res, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue