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 }