90 lines
2.9 KiB
Go
90 lines
2.9 KiB
Go
package webhook
|
|
|
|
// TwilioWebhookHandler processes incoming Twilio SMS webhook HTTP requests via Gin.
|
|
// Reference: Facebook webhook adapter pattern (facebook_webhook.go)
|
|
//
|
|
// URL patterns:
|
|
// /webhooks/twilio/sms/:inbox_id — inbound SMS/MMS
|
|
// /webhooks/twilio/status/:inbox_id — delivery status callbacks
|
|
//
|
|
// Method: POST (Twilio sends form-encoded data, not JSON)
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
twiliochannel "github.com/gochat/gochat/internal/channel/twilio"
|
|
"github.com/gochat/gochat/internal/model"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// TwilioWebhookHandler processes Twilio SMS webhook requests via Gin.
|
|
type TwilioWebhookHandler struct {
|
|
twilioWebhook *twiliochannel.WebhookHandler
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewTwilioWebhookHandler creates a Twilio SMS webhook handler for Gin integration.
|
|
func NewTwilioWebhookHandler(twilioWebhook *twiliochannel.WebhookHandler, db *gorm.DB) *TwilioWebhookHandler {
|
|
return &TwilioWebhookHandler{
|
|
twilioWebhook: twilioWebhook,
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// HandleTwilioInboundSMS processes an incoming Twilio SMS webhook Gin request.
|
|
func (h *TwilioWebhookHandler) HandleTwilioInboundSMS(c *gin.Context) {
|
|
inboxIDStr := c.Param("inbox_id")
|
|
inboxID, err := strconv.ParseUint(inboxIDStr, 10, 32)
|
|
if err != nil {
|
|
applogger.L().Warnf("Twilio webhook: invalid inbox_id %s", inboxIDStr)
|
|
c.Data(http.StatusOK, "application/xml", []byte("<Response></Response>"))
|
|
return
|
|
}
|
|
|
|
// Lookup inbox from database
|
|
inbox, err := h.lookupInbox(uint(inboxID))
|
|
if err != nil {
|
|
applogger.L().Warnf("Twilio webhook: inbox lookup failed for id %d: %v", inboxID, err)
|
|
c.Data(http.StatusOK, "application/xml", []byte("<Response></Response>"))
|
|
return
|
|
}
|
|
|
|
// Dispatch to the channel-level webhook handler
|
|
// Twilio expects a TwiML XML response, not JSON
|
|
h.twilioWebhook.HandleInboundSMS(c.Writer, c.Request, inbox)
|
|
}
|
|
|
|
// HandleTwilioDeliveryStatus processes a Twilio delivery status callback.
|
|
func (h *TwilioWebhookHandler) HandleTwilioDeliveryStatus(c *gin.Context) {
|
|
inboxIDStr := c.Param("inbox_id")
|
|
inboxID, err := strconv.ParseUint(inboxIDStr, 10, 32)
|
|
if err != nil {
|
|
applogger.L().Warnf("Twilio status webhook: invalid inbox_id %s", inboxIDStr)
|
|
c.Status(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
// Lookup inbox from database
|
|
inbox, err := h.lookupInbox(uint(inboxID))
|
|
if err != nil {
|
|
applogger.L().Warnf("Twilio status webhook: inbox lookup failed for id %d: %v", inboxID, err)
|
|
c.Status(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
// Dispatch to the channel-level delivery status handler
|
|
h.twilioWebhook.HandleDeliveryStatus(c.Writer, c.Request, inbox)
|
|
}
|
|
|
|
// lookupInbox fetches an Inbox record from the database.
|
|
func (h *TwilioWebhookHandler) lookupInbox(inboxID uint) (*model.Inbox, error) {
|
|
var inbox model.Inbox
|
|
if err := h.db.Where("id = ?", inboxID).First(&inbox).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &inbox, nil
|
|
} |