github.com/diamondburned/arikawa/v2@v2.1.0/utils/sendpart/sendpart.go (about) 1 package sendpart 2 3 import ( 4 "io" 5 "mime/multipart" 6 "net/url" 7 "strconv" 8 9 "github.com/diamondburned/arikawa/v2/utils/httputil" 10 "github.com/diamondburned/arikawa/v2/utils/json" 11 "github.com/pkg/errors" 12 ) 13 14 // File represents a file to be uploaded to Discord. 15 type File struct { 16 Name string 17 Reader io.Reader 18 } 19 20 // AttachmentURI returns the file encoded using the attachment URI required for 21 // embedding an attachment image. 22 func (f File) AttachmentURI() string { 23 u := url.URL{ 24 Scheme: "attachment", 25 Path: f.Name, 26 } 27 return u.String() 28 } 29 30 // DataMultipartWriter is a MultipartWriter that also contains data that's 31 // JSON-marshalable. 32 type DataMultipartWriter interface { 33 // NeedsMultipart returns true if the data interface must be sent using 34 // multipart form. 35 NeedsMultipart() bool 36 37 httputil.MultipartWriter 38 } 39 40 // POST sends a POST request using client to the given URL and unmarshal the 41 // body into v if it's not nil. It will only send using multipart if files is 42 // true. 43 func POST(c *httputil.Client, data DataMultipartWriter, v interface{}, url string) error { 44 if !data.NeedsMultipart() { 45 // No files, so no need for streaming. 46 return c.RequestJSON(v, "POST", url, httputil.WithJSONBody(data)) 47 } 48 49 resp, err := c.MeanwhileMultipart(data, "POST", url) 50 if err != nil { 51 return err 52 } 53 54 var body = resp.GetBody() 55 defer body.Close() 56 57 if v == nil { 58 return nil 59 } 60 61 return json.DecodeStream(body, v) 62 } 63 64 // Write writes the item into payload_json and the list of files into the 65 // multipart writer. Write does not close the body. 66 func Write(body *multipart.Writer, item interface{}, files []File) error { 67 // Encode the JSON body first 68 w, err := body.CreateFormField("payload_json") 69 if err != nil { 70 return errors.Wrap(err, "failed to create bodypart for JSON") 71 } 72 73 if err := json.EncodeStream(w, item); err != nil { 74 return errors.Wrap(err, "failed to encode JSON") 75 } 76 77 for i, file := range files { 78 num := strconv.Itoa(i) 79 80 w, err := body.CreateFormFile("file"+num, file.Name) 81 if err != nil { 82 return errors.Wrap(err, "failed to create bodypart for "+num) 83 } 84 85 if _, err := io.Copy(w, file.Reader); err != nil { 86 return errors.Wrap(err, "failed to write for file "+num) 87 } 88 } 89 90 return nil 91 }