From 9410ddfc04b12826320b88e0de9cfec7dfc3ce3f Mon Sep 17 00:00:00 2001 From: Michel Spinelli Date: Wed, 24 Jun 2026 14:38:24 -0300 Subject: [PATCH] feat: implement alwaysOnline presence flag (was a no-op) The `alwaysOnline` advanced setting exists on the instance model, the REST API and Swagger, but it was never wired into the presence logic. On every connect the device was marked `PresenceAvailable` unconditionally and the periodic `schedulePresenceUpdates` job kept re-asserting it, so the linked device stayed permanently "available". WhatsApp then delivers messages to that active session and suppresses push notifications on the user's phone. This gates the connect-time presence (and the periodic job) behind `Instance.AlwaysOnline`. When the flag is false we send `PresenceUnavailable` once so the phone keeps receiving push notifications; when true the previous always-online behavior is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/whatsmeow/service/whatsmeow.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/pkg/whatsmeow/service/whatsmeow.go b/pkg/whatsmeow/service/whatsmeow.go index 78ec6c17..3c8702ff 100644 --- a/pkg/whatsmeow/service/whatsmeow.go +++ b/pkg/whatsmeow/service/whatsmeow.go @@ -905,13 +905,28 @@ func (mycli *MyClient) myEventHandler(rawEvt interface{}) { postMap["data"] = dataMap - go schedulePresenceUpdates(mycli) - - err := mycli.WAClient.SendPresence(context.Background(), types.PresenceAvailable) - if err != nil { - mycli.loggerWrapper.GetLogger(mycli.userID).LogWarn("[%s] Failed to send available presence %v", mycli.userID, err) + // Respect the alwaysOnline instance flag. Previously the device was marked + // online unconditionally on every connect (and the periodic presence job was + // started), which kept the linked device permanently "available". WhatsApp then + // delivers messages to that active session and suppresses push notifications on + // the user's phone. When alwaysOnline is false we now send Unavailable instead. + var err error + if mycli.Instance.AlwaysOnline { + go schedulePresenceUpdates(mycli) + + err = mycli.WAClient.SendPresence(context.Background(), types.PresenceAvailable) + if err != nil { + mycli.loggerWrapper.GetLogger(mycli.userID).LogWarn("[%s] Failed to send available presence %v", mycli.userID, err) + } else { + mycli.loggerWrapper.GetLogger(mycli.userID).LogWarn("[%s] Marked self as available", mycli.userID) + } } else { - mycli.loggerWrapper.GetLogger(mycli.userID).LogWarn("[%s] Marked self as available", mycli.userID) + err = mycli.WAClient.SendPresence(context.Background(), types.PresenceUnavailable) + if err != nil { + mycli.loggerWrapper.GetLogger(mycli.userID).LogWarn("[%s] Failed to send unavailable presence %v", mycli.userID, err) + } else { + mycli.loggerWrapper.GetLogger(mycli.userID).LogInfo("[%s] Marked self as unavailable (alwaysOnline=false)", mycli.userID) + } } mycli.Instance.Connected = true