]> git.giacomolli.uk - onechat/blob - whatsapp_image.go
Pass caller contexts through WhatsApp callbacks
[onechat] / whatsapp_image.go
1 package main
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "time"
8
9 "go.mau.fi/whatsmeow"
10 "go.mau.fi/whatsmeow/proto/waE2E"
11 )
12
13 // whatsappImageTime is the longest time of an image download.
14 const whatsappImageTime = 2 * time.Minute
15
16 // whatsappImage downloads only supported images and stores them before the
17 // event can be acknowledged. Both the declared size and the downloaded bytes
18 // must fit the image store. Decoded bytes determine the stored format.
19 func whatsappImage(ctx context.Context, client WhatsAppClient, store *ImageStore, message *waE2E.ImageMessage) (string, error) {
20 if message.GetFileLength() > imageMaxBytes {
21 return "", errImageSize
22 }
23
24 switch message.GetMimetype() {
25 case "image/jpeg", "image/png", "image/webp":
26 default:
27 return "", errImageFormat
28 }
29
30 if client == nil {
31 return "", errors.New("WhatsApp client is not available")
32 }
33
34 data, err := client.Download(ctx, message)
35 if err != nil {
36 return "", fmt.Errorf("download image: %w", whatsappImageDownloadError(err))
37 }
38
39 name, err := store.Save(data)
40 if err != nil {
41 return "", fmt.Errorf("store image: %w", err)
42 }
43
44 return name, nil
45 }
46
47 // whatsappImageDownloadError keeps only known safe causes. Library errors can
48 // contain signed URLs or direct paths even when request preparation fails, so
49 // arbitrary error text cannot go to the daemon log.
50 func whatsappImageDownloadError(err error) error {
51 switch {
52 case errors.Is(err, context.Canceled):
53 return context.Canceled
54 case errors.Is(err, context.DeadlineExceeded):
55 return context.DeadlineExceeded
56 }
57
58 var response whatsmeow.DownloadHTTPError
59
60 if errors.As(err, &response) && response.Response != nil {
61 return fmt.Errorf("media server returned HTTP %d", response.StatusCode)
62 }
63
64 return errors.New("media download failed")
65 }