From 23d14f8467f5409486cd82455714203008e70928 Mon Sep 17 00:00:00 2001 From: Martin Schere Date: Thu, 16 Oct 2025 13:08:36 +0200 Subject: [PATCH] feat: get many pns for lids --- group.go | 5 ++++ store/noop.go | 4 +++ store/sqlstore/lidmap.go | 63 ++++++++++++++++++++++++++++++++++++++++ store/store.go | 1 + user.go | 11 +++++++ 5 files changed, 84 insertions(+) diff --git a/group.go b/group.go index 1ec8b5ec4..e6a394eae 100644 --- a/group.go +++ b/group.go @@ -653,12 +653,17 @@ func (cli *Client) getCachedGroupData(ctx context.Context, jid types.JID) (*grou cli.groupCacheLock.Lock() defer cli.groupCacheLock.Unlock() if val, ok := cli.groupCache[jid]; ok { + cli.Log.Debugf("Group participants cache HIT for group %s (has %d members)", jid, len(val.Members)) return val, nil } + cli.Log.Debugf("Group participants cache MISS for group %s, fetching from server", jid) _, err := cli.getGroupInfo(ctx, jid, false) if err != nil { return nil, err } + if cachedData := cli.groupCache[jid]; cachedData != nil { + cli.Log.Debugf("Group participants cache populated for %s with %d members", jid, len(cachedData.Members)) + } return cli.groupCache[jid], nil } diff --git a/store/noop.go b/store/noop.go index 56dbed9a5..9cf12b51b 100644 --- a/store/noop.go +++ b/store/noop.go @@ -260,6 +260,10 @@ func (n *NoopStore) GetManyLIDsForPNs(ctx context.Context, pns []types.JID) (map return nil, n.Error } +func (n *NoopStore) GetManyPNsForLIDs(ctx context.Context, lids []types.JID) (map[types.JID]types.JID, error) { + return nil, n.Error +} + func (n *NoopStore) GetPNForLID(ctx context.Context, lid types.JID) (types.JID, error) { return types.JID{}, n.Error } diff --git a/store/sqlstore/lidmap.go b/store/sqlstore/lidmap.go index e7263372b..91ed382ab 100644 --- a/store/sqlstore/lidmap.go +++ b/store/sqlstore/lidmap.go @@ -199,6 +199,69 @@ func (s *CachedLIDMap) GetManyLIDsForPNs(ctx context.Context, pns []types.JID) ( return result, err } +func (s *CachedLIDMap) GetManyPNsForLIDs(ctx context.Context, lids []types.JID) (map[types.JID]types.JID, error) { + if len(lids) == 0 { + return nil, nil + } + + result := make(map[types.JID]types.JID, len(lids)) + + s.lidCacheLock.RLock() + missingLIDs := make([]string, 0, len(lids)) + missingLIDDevices := make(map[string][]types.JID) + for _, lid := range lids { + if lid.Server != types.HiddenUserServer { + continue + } + if pnUser, ok := s.lidToPNCache[lid.User]; ok && pnUser != "" { + result[lid] = types.JID{User: pnUser, Device: lid.Device, Server: types.DefaultUserServer} + } else if !s.cacheFilled { + missingLIDs = append(missingLIDs, lid.User) + missingLIDDevices[lid.User] = append(missingLIDDevices[lid.User], lid) + } + } + s.lidCacheLock.RUnlock() + + if len(missingLIDs) == 0 { + return result, nil + } + + s.lidCacheLock.Lock() + defer s.lidCacheLock.Unlock() + + var rows dbutil.Rows + var err error + if s.db.Dialect == dbutil.Postgres && PostgresArrayWrapper != nil { + rows, err = s.db.Query( + ctx, + `SELECT lid, pn FROM whatsmeow_lid_map WHERE lid = ANY($1)`, + PostgresArrayWrapper(missingLIDs), + ) + } else { + placeholders := make([]string, len(missingLIDs)) + for i := range missingLIDs { + placeholders[i] = fmt.Sprintf("$%d", i+1) + } + rows, err = s.db.Query( + ctx, + fmt.Sprintf(`SELECT lid, pn FROM whatsmeow_lid_map WHERE lid IN (%s)`, strings.Join(placeholders, ",")), + exslices.CastToAny(missingLIDs)..., + ) + } + if err != nil { + return nil, err + } + err = s.scanManyLids(rows, func(lid, pn string) { + for _, dev := range missingLIDDevices[lid] { + pnDev := dev + pnDev.Server = types.DefaultUserServer + pnDev.User = pn + result[dev] = pnDev.ToNonAD() + } + }) + return result, err +} + func (s *CachedLIDMap) PutLIDMapping(ctx context.Context, lid, pn types.JID) error { if lid.Server != types.HiddenUserServer || pn.Server != types.DefaultUserServer { return fmt.Errorf("invalid PutLIDMapping call %s/%s", lid, pn) diff --git a/store/store.go b/store/store.go index f64b2d855..13c7032c2 100644 --- a/store/store.go +++ b/store/store.go @@ -174,6 +174,7 @@ type LIDStore interface { GetPNForLID(ctx context.Context, lid types.JID) (types.JID, error) GetLIDForPN(ctx context.Context, pn types.JID) (types.JID, error) GetManyLIDsForPNs(ctx context.Context, pns []types.JID) (map[types.JID]types.JID, error) + GetManyPNsForLIDs(ctx context.Context, lids []types.JID) (map[types.JID]types.JID, error) } type AllSessionSpecificStores interface { diff --git a/user.go b/user.go index 864a2b71b..c03dcaf5e 100644 --- a/user.go +++ b/user.go @@ -455,19 +455,30 @@ func (cli *Client) GetUserDevicesContext(ctx context.Context, jids []types.JID) defer cli.userDevicesCacheLock.Unlock() var devices, jidsToSync, fbJIDsToSync []types.JID + var cacheHits, cacheMisses []types.JID for _, jid := range jids { cached, ok := cli.userDevicesCache[jid] if ok && len(cached.devices) > 0 { devices = append(devices, cached.devices...) + cacheHits = append(cacheHits, jid) } else if jid.Server == types.MessengerServer { fbJIDsToSync = append(fbJIDsToSync, jid) + cacheMisses = append(cacheMisses, jid) } else if jid.IsBot() { // Bot JIDs do not have devices, the usync query is empty devices = append(devices, jid) } else { jidsToSync = append(jidsToSync, jid) + cacheMisses = append(cacheMisses, jid) } } + + if len(cacheHits) > 0 { + cli.Log.Debugf("User devices cache HIT for %d JIDs: %v", len(cacheHits), cacheHits) + } + if len(cacheMisses) > 0 { + cli.Log.Debugf("User devices cache MISS for %d JIDs: %v", len(cacheMisses), cacheMisses) + } if len(jidsToSync) > 0 { list, err := cli.usync(ctx, jidsToSync, "query", "message", []waBinary.Node{ {Tag: "devices", Attrs: waBinary.Attrs{"version": "2"}},