diff --git a/pkg/chat/handler/chat_handler.go b/pkg/chat/handler/chat_handler.go index c89f2936..35adc642 100644 --- a/pkg/chat/handler/chat_handler.go +++ b/pkg/chat/handler/chat_handler.go @@ -319,7 +319,7 @@ func (c *chatHandler) HistorySyncRequest(ctx *gin.Context) { return } - resp, err := c.chatService.HistorySyncRequest(data, instance) + resp, err := c.chatService.HistorySyncRequest(ctx.Request.Context(), data, instance) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return diff --git a/pkg/chat/service/chat_service.go b/pkg/chat/service/chat_service.go index c4eda9d7..0a6f28ca 100644 --- a/pkg/chat/service/chat_service.go +++ b/pkg/chat/service/chat_service.go @@ -21,7 +21,7 @@ type ChatService interface { ChatUnarchive(data *BodyStruct, instance *instance_model.Instance) (string, error) ChatMute(data *BodyStruct, instance *instance_model.Instance) (string, error) ChatUnmute(data *BodyStruct, instance *instance_model.Instance) (string, error) - HistorySyncRequest(data *HistorySyncRequestStruct, instance *instance_model.Instance) (*whatsmeow.SendResponse, error) + HistorySyncRequest(ctx context.Context, data *HistorySyncRequestStruct, instance *instance_model.Instance) (*whatsmeow.SendResponse, error) } type chatService struct { @@ -216,7 +216,7 @@ func (c *chatService) ChatUnmute(data *BodyStruct, instance *instance_model.Inst return ts.String(), nil } -func (c *chatService) HistorySyncRequest(data *HistorySyncRequestStruct, instance *instance_model.Instance) (*whatsmeow.SendResponse, error) { +func (c *chatService) HistorySyncRequest(ctx context.Context, data *HistorySyncRequestStruct, instance *instance_model.Instance) (*whatsmeow.SendResponse, error) { client, err := c.ensureClientConnected(instance.Id) if err != nil { return nil, err @@ -234,7 +234,13 @@ func (c *chatService) HistorySyncRequest(data *HistorySyncRequestStruct, instanc histRequest := client.BuildHistorySyncRequest(&messageInfo, data.Count) - res, err := client.SendMessage(context.Background(), messageInfo.Chat, histRequest, whatsmeow.SendRequestExtra{Peer: true}) + // On-demand history-sync requests must be sent to our OWN JID as a peer message, not to the + // contact. SendPeerMessage does exactly that (getOwnID().ToNonAD() + Peer:true). Sending it to + // messageInfo.Chat (the contact) fails with "no signal session established" and never returns + // history. whatsmeow's BuildHistorySyncRequest doc: "The built message can be sent using + // Client.SendPeerMessage." The target chat/cursor is already encoded inside histRequest. + // Uses the caller's context so the request can be cancelled / time-bounded. + res, err := client.SendPeerMessage(ctx, histRequest) if err != nil { c.loggerWrapper.GetLogger(instance.Id).LogError("[%s] error history sync request: %v", instance.Id, err) return nil, err diff --git a/pkg/whatsmeow/service/whatsmeow.go b/pkg/whatsmeow/service/whatsmeow.go index 366f0edb..63ca20c6 100644 --- a/pkg/whatsmeow/service/whatsmeow.go +++ b/pkg/whatsmeow/service/whatsmeow.go @@ -301,6 +301,15 @@ func (w whatsmeowService) ForceUpdateJid(instanceId string, number string) error return nil } +// History-sync depth requested from the phone when a device links (DeviceProps.HistorySyncConfig). +// Generous defaults so a newly linked device receives the full available history; tune here if +// bandwidth/storage is a concern. +const ( + historyFullSyncDaysLimit = 3650 // ~10 years + historyFullSyncSizeMbLimit = 2048 // 2 GB + historyStorageQuotaMb = 2048 // 2 GB +) + func (w whatsmeowService) StartClient(cd *ClientData) { w.loggerWrapper.GetLogger(cd.Instance.Id).LogInfo("Starting websocket connection to Whatsapp for user '%s'", cd.Instance.Id) @@ -374,6 +383,15 @@ func (w whatsmeowService) StartClient(cd *ClientData) { store.DeviceProps.Os = &cd.Instance.OsName store.DeviceProps.RequireFullSync = proto.Bool(true) + // RequireFullSync alone still yields a shallow/uneven backfill because the phone falls back to + // conservative defaults. Explicitly request a deep on-link HistorySync window so newly linked + // devices receive the full available message history. Values are named constants so deployments + // can tune history depth / resource usage in one place. + store.DeviceProps.HistorySyncConfig = &waCompanionReg.DeviceProps_HistorySyncConfig{ + FullSyncDaysLimit: proto.Uint32(historyFullSyncDaysLimit), + FullSyncSizeMbLimit: proto.Uint32(historyFullSyncSizeMbLimit), + StorageQuotaMb: proto.Uint32(historyStorageQuotaMb), + } if w.config.WhatsappVersionMajor != 0 && w.config.WhatsappVersionMinor != 0 && w.config.WhatsappVersionPatch != 0 { w.loggerWrapper.GetLogger(cd.Instance.Id).LogInfo("[%s] Setting whatsapp version to %d.%d.%d", cd.Instance.Id, w.config.WhatsappVersionMajor, w.config.WhatsappVersionMinor, w.config.WhatsappVersionPatch)