github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/conflicts.go (about) 1 package teams 2 3 import ( 4 "fmt" 5 6 "github.com/keybase/client/go/libkb" 7 "github.com/keybase/client/go/lru" 8 "github.com/keybase/client/go/protocol/keybase1" 9 "golang.org/x/net/context" 10 ) 11 12 // Increment to invalidate the disk cache. 13 const diskStorageVersionConflictInfo = 1 14 15 type conflictID struct { 16 isPublic bool 17 id keybase1.TeamID 18 } 19 20 func (i conflictID) MemKey() string { 21 prefix := "r" 22 if i.isPublic { 23 prefix = "u" 24 } 25 return fmt.Sprintf("%s%s", prefix, i.id) 26 } 27 28 func (i conflictID) DbKey() libkb.DbKey { 29 return libkb.DbKey{ 30 Typ: libkb.ObjType(libkb.DBImplicitTeamConflictInfo), 31 Key: i.MemKey(), 32 } 33 } 34 35 var _ libkb.LRUKeyer = conflictID{} 36 37 type rawGetConflictInfo struct { 38 Status libkb.AppStatus `json:"status"` 39 ConflictInfo *keybase1.ImplicitTeamConflictInfo `json:"conflict_info"` 40 } 41 42 func (r *rawGetConflictInfo) GetAppStatus() *libkb.AppStatus { 43 return &r.Status 44 } 45 46 func GetConflictInfo(ctx context.Context, g *libkb.GlobalContext, id keybase1.TeamID, isFullyResolved bool, name keybase1.ImplicitTeamDisplayName) (ret keybase1.ImplicitTeamDisplayName, err error) { 47 mctx := libkb.NewMetaContext(ctx, g) 48 defer mctx.Trace(fmt.Sprintf("GetConflictInfo(%s,%v)", id, name), &err)() 49 50 ret = name.DeepCopy() 51 52 key := conflictID{name.IsPublic, id} 53 cv, err := g.GetImplicitTeamConflictInfoCacher().Get(ctx, g, key) 54 if err != nil { 55 mctx.Debug("In fetching from cache: %s", err.Error()) 56 } 57 if cv != nil { 58 if p, ok := cv.(*keybase1.ImplicitTeamConflictInfo); ok { 59 if p.IsConflict() { 60 ret.ConflictInfo = p 61 } 62 return ret, nil 63 } 64 mctx.Debug("Bad element of wrong type from cache: %T", cv) 65 } 66 67 displayName, err := FormatImplicitTeamDisplayName(ctx, g, name) 68 if err != nil { 69 return ret, err 70 } 71 72 arg := libkb.NewAPIArg("team/conflict_info") 73 arg.SessionType = libkb.APISessionTypeREQUIRED 74 if name.IsPublic { 75 arg.SessionType = libkb.APISessionTypeOPTIONAL 76 } 77 arg.Args = libkb.HTTPArgs{ 78 "tid": libkb.S{Val: string(id)}, 79 "display_name": libkb.S{Val: displayName}, 80 "public": libkb.B{Val: name.IsPublic}, 81 } 82 var raw rawGetConflictInfo 83 if err = mctx.G().API.GetDecode(mctx, arg, &raw); err != nil { 84 return ret, err 85 } 86 87 ci := raw.ConflictInfo 88 ret.ConflictInfo = ci 89 90 // If the team is not fully resolved, and there isn't a conflict, there might 91 // still become a conflict in the future, so we decide not to cache it. 92 // Otherwise, the answer stays true indefinitely, so we can cache the value 93 // without fear of staleness. 94 if isFullyResolved || ci.IsConflict() { 95 tmpErr := mctx.G().GetImplicitTeamConflictInfoCacher().Put(ctx, g, key, ci) 96 if tmpErr != nil { 97 mctx.Debug("Failed to cached implicit team conflict info: %s", tmpErr.Error()) 98 } 99 } 100 101 return ret, nil 102 } 103 104 func NewImplicitTeamConflictInfoCache(g *libkb.GlobalContext) *lru.Cache { 105 return lru.NewLRU(g, libkb.ImplicitTeamConflictInfoCacheSize, diskStorageVersionConflictInfo, keybase1.ImplicitTeamConflictInfo{}) 106 } 107 108 func NewImplicitTeamConflictInfoCacheAndInstall(g *libkb.GlobalContext) { 109 cache := NewImplicitTeamConflictInfoCache(g) 110 g.SetImplicitTeamConflictInfoCacher(cache) 111 g.AddLogoutHook(cache, "implicitTeamConflictInfoCache") 112 g.AddDbNukeHook(cache, "implicitTeamConflictInfoCache") 113 }