feat(presence): expose POST /message/subscribe to receive contact presence - #152
Open
nicolasnovis wants to merge 1 commit into
Open
feat(presence): expose POST /message/subscribe to receive contact presence#152nicolasnovis wants to merge 1 commit into
nicolasnovis wants to merge 1 commit into
Conversation
Add POST /message/subscribe so an instance can subscribe to a contact's WhatsApp presence. whatsmeow only delivers events.Presence for JIDs we've explicitly subscribed to (and only while marked available), so the handler sends available first, then SubscribePresence(jid). Subscriptions are ephemeral, so callers re-subscribe when a chat is opened. Also enrich the events.Presence webhook with explicit top-level 'from' and 'lastSeen' (unix) fields so consumers don't depend on JID/time marshaling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reviewer's GuideAdds a new POST /message/subscribe endpoint and service method to explicitly subscribe an instance to a contact’s presence updates in WhatsApp (via whatsmeow), and enriches Presence webhook events with top-level from and lastSeen fields. Sequence diagram for POST /message/subscribe presence subscription flowsequenceDiagram
actor ApiClient
participant GinRouter
participant MessageHandler
participant MessageService
participant MyClient
ApiClient->>GinRouter: POST /message/subscribe {number}
GinRouter->>MessageHandler: SubscribePresence(ctx)
MessageHandler->>MessageHandler: ctx.MustGet(instance)
MessageHandler->>MessageHandler: ctx.ShouldBindBodyWithJSON(data)
MessageHandler->>MessageService: SubscribePresence(data, instance)
MessageService->>MessageService: ensureClientConnected(instance.Id)
MessageService->>MessageService: utils.ParseJID(data.Number)
MessageService->>MessageService: utils.CanonicalJID(recipient)
MessageService->>MyClient: SendPresence(ctx, types.PresenceAvailable)
MessageService->>MyClient: SubscribePresence(ctx, recipient)
MessageService-->>MessageHandler: nil
MessageHandler-->>ApiClient: 200 {"message":"success"}
Sequence diagram for updated Presence webhook event enrichmentsequenceDiagram
participant WhatsApp
participant MyClient
WhatsApp-->>MyClient: events.Presence evt
MyClient->>MyClient: myEventHandler(evt)
MyClient->>MyClient: postMap["event"] = "Presence"
MyClient->>MyClient: postMap["from"] = evt.From.String()
alt evt.Unavailable && !evt.LastSeen.IsZero()
MyClient->>MyClient: postMap["state"] = "offline"
MyClient->>MyClient: postMap["lastSeen"] = evt.LastSeen.Unix()
else evt.Unavailable && evt.LastSeen.IsZero()
MyClient->>MyClient: postMap["state"] = "offline"
else !evt.Unavailable
MyClient->>MyClient: postMap["state"] = "online"
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
SubscribePresencehandler you declarevar data *message_service.SubscribePresenceStructand pass&datatoShouldBindBodyWithJSON; this creates a pointer-to-pointer pattern that is unusual for Gin and inconsistent with the other handlers—consider using a value struct (e.g.var data message_service.SubscribePresenceStructand binding into&data) for simpler and safer binding. - In
MessageService.SubscribePresenceyou usecontext.Background()forSendPresenceandSubscribePresence; consider threading through a request-scoped context (or a context with timeout) so these calls respect client cancellation and avoid potentially hanging operations.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `SubscribePresence` handler you declare `var data *message_service.SubscribePresenceStruct` and pass `&data` to `ShouldBindBodyWithJSON`; this creates a pointer-to-pointer pattern that is unusual for Gin and inconsistent with the other handlers—consider using a value struct (e.g. `var data message_service.SubscribePresenceStruct` and binding into `&data`) for simpler and safer binding.
- In `MessageService.SubscribePresence` you use `context.Background()` for `SendPresence` and `SubscribePresence`; consider threading through a request-scoped context (or a context with timeout) so these calls respect client cancellation and avoid potentially hanging operations.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses part of #146 (the
SubscribePresencehalf).whatsmeow only delivers
events.Presence(online/offline/last-seen) for JIDs you've explicitlySubscribePresence'd, and only while the instance is marked available. Today there is no route to subscribe, so the existingevents.Presencehandler never fires.This adds
POST /message/subscribe {number}which sends available first (idempotent — chat presence and the background presence loop already do this) and then callsclient.SubscribePresence(jid). Subscriptions are ephemeral (reset on reconnect), so callers re-subscribe when a chat is opened.It also enriches the
Presencewebhook payload with explicit top-levelfromandlastSeen(unix) fields, so consumers don't have to depend ontypes.JID/time.TimeJSON marshaling.Tested in production: opening a chat subscribes the contact, and online/offline/last-seen events flow through the webhook.
Summary by Sourcery
Add an endpoint and service support to subscribe to WhatsApp contact presence and enrich emitted presence webhooks.
New Features:
Enhancements: