github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/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  }