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

     1  package globals
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/keybase/client/go/chat/types"
     8  	"github.com/keybase/client/go/libkb"
     9  	"github.com/keybase/client/go/protocol/chat1"
    10  	"github.com/keybase/client/go/protocol/keybase1"
    11  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    12  )
    13  
    14  type keyfinderKey int
    15  type identifyNotifierKey int
    16  type chatTrace int
    17  type identifyModeKey int
    18  type upakfinderKey int
    19  type rateLimitKey int
    20  type nameInfoOverride int
    21  type localizerCancelableKeyTyp int
    22  type messageSkipsKeyTyp int
    23  type unboxModeKeyTyp int
    24  type emojiHarvesterKeyTyp int
    25  type ctxMutexKeyTyp int
    26  
    27  var kfKey keyfinderKey
    28  var inKey identifyNotifierKey
    29  var chatTraceKey chatTrace
    30  var identModeKey identifyModeKey
    31  var upKey upakfinderKey
    32  var rlKey rateLimitKey
    33  var nameInfoOverrideKey nameInfoOverride
    34  var localizerCancelableKey localizerCancelableKeyTyp
    35  var messageSkipsKey messageSkipsKeyTyp
    36  var unboxModeKey unboxModeKeyTyp
    37  var emojiHarvesterKey emojiHarvesterKeyTyp
    38  var ctxMutexKey ctxMutexKeyTyp
    39  
    40  type identModeData struct {
    41  	mode   keybase1.TLFIdentifyBehavior
    42  	breaks *[]keybase1.TLFIdentifyFailure
    43  }
    44  
    45  func CtxKeyFinder(ctx context.Context, g *Context) types.KeyFinder {
    46  	if kf, ok := ctx.Value(kfKey).(types.KeyFinder); ok {
    47  		return kf
    48  	}
    49  	return g.CtxFactory.NewKeyFinder()
    50  }
    51  
    52  func CtxUPAKFinder(ctx context.Context, g *Context) types.UPAKFinder {
    53  	if up, ok := ctx.Value(upKey).(types.UPAKFinder); ok {
    54  		return up
    55  	}
    56  	return g.CtxFactory.NewUPAKFinder()
    57  }
    58  
    59  func CtxIdentifyMode(ctx context.Context) (ib keybase1.TLFIdentifyBehavior, breaks *[]keybase1.TLFIdentifyFailure, ok bool) {
    60  	if imd, ok := ctx.Value(identModeKey).(identModeData); ok {
    61  		return imd.mode, imd.breaks, ok
    62  	}
    63  	return keybase1.TLFIdentifyBehavior_CHAT_CLI, nil, false
    64  }
    65  
    66  func CtxAddIdentifyMode(ctx context.Context, mode keybase1.TLFIdentifyBehavior,
    67  	breaks *[]keybase1.TLFIdentifyFailure) context.Context {
    68  	if mode == keybase1.TLFIdentifyBehavior_UNSET {
    69  		mode = keybase1.TLFIdentifyBehavior_CHAT_CLI
    70  	}
    71  	return context.WithValue(ctx, identModeKey, identModeData{mode: mode, breaks: breaks})
    72  }
    73  
    74  func CtxIdentifyNotifier(ctx context.Context) types.IdentifyNotifier {
    75  	if in, ok := ctx.Value(inKey).(types.IdentifyNotifier); ok {
    76  		return in
    77  	}
    78  	return nil
    79  }
    80  
    81  func CtxModifyIdentifyNotifier(ctx context.Context, notifier types.IdentifyNotifier) context.Context {
    82  	return context.WithValue(ctx, inKey, notifier)
    83  }
    84  
    85  func CtxAddRateLimit(ctx context.Context, rl []chat1.RateLimit) {
    86  	if l, ok := ctx.Value(ctxMutexKey).(*sync.RWMutex); ok {
    87  		l.Lock()
    88  		defer l.Unlock()
    89  		if existingRL, ok := ctx.Value(rlKey).(map[string]chat1.RateLimit); ok {
    90  			for _, r := range rl {
    91  				existingRL[r.Name] = r
    92  			}
    93  		}
    94  	}
    95  }
    96  
    97  func CtxRateLimits(ctx context.Context) (res []chat1.RateLimit) {
    98  	if l, ok := ctx.Value(ctxMutexKey).(*sync.RWMutex); ok {
    99  		l.RLock()
   100  		defer l.RUnlock()
   101  		if existingRL, ok := ctx.Value(rlKey).(map[string]chat1.RateLimit); ok {
   102  			for _, rl := range existingRL {
   103  				res = append(res, rl)
   104  			}
   105  		}
   106  	}
   107  	return res
   108  }
   109  
   110  func CtxAddMessageCacheSkips(ctx context.Context, convID chat1.ConversationID, msgs []chat1.MessageUnboxed) {
   111  	if l, ok := ctx.Value(ctxMutexKey).(*sync.RWMutex); ok {
   112  		l.Lock()
   113  		defer l.Unlock()
   114  		if existingSkips, ok := ctx.Value(messageSkipsKey).(map[chat1.ConvIDStr]MessageCacheSkip); ok {
   115  			existingSkips[convID.ConvIDStr()] = MessageCacheSkip{
   116  				ConvID: convID,
   117  				Msgs:   append(existingSkips[convID.ConvIDStr()].Msgs, msgs...),
   118  			}
   119  		}
   120  	}
   121  }
   122  
   123  type MessageCacheSkip struct {
   124  	ConvID chat1.ConversationID
   125  	Msgs   []chat1.MessageUnboxed
   126  }
   127  
   128  func CtxMessageCacheSkips(ctx context.Context) (res []MessageCacheSkip) {
   129  	if l, ok := ctx.Value(ctxMutexKey).(*sync.RWMutex); ok {
   130  		l.RLock()
   131  		defer l.RUnlock()
   132  		if existingSkips, ok := ctx.Value(messageSkipsKey).(map[chat1.ConvIDStr]MessageCacheSkip); ok {
   133  			for _, skips := range existingSkips {
   134  				res = append(res, skips)
   135  			}
   136  		}
   137  	}
   138  	return res
   139  }
   140  
   141  func CtxModifyUnboxMode(ctx context.Context, unboxMode types.UnboxMode) context.Context {
   142  	return context.WithValue(ctx, unboxModeKey, unboxMode)
   143  }
   144  
   145  func CtxUnboxMode(ctx context.Context) types.UnboxMode {
   146  	if unboxMode, ok := ctx.Value(unboxModeKey).(types.UnboxMode); ok {
   147  		return unboxMode
   148  	}
   149  	return types.UnboxModeFull
   150  }
   151  
   152  func CtxOverrideNameInfoSource(ctx context.Context) (types.NameInfoSource, bool) {
   153  	if ni, ok := ctx.Value(nameInfoOverrideKey).(types.NameInfoSource); ok {
   154  		return ni, true
   155  	}
   156  	return nil, false
   157  }
   158  
   159  func CtxAddOverrideNameInfoSource(ctx context.Context, ni types.NameInfoSource) context.Context {
   160  	return context.WithValue(ctx, nameInfoOverrideKey, ni)
   161  }
   162  
   163  func CtxTrace(ctx context.Context) (string, bool) {
   164  	if trace, ok := ctx.Value(chatTraceKey).(string); ok {
   165  		return trace, true
   166  	}
   167  	return "", false
   168  }
   169  
   170  func CtxAddLogTags(ctx context.Context, g *Context) context.Context {
   171  
   172  	// Add trace context value
   173  	trace := libkb.RandStringB64(3)
   174  	ctx = context.WithValue(ctx, chatTraceKey, trace)
   175  
   176  	// Add log tags
   177  	ctx = libkb.WithLogTagWithValue(ctx, "chat-trace", trace)
   178  
   179  	rpcTags := make(map[string]interface{})
   180  	rpcTags["user-agent"] = libkb.UserAgent
   181  	rpcTags["platform"] = libkb.GetPlatformString()
   182  	rpcTags["apptype"] = g.GetAppType()
   183  	ctx = rpc.AddRpcTagsToContext(ctx, rpcTags)
   184  
   185  	return ctx
   186  }
   187  
   188  func IsLocalizerCancelableCtx(ctx context.Context) bool {
   189  	if bval, ok := ctx.Value(localizerCancelableKey).(bool); ok && bval {
   190  		return true
   191  	}
   192  	return false
   193  }
   194  
   195  func CtxAddLocalizerCancelable(ctx context.Context) context.Context {
   196  	return context.WithValue(ctx, localizerCancelableKey, true)
   197  }
   198  
   199  func CtxRemoveLocalizerCancelable(ctx context.Context) context.Context {
   200  	if IsLocalizerCancelableCtx(ctx) {
   201  		return context.WithValue(ctx, localizerCancelableKey, false)
   202  	}
   203  	return ctx
   204  }
   205  
   206  func IsEmojiHarvesterCtx(ctx context.Context) bool {
   207  	if bval, ok := ctx.Value(emojiHarvesterKey).(bool); ok && bval {
   208  		return true
   209  	}
   210  	return false
   211  }
   212  
   213  func CtxMakeEmojiHarvester(ctx context.Context) context.Context {
   214  	return context.WithValue(ctx, emojiHarvesterKey, true)
   215  }
   216  
   217  func ChatCtx(ctx context.Context, g *Context, mode keybase1.TLFIdentifyBehavior,
   218  	breaks *[]keybase1.TLFIdentifyFailure, notifier types.IdentifyNotifier) context.Context {
   219  	if breaks == nil {
   220  		breaks = new([]keybase1.TLFIdentifyFailure)
   221  	}
   222  	res := ctx
   223  	if _, _, ok := CtxIdentifyMode(res); !ok {
   224  		res = CtxAddIdentifyMode(res, mode, breaks)
   225  	}
   226  	if _, ok := res.Value(kfKey).(types.KeyFinder); !ok {
   227  		res = context.WithValue(res, kfKey, g.CtxFactory.NewKeyFinder())
   228  	}
   229  	if _, ok := res.Value(inKey).(types.IdentifyNotifier); !ok {
   230  		res = context.WithValue(res, inKey, notifier)
   231  	}
   232  	if _, ok := res.Value(upKey).(types.UPAKFinder); !ok {
   233  		res = context.WithValue(res, upKey, g.CtxFactory.NewUPAKFinder())
   234  	}
   235  	if _, ok := res.Value(ctxMutexKey).(*sync.RWMutex); !ok {
   236  		res = context.WithValue(res, ctxMutexKey, &sync.RWMutex{})
   237  	}
   238  	if _, ok := res.Value(rlKey).(map[string]chat1.RateLimit); !ok {
   239  		res = context.WithValue(res, rlKey, make(map[string]chat1.RateLimit))
   240  	}
   241  	if _, ok := res.Value(messageSkipsKey).(map[chat1.ConvIDStr]MessageCacheSkip); !ok {
   242  		res = context.WithValue(res, messageSkipsKey, make(map[chat1.ConvIDStr]MessageCacheSkip))
   243  	}
   244  	if _, ok := res.Value(unboxModeKey).(types.UnboxMode); !ok {
   245  		res = context.WithValue(res, unboxModeKey, types.UnboxModeFull)
   246  	}
   247  	if _, ok := CtxTrace(res); !ok {
   248  		res = CtxAddLogTags(res, g)
   249  	}
   250  	return res
   251  }
   252  
   253  func BackgroundChatCtx(sourceCtx context.Context, g *Context) context.Context {
   254  	rctx := libkb.CopyTagsToBackground(sourceCtx)
   255  
   256  	in := CtxIdentifyNotifier(sourceCtx)
   257  	if ident, breaks, ok := CtxIdentifyMode(sourceCtx); ok {
   258  		rctx = ChatCtx(rctx, g, ident, breaks, in)
   259  	}
   260  
   261  	// Overwrite trace tag
   262  	if tr, ok := sourceCtx.Value(chatTraceKey).(string); ok {
   263  		rctx = context.WithValue(rctx, chatTraceKey, tr)
   264  	}
   265  
   266  	if ni, ok := CtxOverrideNameInfoSource(sourceCtx); ok {
   267  		rctx = CtxAddOverrideNameInfoSource(rctx, ni)
   268  	}
   269  	rctx = context.WithValue(rctx, kfKey, CtxKeyFinder(sourceCtx, g))
   270  	rctx = context.WithValue(rctx, upKey, CtxUPAKFinder(sourceCtx, g))
   271  	rctx = context.WithValue(rctx, inKey, in)
   272  	rctx = libkb.WithLogTag(rctx, "CHTBKG")
   273  	if IsLocalizerCancelableCtx(sourceCtx) {
   274  		rctx = CtxAddLocalizerCancelable(rctx)
   275  	}
   276  	if IsEmojiHarvesterCtx(sourceCtx) {
   277  		rctx = CtxMakeEmojiHarvester(rctx)
   278  	}
   279  	return rctx
   280  }