github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/utils/collapses.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/keybase/client/go/chat/globals"
     8  	"github.com/keybase/client/go/libkb"
     9  	"github.com/keybase/client/go/protocol/chat1"
    10  	"github.com/keybase/client/go/protocol/gregor1"
    11  	"github.com/keybase/clockwork"
    12  	"golang.org/x/net/context"
    13  )
    14  
    15  type singleCollapseRecord struct {
    16  	Collapsed bool
    17  	Time      time.Time
    18  }
    19  
    20  type rangeCollapseRecord struct {
    21  	Collapsed bool
    22  	MsgID     chat1.MessageID
    23  	Time      time.Time
    24  }
    25  
    26  type Collapses struct {
    27  	globals.Contextified
    28  	DebugLabeler
    29  
    30  	clock clockwork.Clock
    31  }
    32  
    33  func NewCollapses(g *globals.Context) *Collapses {
    34  	return &Collapses{
    35  		Contextified: globals.NewContextified(g),
    36  		DebugLabeler: NewDebugLabeler(g.ExternalG(), "Utils.Collapses", false),
    37  		clock:        clockwork.NewRealClock(),
    38  	}
    39  }
    40  
    41  func (c *Collapses) singleKey(uid gregor1.UID, convID chat1.ConversationID, msgID chat1.MessageID) libkb.DbKey {
    42  	return libkb.DbKey{
    43  		Typ: libkb.DBChatCollapses,
    44  		Key: fmt.Sprintf("single:%s:%s:%d", uid, convID, msgID),
    45  	}
    46  }
    47  
    48  func (c *Collapses) rangeKey(uid gregor1.UID, convID chat1.ConversationID) libkb.DbKey {
    49  	return libkb.DbKey{
    50  		Typ: libkb.DBChatCollapses,
    51  		Key: fmt.Sprintf("range:%s:%s", uid, convID),
    52  	}
    53  }
    54  
    55  func (c *Collapses) ToggleSingle(ctx context.Context, uid gregor1.UID, convID chat1.ConversationID,
    56  	msgID chat1.MessageID, collapsed bool) error {
    57  	key := c.singleKey(uid, convID, msgID)
    58  	return c.G().GetKVStore().PutObj(key, nil, singleCollapseRecord{
    59  		Collapsed: collapsed,
    60  		Time:      c.clock.Now(),
    61  	})
    62  }
    63  
    64  func (c *Collapses) ToggleRange(ctx context.Context, uid gregor1.UID, convID chat1.ConversationID,
    65  	msgID chat1.MessageID, collapsed bool) error {
    66  	key := c.rangeKey(uid, convID)
    67  	return c.G().GetKVStore().PutObj(key, nil, rangeCollapseRecord{
    68  		Collapsed: collapsed,
    69  		MsgID:     msgID,
    70  		Time:      c.clock.Now(),
    71  	})
    72  }
    73  
    74  func (c *Collapses) IsCollapsed(ctx context.Context, uid gregor1.UID, convID chat1.ConversationID,
    75  	msgID chat1.MessageID, msgType chat1.MessageType) bool {
    76  	if !IsCollapsibleMessageType(msgType) {
    77  		return false
    78  	}
    79  	singleKey := c.singleKey(uid, convID, msgID)
    80  	rangeKey := c.rangeKey(uid, convID)
    81  	// Get both to see which one takes precedence in time order
    82  	var singleRec singleCollapseRecord
    83  	var rangeRec rangeCollapseRecord
    84  	singleFound, err := c.G().GetKVStore().GetInto(&singleRec, singleKey)
    85  	if err != nil {
    86  		c.Debug(ctx, "IsCollapsed: failed to read single record: %s", err)
    87  		singleFound = false
    88  	}
    89  	rangeFound, err := c.G().GetKVStore().GetInto(&rangeRec, rangeKey)
    90  	if err != nil {
    91  		c.Debug(ctx, "IsCollapsed: failed to read range record: %s", err)
    92  		rangeFound = false
    93  	}
    94  	if singleFound && !rangeFound {
    95  		return singleRec.Collapsed
    96  	} else if !singleFound && rangeFound {
    97  		if msgID <= rangeRec.MsgID {
    98  			return rangeRec.Collapsed
    99  		}
   100  		return false
   101  	} else if !singleFound && !rangeFound {
   102  		return false
   103  	} else if singleFound && rangeFound {
   104  		if singleRec.Time.After(rangeRec.Time) {
   105  			return singleRec.Collapsed
   106  		}
   107  		if msgID <= rangeRec.MsgID {
   108  			return rangeRec.Collapsed
   109  		}
   110  		return false
   111  	}
   112  	return false
   113  }