github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }