12 // whatsappGroupsLookupTime is the longest time of a read of group
14 whatsappGroupsLookupTime = 10 * time.Second
16 // whatsappGroupsRefresh is the shortest time between two reads of the
17 // groups from WhatsApp for a group with no name.
18 whatsappGroupsRefresh = time.Minute
20 // whatsappUnknownGroup is the name of a group whose name is not known.
21 whatsappUnknownGroup = "A group with no known name"
23 // whatsappGroupsAge is how long whatsapp_find uses the groups that it
24 // read from WhatsApp.
25 whatsappGroupsAge = time.Hour
28 // newWhatsAppGroups returns the names of the groups with no names yet. logger
29 // gets the failures of a read.
30 func newWhatsAppGroups(logger *slog.Logger) *WhatsAppGroups {
31 return &WhatsAppGroups{
33 names: make(map[string]string),
37 // WhatsAppGroups holds the names of the groups of the account, by the ID of the
38 // group. They come from the events of the groups and from reads of the groups
39 // from WhatsApp, and they stay in memory only. triedAt is the time of the last
40 // read, and readAt the time of the last read that succeeded. The mutex
41 // protects all fields after logger.
42 type WhatsAppGroups struct {
46 names map[string]string
51 // name returns the name of the group id, or whatsappUnknownGroup. A group that
52 // is not in the names reads the groups from WhatsApp with the client of link
53 // again, at most once in whatsappGroupsRefresh.
54 func (g *WhatsAppGroups) name(ctx context.Context, link WhatsAppLink, id string) string {
57 name, found := g.names[id]
58 fresh := time.Since(g.triedAt) < whatsappGroupsRefresh
66 name, found = g.names[id]
70 if !found || name == "" {
71 return whatsappUnknownGroup
77 // read reads the names of the groups of the account from WhatsApp with the
78 // client of link, and tells if it could.
79 func (g *WhatsAppGroups) read(ctx context.Context, link WhatsAppLink) bool {
80 if link.client == nil {
84 ctx, cancel := context.WithTimeout(ctx, whatsappGroupsLookupTime)
87 groups, err := link.client.GetJoinedGroups(ctx)
89 g.logger.Warn("group list failed", "err", whatsappRedact(link.own, err.Error()))
93 defer g.mutex.Unlock()
95 g.triedAt = time.Now()
101 for _, group := range groups {
102 g.names[group.JID.String()] = group.Name
108 // set makes name the name of the group id.
109 func (g *WhatsAppGroups) set(id, name string) {
111 defer g.mutex.Unlock()
116 // stale tells if the last read that succeeded is older than whatsappGroupsAge.
117 func (g *WhatsAppGroups) stale() bool {
119 defer g.mutex.Unlock()
121 return time.Since(g.readAt) >= whatsappGroupsAge
124 // all returns a copy of the names of the groups.
125 func (g *WhatsAppGroups) all() map[string]string {
127 defer g.mutex.Unlock()
129 return maps.Clone(g.names)