feat(cache): 🎉 add message caching functionality
Some checks failed
CI / Test (1.23) (push) Failing after -27m1s
CI / Lint (push) Successful in -26m31s
CI / Build (push) Successful in -27m3s
CI / Test (1.22) (push) Failing after -24m58s

* Implement MessageCache to store events when no webhooks are available.
* Add configuration options for enabling cache, setting data path, max age, and max events.
* Create API endpoints for managing cached events, including listing, replaying, and deleting.
* Integrate caching into the hooks manager to store events when no active webhooks are found.
* Enhance logging for better traceability of cached events and operations.
This commit is contained in:
Hein
2026-01-30 16:00:34 +02:00
parent 3901bbb668
commit c4d974d6ce
9 changed files with 1535 additions and 30 deletions

View File

@@ -31,13 +31,24 @@ func (c *Client) HandleWebhook(r *http.Request) error {
return fmt.Errorf("failed to parse webhook payload: %w", err)
}
logging.Info("Processing webhook payload",
"account_id", c.id,
"entries", len(payload.Entry))
// Process each entry
changeCount := 0
for _, entry := range payload.Entry {
changeCount += len(entry.Changes)
for i := range entry.Changes {
c.processChange(entry.Changes[i])
}
}
logging.Info("Webhook payload processed",
"account_id", c.id,
"entries", len(payload.Entry),
"changes", changeCount)
return nil
}
@@ -45,11 +56,17 @@ func (c *Client) HandleWebhook(r *http.Request) error {
func (c *Client) processChange(change WebhookChange) {
ctx := context.Background()
logging.Info("Processing webhook change",
"account_id", c.id,
"field", change.Field,
"phone_number_id", change.Value.Metadata.PhoneNumberID)
// Handle different field types
switch change.Field {
case "messages":
// Process messages
for _, msg := range change.Value.Messages {
for i := range change.Value.Messages {
msg := change.Value.Messages[i]
c.processMessage(ctx, msg, change.Value.Contacts)
}
@@ -212,7 +229,8 @@ func (c *Client) processMessage(ctx context.Context, msg WebhookMessage, contact
messageType = "contacts"
// Format contacts as text
var contactNames []string
for _, contact := range msg.Contacts {
for i := range msg.Contacts {
contact := msg.Contacts[i]
contactNames = append(contactNames, contact.Name.FormattedName)
}
text = fmt.Sprintf("Shared %d contact(s): %s", len(msg.Contacts), strings.Join(contactNames, ", "))
@@ -262,7 +280,7 @@ func (c *Client) processMessage(ctx context.Context, msg WebhookMessage, contact
}
case "unknown":
messageType = "unknown"
// messageType = "unknown"
logging.Warn("Received unknown message type", "account_id", c.id, "message_id", msg.ID)
return
@@ -272,7 +290,7 @@ func (c *Client) processMessage(ctx context.Context, msg WebhookMessage, contact
}
// Publish message received event
logging.Debug("Publishing message received event",
logging.Info("Message received via WhatsApp",
"account_id", c.id,
"message_id", msg.ID,
"from", msg.From,
@@ -306,15 +324,15 @@ func (c *Client) processStatus(ctx context.Context, status WebhookStatus) {
switch status.Status {
case "sent":
c.eventBus.Publish(events.MessageSentEvent(ctx, c.id, status.ID, status.RecipientID, ""))
logging.Debug("Message sent status", "account_id", c.id, "message_id", status.ID)
logging.Info("Message status: sent", "account_id", c.id, "message_id", status.ID, "recipient", status.RecipientID)
case "delivered":
c.eventBus.Publish(events.MessageDeliveredEvent(ctx, c.id, status.ID, status.RecipientID, timestamp))
logging.Debug("Message delivered", "account_id", c.id, "message_id", status.ID)
logging.Info("Message status: delivered", "account_id", c.id, "message_id", status.ID, "recipient", status.RecipientID)
case "read":
c.eventBus.Publish(events.MessageReadEvent(ctx, c.id, status.ID, status.RecipientID, timestamp))
logging.Debug("Message read", "account_id", c.id, "message_id", status.ID)
logging.Info("Message status: read", "account_id", c.id, "message_id", status.ID, "recipient", status.RecipientID)
case "failed":
errMsg := "unknown error"