12 // whatsappGroupsRefresh is the shortest time between two reads of the
13 // groups from WhatsApp for a group with no name.
14 whatsappGroupsRefresh = time.Minute
16 // whatsappUnknownGroup is the name of a group whose name is not known.
17 whatsappUnknownGroup = "A group with no known name"
19 // whatsappGroupsAge is how long whatsapp_find uses the groups that it
20 // read from WhatsApp.
21 whatsappGroupsAge = time.Hour
24 // newWhatsAppGroups returns the names of the groups with no names yet. logger
25 // gets the failures of a read.
26 func newWhatsAppGroups(logger *slog.Logger) *WhatsAppGroups {
27 return &WhatsAppGroups{
29 names: make(map[string]string),
33 // WhatsAppGroups holds the names of the groups of the account, by the ID of the
34 // group. They come from the events of the groups and from reads of the groups
35 // from WhatsApp, and they stay in memory only. triedAt is the time of the last
36 // read, and readAt the time of the last read that succeeded. The mutex
37 // protects all fields after logger.
38 type WhatsAppGroups struct {
42 names map[string]string
47 // name returns the name of the group id, or whatsappUnknownGroup. A group that
48 // is not in the names reads the groups from WhatsApp with the client of link
49 // again, at most once in whatsappGroupsRefresh.
50 func (g *WhatsAppGroups) name(ctx context.Context, link WhatsAppLink, id string) string {
53 name, found := g.names[id]
54 fresh := time.Since(g.triedAt) < whatsappGroupsRefresh
62 name, found = g.names[id]
66 if !found || name == "" {
67 return whatsappUnknownGroup
73 // read reads the names of the groups of the account from WhatsApp with the
74 // client of link, and tells if it could.
75 func (g *WhatsAppGroups) read(ctx context.Context, link WhatsAppLink) bool {
76 if link.client == nil {
80 ctx, cancel := context.WithTimeout(ctx, whatsappLookupTime)
83 groups, err := link.client.GetJoinedGroups(ctx)
85 g.logger.Warn("group list failed", "err", whatsappRedact(link.own, err.Error()))
89 defer g.mutex.Unlock()
91 g.triedAt = time.Now()
97 for _, group := range groups {
98 g.names[group.JID.String()] = group.Name
104 // set makes name the name of the group id.
105 func (g *WhatsAppGroups) set(id, name string) {
107 defer g.mutex.Unlock()
112 // stale tells if the last read that succeeded is older than whatsappGroupsAge.
113 func (g *WhatsAppGroups) stale() bool {
115 defer g.mutex.Unlock()
117 return time.Since(g.readAt) >= whatsappGroupsAge
120 // all returns a copy of the names of the groups.
121 func (g *WhatsAppGroups) all() map[string]string {
123 defer g.mutex.Unlock()
125 return maps.Clone(g.names)