feat(webhook): persist provider receipt statuses

This commit is contained in:
2026-06-05 00:03:15 +08:00
parent 5eb726b124
commit 66ecabb984
8 changed files with 305 additions and 4 deletions
+41 -1
View File
@@ -25,11 +25,13 @@ package webhook
// - Same hub.mode/hub.verify_token/hub.challenge verification flow
import (
"context"
"encoding/json"
"io"
"net/http"
"os"
"strconv"
"time"
"github.com/gin-gonic/gin"
@@ -193,6 +195,7 @@ func (h *FacebookWebhookHandler) HandleFacebookWebhook(c *gin.Context) {
"event_type", event.EventType,
"inbox_id", inbox.ID,
)
h.persistFacebookReceipt(c.Request.Context(), inbox, event)
continue
}
@@ -423,7 +426,11 @@ func (h *FacebookWebhookHandler) instagramAppSecrets(events []*fbchannel.ParsedW
}
func (h *FacebookWebhookHandler) processInstagramEvent(c *gin.Context, inbox *model.Inbox, event *fbchannel.ParsedWebhookEvent) {
if fbchannel.IsEchoMessage(event) || fbchannel.IsDeliveryOrReadReceipt(event) || fbchannel.IsThreadControlEvent(event) {
if fbchannel.IsDeliveryOrReadReceipt(event) {
h.persistFacebookReceipt(c.Request.Context(), inbox, event)
return
}
if fbchannel.IsEchoMessage(event) || fbchannel.IsThreadControlEvent(event) {
return
}
@@ -463,6 +470,39 @@ func (h *FacebookWebhookHandler) processInstagramEvent(c *gin.Context, inbox *mo
}
}
func (h *FacebookWebhookHandler) persistFacebookReceipt(ctx context.Context, inbox *model.Inbox, event *fbchannel.ParsedWebhookEvent) {
if h.persister == nil {
return
}
switch event.EventType {
case fbchannel.EventFBDelivery, fbchannel.EventIGDelivery:
if event.Delivery == nil {
return
}
occurredAt := millisToTime(event.Delivery.Watermark)
for _, mid := range event.Delivery.Mids {
if err := h.persister.UpdateMessageStatus(ctx, inbox, mid, model.MessageStatusDelivered, occurredAt); err != nil {
applogger.L().Errorf("Facebook webhook: delivery status persistence failed mid=%s inbox=%d: %v", mid, inbox.ID, err)
}
}
case fbchannel.EventFBRead, fbchannel.EventIGRead:
if event.Read == nil {
return
}
if err := h.persister.UpdateContactConversationMessagesStatus(ctx, inbox, event.SenderID, model.MessageStatusRead, millisToTime(event.Read.Watermark)); err != nil {
applogger.L().Errorf("Facebook webhook: read status persistence failed sender=%s inbox=%d: %v", event.SenderID, inbox.ID, err)
}
}
}
func millisToTime(value int64) *time.Time {
if value <= 0 {
return nil
}
t := time.UnixMilli(value)
return &t
}
func parseOptionalUintParam(value string) (uint, error) {
if value == "" {
return 0, nil