diff --git a/0_example/create-message/main.go b/0_example/create-message/main.go new file mode 100644 index 0000000..3f1f445 --- /dev/null +++ b/0_example/create-message/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "log" + "os" + + "github.com/Karitham/corde" +) + +func main() { + token := os.Getenv("DISCORD_BOT_TOKEN") + if token == "" { + log.Fatalln("DISCORD_BOT_TOKEN not set") + } + + chID := corde.SnowflakeFromString(os.Getenv("DISCORD_CHANNEL_ID")) + if chID == 0 { + log.Fatalln("DISCORD_CHANNEL_ID not set") + } + + m := corde.NewMux("", 0, token) + + message := corde.Message{ + Embeds: []corde.Embed{ + { + Title: "hello corde!", + URL: "https://github.com/Karitham/corde", + Description: "corde is awesome :knot:", + }, + }, + } + + msg, err := m.CreateMessage(chID, message) + if err != nil { + log.Fatalln("error creating message: ", err) + } + + log.Printf("message created: %s", msg.ID) +} diff --git a/interactions-api.go b/interactions-api.go index 04ebbd6..9dd8db7 100644 --- a/interactions-api.go +++ b/interactions-api.go @@ -11,42 +11,50 @@ import ( ) // returns the body and its content-type -func toBody(i *InteractionRespData) (*bytes.Buffer, string) { - body := new(bytes.Buffer) +func toBody(w io.Writer, m *InteractionRespData) (string, error) { contentType := "application/json" payloadJSON := &bytes.Buffer{} - err := json.NewEncoder(payloadJSON).Encode(i) + err := json.NewEncoder(payloadJSON).Encode(m) if err != nil { - return nil, "" + return "", err } - if len(i.Attachments) < 1 { - payloadJSON.WriteTo(body) - return body, contentType + if len(m.Attachments) < 1 { + payloadJSON.WriteTo(w) + return contentType, nil } - mw := multipart.NewWriter(body) + mw := multipart.NewWriter(w) defer mw.Close() contentType = mw.FormDataContentType() mw.WriteField("payload_json", payloadJSON.String()) - for i, f := range i.Attachments { + if err := writeAttachments(mw, m.Attachments); err != nil { + return contentType, err + } + + return contentType, nil +} + +func writeAttachments(mw *multipart.Writer, attachments []Attachment) error { + for i, f := range attachments { if f.ID == 0 { f.ID = Snowflake(i) } ff, CFerr := mw.CreateFormFile(fmt.Sprintf("files[%d]", i), f.Filename) if CFerr != nil { - return body, contentType + return CFerr } if _, CopyErr := io.Copy(ff, f.Body); CopyErr != nil { - return body, contentType + return CopyErr } } - return body, contentType + + return nil } // GetOriginalInteraction returns the original response to an Interaction @@ -66,9 +74,13 @@ func (m *Mux) GetOriginalInteraction(token string) (*InteractionRespData, error) // // https://discord.com/developers/docs/interactions/receiving-and-responding#edit-original-interaction-response func (m *Mux) EditOriginalInteraction(token string, data InteractionResponder) error { - body, contentType := toBody(data.InteractionRespData()) + body := &bytes.Buffer{} + contentType, err := toBody(body, data.InteractionRespData()) + if err != nil { + return err + } - _, err := m.Client.Do( + _, err = m.Client.Do( rest.Req("/webhooks", m.AppID, token, "messages/@original"). AnyBody(body).Patch(m.authorize, rest.ContentType(contentType)), ) @@ -97,9 +109,13 @@ func (m *Mux) DeleteOriginalInteraction(token string) error { // // https://discord.com/developers/docs/interactions/receiving-and-responding#followup-messages func (m *Mux) FollowUpInteraction(token string, data InteractionResponder) error { - body, contentType := toBody(data.InteractionRespData()) + body := &bytes.Buffer{} + contentType, err := toBody(body, data.InteractionRespData()) + if err != nil { + return err + } - _, err := m.Client.Do( + _, err = m.Client.Do( rest.Req("/webhooks", m.AppID, token). AnyBody(body).Post(m.authorize, rest.ContentType(contentType)), ) @@ -126,9 +142,13 @@ func (m *Mux) GetFollowUpInteraction(token string, messageID Snowflake) (*Intera // // https://discord.com/developers/docs/interactions/receiving-and-responding#edit-followup-message func (m *Mux) EditFollowUpInteraction(token string, messageID Snowflake, data InteractionResponder) error { - body, contentType := toBody(data.InteractionRespData()) + body := &bytes.Buffer{} + contentType, err := toBody(body, data.InteractionRespData()) + if err != nil { + return err + } - _, err := m.Client.Do( + _, err = m.Client.Do( rest.Req("/webhooks", m.AppID, token, "messages", messageID). AnyBody(body).Patch(m.authorize, rest.ContentType(contentType)), ) diff --git a/messages-api.go b/messages-api.go new file mode 100644 index 0000000..fc618d5 --- /dev/null +++ b/messages-api.go @@ -0,0 +1,70 @@ +package corde + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "mime/multipart" + + "github.com/Karitham/corde/internal/rest" +) + +// returns the content-type +func toBodyMessage(w io.Writer, m Message) (string, error) { + contentType := "application/json" + + payloadJSON := &bytes.Buffer{} + err := json.NewEncoder(payloadJSON).Encode(m) + if err != nil { + return "", err + } + + if len(m.Attachments) < 1 { + payloadJSON.WriteTo(w) + return contentType, nil + } + + mw := multipart.NewWriter(w) + defer mw.Close() + + contentType = mw.FormDataContentType() + mw.WriteField("payload_json", payloadJSON.String()) + + if err := writeAttachments(mw, m.Attachments); err != nil { + return contentType, err + } + + return contentType, nil +} + +// CreateMessage creates a new message in a channel +// +// https://discord.com/developers/docs/resources/channel#create-message +func (m *Mux) CreateMessage(channelID Snowflake, data Message) (*Message, error) { + body := &bytes.Buffer{} + contentType, err := toBodyMessage(body, data) + if err != nil { + return nil, err + } + + resp, err := m.Client.Do( + rest.Req("/channels", channelID, "messages"). + AnyBody(body).Post(m.authorize, rest.ContentType(contentType)), + ) + if err != nil { + return nil, fmt.Errorf("failed to create message: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode > 299 { + anyerr := map[string]any{} + json.NewDecoder(resp.Body).Decode(&anyerr) + return nil, fmt.Errorf("failed to create message: %+v", anyerr) + } + + msg := &Message{} + json.NewDecoder(resp.Body).Decode(msg) + return msg, nil + +} diff --git a/messages.go b/messages.go index dbdc651..b2d52d9 100644 --- a/messages.go +++ b/messages.go @@ -26,7 +26,7 @@ type Message struct { Activity Activity `json:"activity,omitempty"` Application Application `json:"application,omitempty"` ApplicationID Snowflake `json:"application_id,omitempty"` - MessageReference MessageReference `json:"message_reference,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` Flags MessageFlag `json:"flags,omitempty"` ReferencedMessage *Message `json:"referenced_message,omitempty"` Interaction *Interaction[JsonRaw] `json:"interaction,omitempty"` diff --git a/router.go b/router.go index 7e23301..ffe9e56 100644 --- a/router.go +++ b/router.go @@ -169,5 +169,5 @@ func routeRequest[IntReqData InteractionDataConstraint]( return nil } - return fmt.Errorf("No handler for interaction type: %d", it) + return fmt.Errorf("no handler for interaction type: %d", it) }