Major refactor to library
This commit is contained in:
138
pkg/whatsapp/businessapi/media.go
Normal file
138
pkg/whatsapp/businessapi/media.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package businessapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// uploadMedia uploads media to the Business API and returns the media ID
|
||||
func (c *Client) uploadMedia(ctx context.Context, data []byte, mimeType string) (string, error) {
|
||||
url := fmt.Sprintf("https://graph.facebook.com/%s/%s/media",
|
||||
c.config.APIVersion,
|
||||
c.config.PhoneNumberID)
|
||||
|
||||
// Create multipart form data
|
||||
var requestBody bytes.Buffer
|
||||
writer := multipart.NewWriter(&requestBody)
|
||||
|
||||
// Add the file
|
||||
part, err := writer.CreateFormFile("file", "media")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create form file: %w", err)
|
||||
}
|
||||
|
||||
if _, err := part.Write(data); err != nil {
|
||||
return "", fmt.Errorf("failed to write file data: %w", err)
|
||||
}
|
||||
|
||||
// Add messaging_product field
|
||||
if err := writer.WriteField("messaging_product", "whatsapp"); err != nil {
|
||||
return "", fmt.Errorf("failed to write messaging_product field: %w", err)
|
||||
}
|
||||
|
||||
// Add type field (mime type)
|
||||
if err := writer.WriteField("type", mimeType); err != nil {
|
||||
return "", fmt.Errorf("failed to write type field: %w", err)
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close multipart writer: %w", err)
|
||||
}
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, &requestBody)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
// Send request
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to upload media: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var errResp ErrorResponse
|
||||
if err := json.Unmarshal(body, &errResp); err == nil {
|
||||
return "", fmt.Errorf("upload error: %s (code: %d)", errResp.Error.Message, errResp.Error.Code)
|
||||
}
|
||||
return "", fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
var uploadResp MediaUploadResponse
|
||||
if err := json.Unmarshal(body, &uploadResp); err != nil {
|
||||
return "", fmt.Errorf("failed to parse upload response: %w", err)
|
||||
}
|
||||
|
||||
return uploadResp.ID, nil
|
||||
}
|
||||
|
||||
// downloadMedia downloads media from the Business API using the media ID
|
||||
func (c *Client) downloadMedia(ctx context.Context, mediaID string) ([]byte, string, error) {
|
||||
// Step 1: Get the media URL
|
||||
url := fmt.Sprintf("https://graph.facebook.com/%s/%s",
|
||||
c.config.APIVersion,
|
||||
mediaID)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to get media URL: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return nil, "", fmt.Errorf("failed to get media URL, status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
var mediaResp MediaURLResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&mediaResp); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to parse media URL response: %w", err)
|
||||
}
|
||||
|
||||
// Step 2: Download from the CDN URL
|
||||
downloadReq, err := http.NewRequestWithContext(ctx, "GET", mediaResp.URL, nil)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to create download request: %w", err)
|
||||
}
|
||||
|
||||
downloadReq.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
|
||||
|
||||
downloadResp, err := c.httpClient.Do(downloadReq)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to download media: %w", err)
|
||||
}
|
||||
defer downloadResp.Body.Close()
|
||||
|
||||
if downloadResp.StatusCode != http.StatusOK {
|
||||
return nil, "", fmt.Errorf("failed to download media, status %d", downloadResp.StatusCode)
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(downloadResp.Body)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to read media data: %w", err)
|
||||
}
|
||||
|
||||
return data, mediaResp.MimeType, nil
|
||||
}
|
||||
Reference in New Issue
Block a user