github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/storage/version.go (about) 1 package storage 2 3 import ( 4 "github.com/keybase/client/go/chat/globals" 5 "github.com/keybase/client/go/chat/utils" 6 "github.com/keybase/client/go/libkb" 7 "github.com/keybase/client/go/protocol/chat1" 8 context "golang.org/x/net/context" 9 ) 10 11 type ServerVersions struct { 12 globals.Contextified 13 utils.DebugLabeler 14 15 cached *chat1.ServerCacheVers 16 } 17 18 func NewServerVersions(g *globals.Context) *ServerVersions { 19 return &ServerVersions{ 20 Contextified: globals.NewContextified(g), 21 DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "ServerVersions", false), 22 } 23 } 24 25 func (s *ServerVersions) makeKey() libkb.DbKey { 26 return libkb.DbKey{ 27 Typ: libkb.DBChatBlocks, 28 Key: "versions", 29 } 30 } 31 32 func (s *ServerVersions) fetchLocked(ctx context.Context) (chat1.ServerCacheVers, error) { 33 // Check in memory first 34 if s.cached != nil { 35 return *s.cached, nil 36 } 37 38 // Read from LevelDb 39 raw, found, err := s.G().LocalChatDb.GetRaw(s.makeKey()) 40 if err != nil { 41 s.Debug(ctx, "fetchLocked: failed to read: %s", err.Error()) 42 return chat1.ServerCacheVers{}, err 43 } 44 if !found { 45 s.Debug(ctx, "no server version found, using defaults") 46 return chat1.ServerCacheVers{}, nil 47 } 48 var srvVers chat1.ServerCacheVers 49 if err = decode(raw, &srvVers); err != nil { 50 s.Debug(ctx, "fetchLocked: failed to decode: %s", err.Error()) 51 return chat1.ServerCacheVers{}, err 52 } 53 54 // Store in memory 55 s.cached = &srvVers 56 return *s.cached, nil 57 } 58 59 func (s *ServerVersions) Fetch(ctx context.Context) (chat1.ServerCacheVers, error) { 60 locks.Version.Lock() 61 defer locks.Version.Unlock() 62 63 return s.fetchLocked(ctx) 64 } 65 66 func (s *ServerVersions) matchLocked(ctx context.Context, vers int, 67 versFunc func(chat1.ServerCacheVers) int) (int, error) { 68 srvVers, err := s.fetchLocked(ctx) 69 if err != nil { 70 return 0, err 71 } 72 retVers := versFunc(srvVers) 73 if retVers != vers { 74 return retVers, NewVersionMismatchError(chat1.InboxVers(vers), chat1.InboxVers(retVers)) 75 } 76 return retVers, nil 77 } 78 79 func (s *ServerVersions) MatchInbox(ctx context.Context, vers int) (int, error) { 80 locks.Version.Lock() 81 defer locks.Version.Unlock() 82 83 return s.matchLocked(ctx, vers, func(srvVers chat1.ServerCacheVers) int { return srvVers.InboxVers }) 84 } 85 86 func (s *ServerVersions) MatchBodies(ctx context.Context, vers int) (int, error) { 87 locks.Version.Lock() 88 defer locks.Version.Unlock() 89 90 return s.matchLocked(ctx, vers, func(srvVers chat1.ServerCacheVers) int { return srvVers.BodiesVers }) 91 } 92 93 func (s *ServerVersions) Set(ctx context.Context, vers chat1.ServerCacheVers) (err error) { 94 locks.Version.Lock() 95 defer locks.Version.Unlock() 96 97 // Write in memory 98 s.cached = &vers 99 100 // Write out to LevelDB 101 dat, err := encode(vers) 102 if err != nil { 103 s.Debug(ctx, "Sync: failed to encode: %s", err.Error()) 104 return err 105 } 106 if err = s.G().LocalChatDb.PutRaw(s.makeKey(), dat); err != nil { 107 s.Debug(ctx, "Sync: failed to write: %s", err.Error()) 108 return err 109 } 110 111 return nil 112 }